1 /***********************************************************************************************************************
2 * Copyright (c) 2004, 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.linear.ean;
28
29 import net.sourceforge.barbecue.BarcodeException;
30 import net.sourceforge.barbecue.Module;
31 import net.sourceforge.barbecue.linear.upc.UPCABarcode;
32 import net.sourceforge.barbecue.output.LabelLayoutFactory;
33 import net.sourceforge.barbecue.output.Output;
34 import net.sourceforge.barbecue.output.OutputException;
35
36 import java.awt.*;
37 import java.util.ArrayList;
38 import java.util.List;
39
40 /**
41 * This is a concrete implementation of the EAN13 barcode.
42 *
43 * @author <a href="mailto:james@metalskin.com">James Jenner</a>
44 */
45 public class EAN13Barcode extends UPCABarcode {
46 /**
47 * A list of type identifiers for the EAN13 barcode format
48 */
49 public static final String[] TYPES = new String[]{
50 "EAN-13", "EAN13"
51 };
52
53 public final static int LEFT_ODD = 0;
54 public final static int LEFT_EVEN = 1;
55 public final static int RIGHT = 2;
56
57 public final static int PARITY_EVEN = 0;
58 public final static int PARITY_ODD = 1;
59
60 public final static int BARCODE_LENGTH = 12;
61
62 public final static String ISBN_NUMBER_SYSTEM = "978";
63 public final static int ISBN_SIZE = 10;
64
65 /**
66 * Constructs a basic mode EAN13 barcode with the specified data and an optional
67 * checksum. The length of the barcode is 11, 12 with a checksum. If the length
68 * passed is only 11, then a checksum will be automaticaly added. If the length
69 * is not 11 or 12 then a barcode exception will be thrown.
70 *
71 * @param data The data to encode
72 * @throws BarcodeException If the data to be encoded is invalid
73 */
74 public EAN13Barcode(String data) throws BarcodeException {
75 super(data);
76 }
77
78 protected int getBarcodeLength() {
79 return BARCODE_LENGTH;
80 }
81
82 protected int getGuardCharSize() {
83 return EAN13ModuleFactory.GUARD_CHAR_SIZE;
84 }
85
86 protected int getLeftWidth() {
87 return EAN13ModuleFactory.LEFT_WIDTH;
88 }
89
90 protected Module getRightMargin() {
91 return EAN13ModuleFactory.RIGHT_MARGIN;
92 }
93
94
95
96
97
98
99
100
101
102 protected Dimension draw(Output output, int x, int y, int barWidth, int barHeight) throws OutputException {
103 int currentX = x;
104
105 output.beginDraw();
106
107
108 int guardBarHeight = 0;
109 int shortBarHeight = barHeight;
110 int textHeight = 10 * barWidth;
111
112 if (drawingText) {
113 shortBarHeight = barHeight - (11 * barWidth);
114 guardBarHeight = shortBarHeight + (6 * barWidth);
115 } else {
116 shortBarHeight = barHeight - (6 * barWidth);
117 guardBarHeight = barHeight;
118 }
119
120 String text = getLabel();
121 int currentY = this.barHeight + y;
122
123 Module[] modules = encodeData();
124
125 String leadChar = String.valueOf(text.charAt(0));
126 String firstSet = text.substring(1, getLeftWidth());
127 String lastSet = text.substring(getLeftWidth());
128
129 if (requiresChecksum) {
130 lastSet = lastSet + calculateChecksum().getSymbol();
131 }
132
133 int startTextPos = 0;
134 int firstTextPos = 0;
135 int secondTextPos = 0;
136
137 int startTextW = x;
138 int firstTextW = 0;
139 int secondTextW = 0;
140 int width = 0;
141 Module preAmble = getPreAmble();
142 Module postAmble = getPostAmble();
143 startTextW = 0;
144
145
146 if (super.drawingQuietSection) {
147 currentX += drawModule(getLeftMargin(), output, currentX, y, barWidth, shortBarHeight + textHeight);
148 }
149 startTextPos = x;
150 startTextW = currentX - startTextPos;
151 width = currentX;
152 int guardCharSize = getGuardCharSize();
153 int leftWidth = getLeftWidth() - 1;
154
155
156 if (preAmble != null) {
157 currentX += drawModule(preAmble, output, currentX, y, barWidth, guardBarHeight);
158 }
159
160
161 for (int i = 0; i < guardCharSize; i++) {
162 currentX += drawModule(modules[0], output, currentX, y, barWidth, guardBarHeight);
163 }
164 firstTextPos = currentX;
165
166
167 width = currentX - width;
168 output.paintBackground(currentX - width, guardBarHeight + currentY, width, ((shortBarHeight + textHeight) - guardBarHeight));
169
170 for (int i = guardCharSize; i < leftWidth; i++) {
171 currentX += drawModule(modules[i], output, currentX, y, barWidth, shortBarHeight);
172 }
173
174 firstTextW = currentX - firstTextPos;
175
176 width = currentX;
177
178 currentX += drawModule(getCentreGuard(), output, currentX, y, barWidth, guardBarHeight);
179 secondTextPos = currentX;
180
181
182 width = currentX - width;
183 output.paintBackground(currentX - width, guardBarHeight + currentY, width, ((shortBarHeight + textHeight) - guardBarHeight));
184
185 for (int i = leftWidth; i < modules.length; i++) {
186 currentX += drawModule(modules[i], output, currentX, y, barWidth, shortBarHeight);
187 }
188
189 secondTextW = currentX - secondTextPos;
190 width = currentX;
191
192
193 if (postAmble != null) {
194 currentX += drawModule(postAmble, output, currentX, y, barWidth, guardBarHeight);
195 }
196
197
198 width = currentX - width;
199 output.paintBackground(currentX - width, guardBarHeight + currentY, width, ((shortBarHeight + textHeight) - guardBarHeight));
200
201
202 currentX += drawModule(getRightMargin(), output, currentX, y, barWidth, shortBarHeight + textHeight);
203
204 if (drawingText) {
205 output.drawText(leadChar, LabelLayoutFactory.createMarginLayout(startTextPos, shortBarHeight, startTextW, textHeight));
206 output.drawText(firstSet, LabelLayoutFactory.createMarginLayout(firstTextPos, shortBarHeight, firstTextW, textHeight));
207 output.drawText(lastSet, LabelLayoutFactory.createMarginLayout(secondTextPos, shortBarHeight, secondTextW, textHeight));
208 }
209
210 Dimension size = new Dimension((int) (currentX - x), (int) (currentY) - y);
211
212 output.endDraw((int) size.getWidth(), (int) size.getHeight());
213
214 return size;
215 }
216
217
218 /**
219 * Returns the encoded data for the barcode.
220 *
221 * @return An array of modules that represent the data as a barcode
222 */
223 protected Module[] encodeData() {
224 List modules = new ArrayList();
225 Module module = null;
226 int len = data.length();
227 char c;
228
229 String firstChar = data.substring(0, 1);
230
231
232
233
234
235
236 for (int i = 1; i < len; i++) {
237 c = data.charAt(i);
238
239 module = EAN13ModuleFactory.getModule(firstChar, String.valueOf(c), i);
240 width += module.widthInBars();
241 modules.add(module);
242 }
243
244 if (requiresChecksum) {
245 module = EAN13ModuleFactory.getModule(firstChar, calculateChecksum().getSymbol(), modules.size() - 1);
246 width += module.widthInBars();
247 modules.add(module);
248 }
249
250 return (Module[]) modules.toArray(new Module[0]);
251 }
252
253 /**
254 * Returns the checksum for the barcode, pre-encoded as a Module.
255 *
256 * @return a Mod-10 caclulated checksum, if no checksum is required Null
257 */
258 protected Module calculateChecksum() {
259 if (requiresChecksum) {
260 return EAN13ModuleFactory.getModuleForIndex(data.substring(0, 1), getMod10CheckDigit(data));
261 }
262
263 return null;
264 }
265
266 public static int getMod10CheckDigit(String data) {
267 int sum = 0;
268 int len = data.length();
269 int value;
270
271
272
273
274
275
276
277
278
279
280
281 for (int i = 0; i < len; i++) {
282 try {
283 value = Integer.parseInt(String.valueOf(data.charAt(i)));
284 sum += calculateChecksum(value, (i % 2) == 0);
285 } catch (java.lang.NumberFormatException e) {
286 }
287 }
288
289 return 10 - (sum % 10);
290 }
291 }