1 /***********************************************************************************************************************
2 * Copyright (c) 2003, International Barcode Consortium
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without modification,
6 * are permitted provided that the following conditions are met:
7 *
8 * Redistributions of source code must retain the above copyright notice, this list of
9 * conditions and the following disclaimer.
10 * Redistributions in binary form must reproduce the above copyright notice, this list of
11 * conditions and the following disclaimer in the documentation and/or other materials
12 * provided with the distribution.
13 * Neither the name of the International Barcode Consortium nor the names of any contributors may be used to endorse
14 * or promote products derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
18 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
19 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
23 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
24 * POSSIBILITY OF SUCH DAMAGE.
25 ***********************************************************************************************************************/
26
27 package net.sourceforge.barbecue.output;
28
29 import org.jdom.Document;
30 import org.jdom.Element;
31 import org.jdom.DocType;
32 import org.jdom.Namespace;
33 import org.jdom.output.XMLOutputter;
34
35 import java.io.BufferedWriter;
36 import java.io.IOException;
37 import java.io.Writer;
38 import java.awt.*;
39
40 /**
41 * SVG outputter to output barcodes as SVG files.
42 *
43 * Contributed by Ryan Martell.
44 *
45 * @author Ryan Martell
46 * @author <a href="mailto:opensource@ianbourke.com">Ian Bourke</a>
47 */
48 public class SVGOutput extends AbstractOutput {
49
50 private static final String DEFAULT_FAMILY = "Arial";
51 private static final int DEFAULT_SIZE = 20;
52
53 private static final String[] FONT_STYLES = new String[] {
54 "font-style: normal", "font-weight: bold", "font-style: italic"
55 };
56
57 private String units;
58 private final Writer writer;
59 private Element root;
60 private Document doc;
61
62 /**
63 * Creates a new instance of SVGOutput.
64 * @param writer The Writer to output the SVG text to
65 * @param font The font for text rendering (only if Barcode has drawText set to true)
66 * @param fgColor Foreground color
67 * @param bgColor Background color
68 * @param scalar The scalar value to convert to units. if barWidth is 1, and you want the
69 * smallest bar to be 1/128 of an inch, this should be set to 1.0/128, and units
70 * should be set to "in"
71 * @param units The units for the scalar, above. "in", "cm", "mm", "px" are acceptable values.
72 */
73 public SVGOutput(java.io.Writer writer, Font font, Color fgColor, Color bgColor, double scalar, String units) {
74 super(font, true, scalar, fgColor, bgColor);
75 this.writer = writer;
76 this.units = units;
77 }
78
79 /**
80 * From AbstractOutput - sets up the SVG output.
81 */
82 public void beginDraw() {
83 root = createElement("svg");
84 doc = new Document(root);
85 }
86
87 /**
88 * From AbstractOutput - finished up the SVG output.
89 * @param width The output width (in pixels) of the barcode
90 * @param height The output height (in pixels) of the barcode.
91 */
92 public void endDraw(int width, int height) throws OutputException {
93 root.setNamespace(Namespace.getNamespace("svg", "http://www.w3.org/2000/svg"));
94 root.setAttribute("width", getScaledDimension(width));
95 root.setAttribute("height", getScaledDimension(height));
96 doc.setDocType(new DocType("svg", "-//W3C//DTD SVG 1.1//EN", "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"));
97
98 try {
99 BufferedWriter bw = new BufferedWriter(writer);
100 XMLOutputter outputter = new XMLOutputter();
101 outputter.output(doc, bw);
102 bw.flush();
103 bw.close();
104 } catch (IOException e) {
105 throw new OutputException(e.getMessage(), e);
106 }
107 }
108
109 protected Element createElement(String name) {
110 Element e = new Element(name);
111 e.setNamespace(Namespace.getNamespace("svg", "http://www.w3.org/2000/svg"));
112 return e;
113 }
114
115 /**
116 * From AbstractOutput - outputs the correct rectangle to the SVG output.
117 * @param x the x coordinate
118 * @param y the y coordinate
119 * @param width the width
120 * @param height the height
121 * @param paintWithForegroundColor if true, use the foreground color, otherwise use the background color
122 */
123 public int drawBar(int x, int y, int width, int height, boolean paintWithForegroundColor) {
124 Element rectElement = createElement("rect");
125 rectElement.setAttribute("x", getScaledDimension(x));
126 rectElement.setAttribute("y", getScaledDimension(y));
127 rectElement.setAttribute("width", getScaledDimension(width));
128 rectElement.setAttribute("height", getScaledDimension(height));
129 rectElement.setAttribute("style", "fill:" + getColorAsCSS(paintWithForegroundColor ? foregroundColour : backgroundColour) + ";");
130 root.addContent(rectElement);
131 return width;
132 }
133
134 public int drawText(String text, LabelLayout layout) throws OutputException {
135 Element textElement = createElement("text");
136 textElement.setAttribute("x", getScaledDimension((int) layout.getBackgroundX()));
137 textElement.setAttribute("y", getScaledDimension((int) layout.getBackgroundY()));
138 textElement.setAttribute("style", constructStyleText());
139 textElement.addContent(text);
140 root.addContent(textElement);
141 return 0;
142 }
143
144 public void paintBackground(int x, int y, int width, int height) {
145
146 }
147
148 private String constructStyleText() {
149 String family = DEFAULT_FAMILY;
150 int size = DEFAULT_SIZE;
151 int style = Font.PLAIN;
152
153 if (font != null) {
154 family = font.getFamily();
155 size = font.getSize();
156 style = font.getStyle();
157 }
158
159 StringBuffer buffer = new StringBuffer();
160 buffer.append("font-family: ");
161 buffer.append(family);
162 buffer.append("; ");
163 buffer.append("font-size: ");
164 buffer.append(size);
165 buffer.append("pt; ");
166 buffer.append(getFontStyle(style));
167 buffer.append("; ");
168 return buffer.toString();
169 }
170
171 private String getFontStyle(int style) {
172 if (style > FONT_STYLES.length && style >= 0) {
173 return FONT_STYLES[Font.PLAIN];
174 } else {
175 return FONT_STYLES[style];
176 }
177 }
178
179 private String getScaledDimension(int value) {
180 return "" + (value * scalar + units);
181 }
182
183 private String getColorAsCSS(Color c) {
184 StringBuffer sb = new StringBuffer("#");
185 float [] components = c.getColorComponents(null);
186 for (int ii = 0; ii < components.length; ii++) {
187 String s = Integer.toHexString((int) (255 * components[ii])).toUpperCase();
188 if (s.length() == 1) {
189 sb.append('0');
190 }
191 sb.append(s);
192 }
193 return sb.toString();
194 }
195 }