001: /*
002: * Copyright 2002 by Paulo Soares.
003: *
004: * The contents of this file are subject to the Mozilla Public License Version 1.1
005: * (the "License"); you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at http://www.mozilla.org/MPL/
007: *
008: * Software distributed under the License is distributed on an "AS IS" basis,
009: * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
010: * for the specific language governing rights and limitations under the License.
011: *
012: * The Original Code is 'iText, a free JAVA-PDF library'.
013: *
014: * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by
015: * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie.
016: * All Rights Reserved.
017: * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer
018: * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved.
019: *
020: * Contributor(s): all the names of the contributors are added in the source code
021: * where applicable.
022: *
023: * Alternatively, the contents of this file may be used under the terms of the
024: * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the
025: * provisions of LGPL are applicable instead of those above. If you wish to
026: * allow use of your version of this file only under the terms of the LGPL
027: * License and not to allow others to use your version of this file under
028: * the MPL, indicate your decision by deleting the provisions above and
029: * replace them with the notice and other provisions required by the LGPL.
030: * If you do not delete the provisions above, a recipient may use your version
031: * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE.
032: *
033: * This library is free software; you can redistribute it and/or modify it
034: * under the terms of the MPL as stated above or under the terms of the GNU
035: * Library General Public License as published by the Free Software Foundation;
036: * either version 2 of the License, or any later version.
037: *
038: * This library is distributed in the hope that it will be useful, but WITHOUT
039: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
040: * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more
041: * details.
042: *
043: * If you didn't download this code from the following link, you should check if
044: * you aren't using an obsolete version:
045: * http://www.lowagie.com/iText/
046: */
047: package com.lowagie.text.pdf;
048:
049: import java.awt.Canvas;
050: import java.awt.Color;
051: import java.awt.Image;
052: import java.awt.image.MemoryImageSource;
053: import java.util.Arrays;
054:
055: import com.lowagie.text.ExceptionConverter;
056: import com.lowagie.text.Rectangle;
057:
058: /** Generates barcodes in several formats: EAN13, EAN8, UPCA, UPCE,
059: * supplemental 2 and 5. The default parameters are:
060: * <pre>
061: *x = 0.8f;
062: *font = BaseFont.createFont("Helvetica", "winansi", false);
063: *size = 8;
064: *baseline = size;
065: *barHeight = size * 3;
066: *guardBars = true;
067: *codeType = EAN13;
068: *code = "";
069: * </pre>
070: *
071: * @author Paulo Soares (psoares@consiste.pt)
072: */
073: public class BarcodeEAN extends Barcode {
074:
075: /** The bar positions that are guard bars.*/
076: private static final int GUARD_EMPTY[] = {};
077: /** The bar positions that are guard bars.*/
078: private static final int GUARD_UPCA[] = { 0, 2, 4, 6, 28, 30, 52,
079: 54, 56, 58 };
080: /** The bar positions that are guard bars.*/
081: private static final int GUARD_EAN13[] = { 0, 2, 28, 30, 56, 58 };
082: /** The bar positions that are guard bars.*/
083: private static final int GUARD_EAN8[] = { 0, 2, 20, 22, 40, 42 };
084: /** The bar positions that are guard bars.*/
085: private static final int GUARD_UPCE[] = { 0, 2, 28, 30, 32 };
086: /** The x coordinates to place the text.*/
087: private static final float TEXTPOS_EAN13[] = { 6.5f, 13.5f, 20.5f,
088: 27.5f, 34.5f, 41.5f, 53.5f, 60.5f, 67.5f, 74.5f, 81.5f,
089: 88.5f };
090: /** The x coordinates to place the text.*/
091: private static final float TEXTPOS_EAN8[] = { 6.5f, 13.5f, 20.5f,
092: 27.5f, 39.5f, 46.5f, 53.5f, 60.5f };
093: /** The basic bar widths.*/
094: private static final byte BARS[][] = { { 3, 2, 1, 1 }, // 0
095: { 2, 2, 2, 1 }, // 1
096: { 2, 1, 2, 2 }, // 2
097: { 1, 4, 1, 1 }, // 3
098: { 1, 1, 3, 2 }, // 4
099: { 1, 2, 3, 1 }, // 5
100: { 1, 1, 1, 4 }, // 6
101: { 1, 3, 1, 2 }, // 7
102: { 1, 2, 1, 3 }, // 8
103: { 3, 1, 1, 2 } // 9
104: };
105:
106: /** The total number of bars for EAN13.*/
107: private static final int TOTALBARS_EAN13 = 11 + 12 * 4;
108: /** The total number of bars for EAN8.*/
109: private static final int TOTALBARS_EAN8 = 11 + 8 * 4;
110: /** The total number of bars for UPCE.*/
111: private static final int TOTALBARS_UPCE = 9 + 6 * 4;
112: /** The total number of bars for supplemental 2.*/
113: private static final int TOTALBARS_SUPP2 = 13;
114: /** The total number of bars for supplemental 5.*/
115: private static final int TOTALBARS_SUPP5 = 31;
116: /** Marker for odd parity.*/
117: private static final int ODD = 0;
118: /** Marker for even parity.*/
119: private static final int EVEN = 1;
120:
121: /** Sequence of parities to be used with EAN13.*/
122: private static final byte PARITY13[][] = {
123: { ODD, ODD, ODD, ODD, ODD, ODD }, // 0
124: { ODD, ODD, EVEN, ODD, EVEN, EVEN }, // 1
125: { ODD, ODD, EVEN, EVEN, ODD, EVEN }, // 2
126: { ODD, ODD, EVEN, EVEN, EVEN, ODD }, // 3
127: { ODD, EVEN, ODD, ODD, EVEN, EVEN }, // 4
128: { ODD, EVEN, EVEN, ODD, ODD, EVEN }, // 5
129: { ODD, EVEN, EVEN, EVEN, ODD, ODD }, // 6
130: { ODD, EVEN, ODD, EVEN, ODD, EVEN }, // 7
131: { ODD, EVEN, ODD, EVEN, EVEN, ODD }, // 8
132: { ODD, EVEN, EVEN, ODD, EVEN, ODD } // 9
133: };
134:
135: /** Sequence of parities to be used with supplemental 2.*/
136: private static final byte PARITY2[][] = { { ODD, ODD }, // 0
137: { ODD, EVEN }, // 1
138: { EVEN, ODD }, // 2
139: { EVEN, EVEN } // 3
140: };
141:
142: /** Sequence of parities to be used with supplemental 2.*/
143: private static final byte PARITY5[][] = {
144: { EVEN, EVEN, ODD, ODD, ODD }, // 0
145: { EVEN, ODD, EVEN, ODD, ODD }, // 1
146: { EVEN, ODD, ODD, EVEN, ODD }, // 2
147: { EVEN, ODD, ODD, ODD, EVEN }, // 3
148: { ODD, EVEN, EVEN, ODD, ODD }, // 4
149: { ODD, ODD, EVEN, EVEN, ODD }, // 5
150: { ODD, ODD, ODD, EVEN, EVEN }, // 6
151: { ODD, EVEN, ODD, EVEN, ODD }, // 7
152: { ODD, EVEN, ODD, ODD, EVEN }, // 8
153: { ODD, ODD, EVEN, ODD, EVEN } // 9
154: };
155:
156: /** Sequence of parities to be used with UPCE.*/
157: private static final byte PARITYE[][] = {
158: { EVEN, EVEN, EVEN, ODD, ODD, ODD }, // 0
159: { EVEN, EVEN, ODD, EVEN, ODD, ODD }, // 1
160: { EVEN, EVEN, ODD, ODD, EVEN, ODD }, // 2
161: { EVEN, EVEN, ODD, ODD, ODD, EVEN }, // 3
162: { EVEN, ODD, EVEN, EVEN, ODD, ODD }, // 4
163: { EVEN, ODD, ODD, EVEN, EVEN, ODD }, // 5
164: { EVEN, ODD, ODD, ODD, EVEN, EVEN }, // 6
165: { EVEN, ODD, EVEN, ODD, EVEN, ODD }, // 7
166: { EVEN, ODD, EVEN, ODD, ODD, EVEN }, // 8
167: { EVEN, ODD, ODD, EVEN, ODD, EVEN } // 9
168: };
169:
170: /** Creates new BarcodeEAN */
171: public BarcodeEAN() {
172: try {
173: x = 0.8f;
174: font = BaseFont.createFont("Helvetica", "winansi", false);
175: size = 8;
176: baseline = size;
177: barHeight = size * 3;
178: guardBars = true;
179: codeType = EAN13;
180: code = "";
181: } catch (Exception e) {
182: throw new ExceptionConverter(e);
183: }
184: }
185:
186: /** Calculates the EAN parity character.
187: * @param code the code
188: * @return the parity character
189: */
190: public static int calculateEANParity(String code) {
191: int mul = 3;
192: int total = 0;
193: for (int k = code.length() - 1; k >= 0; --k) {
194: int n = code.charAt(k) - '0';
195: total += mul * n;
196: mul ^= 2;
197: }
198: return (10 - (total % 10)) % 10;
199: }
200:
201: /** Converts an UPCA code into an UPCE code. If the code can not
202: * be converted a <CODE>null</CODE> is returned.
203: * @param text the code to convert. It must have 12 numeric characters
204: * @return the 8 converted digits or <CODE>null</CODE> if the
205: * code could not be converted
206: */
207: static public String convertUPCAtoUPCE(String text) {
208: if (text.length() != 12
209: || !(text.startsWith("0") || text.startsWith("1")))
210: return null;
211: if (text.substring(3, 6).equals("000")
212: || text.substring(3, 6).equals("100")
213: || text.substring(3, 6).equals("200")) {
214: if (text.substring(6, 8).equals("00"))
215: return text.substring(0, 1) + text.substring(1, 3)
216: + text.substring(8, 11) + text.substring(3, 4)
217: + text.substring(11);
218: } else if (text.substring(4, 6).equals("00")) {
219: if (text.substring(6, 9).equals("000"))
220: return text.substring(0, 1) + text.substring(1, 4)
221: + text.substring(9, 11) + "3"
222: + text.substring(11);
223: } else if (text.substring(5, 6).equals("0")) {
224: if (text.substring(6, 10).equals("0000"))
225: return text.substring(0, 1) + text.substring(1, 5)
226: + text.substring(10, 11) + "4"
227: + text.substring(11);
228: } else if (text.charAt(10) >= '5') {
229: if (text.substring(6, 10).equals("0000"))
230: return text.substring(0, 1) + text.substring(1, 6)
231: + text.substring(10, 11) + text.substring(11);
232: }
233: return null;
234: }
235:
236: /** Creates the bars for the barcode EAN13 and UPCA.
237: * @param _code the text with 13 digits
238: * @return the barcode
239: */
240: public static byte[] getBarsEAN13(String _code) {
241: int code[] = new int[_code.length()];
242: for (int k = 0; k < code.length; ++k)
243: code[k] = _code.charAt(k) - '0';
244: byte bars[] = new byte[TOTALBARS_EAN13];
245: int pb = 0;
246: bars[pb++] = 1;
247: bars[pb++] = 1;
248: bars[pb++] = 1;
249: byte sequence[] = PARITY13[code[0]];
250: for (int k = 0; k < sequence.length; ++k) {
251: int c = code[k + 1];
252: byte stripes[] = BARS[c];
253: if (sequence[k] == ODD) {
254: bars[pb++] = stripes[0];
255: bars[pb++] = stripes[1];
256: bars[pb++] = stripes[2];
257: bars[pb++] = stripes[3];
258: } else {
259: bars[pb++] = stripes[3];
260: bars[pb++] = stripes[2];
261: bars[pb++] = stripes[1];
262: bars[pb++] = stripes[0];
263: }
264: }
265: bars[pb++] = 1;
266: bars[pb++] = 1;
267: bars[pb++] = 1;
268: bars[pb++] = 1;
269: bars[pb++] = 1;
270: for (int k = 7; k < 13; ++k) {
271: int c = code[k];
272: byte stripes[] = BARS[c];
273: bars[pb++] = stripes[0];
274: bars[pb++] = stripes[1];
275: bars[pb++] = stripes[2];
276: bars[pb++] = stripes[3];
277: }
278: bars[pb++] = 1;
279: bars[pb++] = 1;
280: bars[pb++] = 1;
281: return bars;
282: }
283:
284: /** Creates the bars for the barcode EAN8.
285: * @param _code the text with 8 digits
286: * @return the barcode
287: */
288: public static byte[] getBarsEAN8(String _code) {
289: int code[] = new int[_code.length()];
290: for (int k = 0; k < code.length; ++k)
291: code[k] = _code.charAt(k) - '0';
292: byte bars[] = new byte[TOTALBARS_EAN8];
293: int pb = 0;
294: bars[pb++] = 1;
295: bars[pb++] = 1;
296: bars[pb++] = 1;
297: for (int k = 0; k < 4; ++k) {
298: int c = code[k];
299: byte stripes[] = BARS[c];
300: bars[pb++] = stripes[0];
301: bars[pb++] = stripes[1];
302: bars[pb++] = stripes[2];
303: bars[pb++] = stripes[3];
304: }
305: bars[pb++] = 1;
306: bars[pb++] = 1;
307: bars[pb++] = 1;
308: bars[pb++] = 1;
309: bars[pb++] = 1;
310: for (int k = 4; k < 8; ++k) {
311: int c = code[k];
312: byte stripes[] = BARS[c];
313: bars[pb++] = stripes[0];
314: bars[pb++] = stripes[1];
315: bars[pb++] = stripes[2];
316: bars[pb++] = stripes[3];
317: }
318: bars[pb++] = 1;
319: bars[pb++] = 1;
320: bars[pb++] = 1;
321: return bars;
322: }
323:
324: /** Creates the bars for the barcode UPCE.
325: * @param _code the text with 8 digits
326: * @return the barcode
327: */
328: public static byte[] getBarsUPCE(String _code) {
329: int code[] = new int[_code.length()];
330: for (int k = 0; k < code.length; ++k)
331: code[k] = _code.charAt(k) - '0';
332: byte bars[] = new byte[TOTALBARS_UPCE];
333: boolean flip = (code[0] != 0);
334: int pb = 0;
335: bars[pb++] = 1;
336: bars[pb++] = 1;
337: bars[pb++] = 1;
338: byte sequence[] = PARITYE[code[code.length - 1]];
339: for (int k = 1; k < code.length - 1; ++k) {
340: int c = code[k];
341: byte stripes[] = BARS[c];
342: if (sequence[k - 1] == (flip ? EVEN : ODD)) {
343: bars[pb++] = stripes[0];
344: bars[pb++] = stripes[1];
345: bars[pb++] = stripes[2];
346: bars[pb++] = stripes[3];
347: } else {
348: bars[pb++] = stripes[3];
349: bars[pb++] = stripes[2];
350: bars[pb++] = stripes[1];
351: bars[pb++] = stripes[0];
352: }
353: }
354: bars[pb++] = 1;
355: bars[pb++] = 1;
356: bars[pb++] = 1;
357: bars[pb++] = 1;
358: bars[pb++] = 1;
359: bars[pb++] = 1;
360: return bars;
361: }
362:
363: /** Creates the bars for the barcode supplemental 2.
364: * @param _code the text with 2 digits
365: * @return the barcode
366: */
367: public static byte[] getBarsSupplemental2(String _code) {
368: int code[] = new int[2];
369: for (int k = 0; k < code.length; ++k)
370: code[k] = _code.charAt(k) - '0';
371: byte bars[] = new byte[TOTALBARS_SUPP2];
372: int pb = 0;
373: int parity = (code[0] * 10 + code[1]) % 4;
374: bars[pb++] = 1;
375: bars[pb++] = 1;
376: bars[pb++] = 2;
377: byte sequence[] = PARITY2[parity];
378: for (int k = 0; k < sequence.length; ++k) {
379: if (k == 1) {
380: bars[pb++] = 1;
381: bars[pb++] = 1;
382: }
383: int c = code[k];
384: byte stripes[] = BARS[c];
385: if (sequence[k] == ODD) {
386: bars[pb++] = stripes[0];
387: bars[pb++] = stripes[1];
388: bars[pb++] = stripes[2];
389: bars[pb++] = stripes[3];
390: } else {
391: bars[pb++] = stripes[3];
392: bars[pb++] = stripes[2];
393: bars[pb++] = stripes[1];
394: bars[pb++] = stripes[0];
395: }
396: }
397: return bars;
398: }
399:
400: /** Creates the bars for the barcode supplemental 5.
401: * @param _code the text with 5 digits
402: * @return the barcode
403: */
404: public static byte[] getBarsSupplemental5(String _code) {
405: int code[] = new int[5];
406: for (int k = 0; k < code.length; ++k)
407: code[k] = _code.charAt(k) - '0';
408: byte bars[] = new byte[TOTALBARS_SUPP5];
409: int pb = 0;
410: int parity = (((code[0] + code[2] + code[4]) * 3) + ((code[1] + code[3]) * 9)) % 10;
411: bars[pb++] = 1;
412: bars[pb++] = 1;
413: bars[pb++] = 2;
414: byte sequence[] = PARITY5[parity];
415: for (int k = 0; k < sequence.length; ++k) {
416: if (k != 0) {
417: bars[pb++] = 1;
418: bars[pb++] = 1;
419: }
420: int c = code[k];
421: byte stripes[] = BARS[c];
422: if (sequence[k] == ODD) {
423: bars[pb++] = stripes[0];
424: bars[pb++] = stripes[1];
425: bars[pb++] = stripes[2];
426: bars[pb++] = stripes[3];
427: } else {
428: bars[pb++] = stripes[3];
429: bars[pb++] = stripes[2];
430: bars[pb++] = stripes[1];
431: bars[pb++] = stripes[0];
432: }
433: }
434: return bars;
435: }
436:
437: /** Gets the maximum area that the barcode and the text, if
438: * any, will occupy. The lower left corner is always (0, 0).
439: * @return the size the barcode occupies.
440: */
441: public Rectangle getBarcodeSize() {
442: float width = 0;
443: float height = barHeight;
444: if (font != null) {
445: if (baseline <= 0)
446: height += -baseline + size;
447: else
448: height += baseline
449: - font
450: .getFontDescriptor(BaseFont.DESCENT,
451: size);
452: }
453: switch (codeType) {
454: case EAN13:
455: width = x * (11 + 12 * 7);
456: if (font != null) {
457: width += font.getWidthPoint(code.charAt(0), size);
458: }
459: break;
460: case EAN8:
461: width = x * (11 + 8 * 7);
462: break;
463: case UPCA:
464: width = x * (11 + 12 * 7);
465: if (font != null) {
466: width += font.getWidthPoint(code.charAt(0), size)
467: + font.getWidthPoint(code.charAt(11), size);
468: }
469: break;
470: case UPCE:
471: width = x * (9 + 6 * 7);
472: if (font != null) {
473: width += font.getWidthPoint(code.charAt(0), size)
474: + font.getWidthPoint(code.charAt(7), size);
475: }
476: break;
477: case SUPP2:
478: width = x * (6 + 2 * 7);
479: break;
480: case SUPP5:
481: width = x * (4 + 5 * 7 + 4 * 2);
482: break;
483: default:
484: throw new RuntimeException("Invalid code type.");
485: }
486: return new Rectangle(width, height);
487: }
488:
489: /** Places the barcode in a <CODE>PdfContentByte</CODE>. The
490: * barcode is always placed at coodinates (0, 0). Use the
491: * translation matrix to move it elsewhere.<p>
492: * The bars and text are written in the following colors:<p>
493: * <P><TABLE BORDER=1>
494: * <TR>
495: * <TH><P><CODE>barColor</CODE></TH>
496: * <TH><P><CODE>textColor</CODE></TH>
497: * <TH><P>Result</TH>
498: * </TR>
499: * <TR>
500: * <TD><P><CODE>null</CODE></TD>
501: * <TD><P><CODE>null</CODE></TD>
502: * <TD><P>bars and text painted with current fill color</TD>
503: * </TR>
504: * <TR>
505: * <TD><P><CODE>barColor</CODE></TD>
506: * <TD><P><CODE>null</CODE></TD>
507: * <TD><P>bars and text painted with <CODE>barColor</CODE></TD>
508: * </TR>
509: * <TR>
510: * <TD><P><CODE>null</CODE></TD>
511: * <TD><P><CODE>textColor</CODE></TD>
512: * <TD><P>bars painted with current color<br>text painted with <CODE>textColor</CODE></TD>
513: * </TR>
514: * <TR>
515: * <TD><P><CODE>barColor</CODE></TD>
516: * <TD><P><CODE>textColor</CODE></TD>
517: * <TD><P>bars painted with <CODE>barColor</CODE><br>text painted with <CODE>textColor</CODE></TD>
518: * </TR>
519: * </TABLE>
520: * @param cb the <CODE>PdfContentByte</CODE> where the barcode will be placed
521: * @param barColor the color of the bars. It can be <CODE>null</CODE>
522: * @param textColor the color of the text. It can be <CODE>null</CODE>
523: * @return the dimensions the barcode occupies
524: */
525: public Rectangle placeBarcode(PdfContentByte cb, Color barColor,
526: Color textColor) {
527: Rectangle rect = getBarcodeSize();
528: float barStartX = 0;
529: float barStartY = 0;
530: float textStartY = 0;
531: if (font != null) {
532: if (baseline <= 0)
533: textStartY = barHeight - baseline;
534: else {
535: textStartY = -font.getFontDescriptor(BaseFont.DESCENT,
536: size);
537: barStartY = textStartY + baseline;
538: }
539: }
540: switch (codeType) {
541: case EAN13:
542: case UPCA:
543: case UPCE:
544: if (font != null)
545: barStartX += font.getWidthPoint(code.charAt(0), size);
546: break;
547: }
548: byte bars[] = null;
549: int guard[] = GUARD_EMPTY;
550: switch (codeType) {
551: case EAN13:
552: bars = getBarsEAN13(code);
553: guard = GUARD_EAN13;
554: break;
555: case EAN8:
556: bars = getBarsEAN8(code);
557: guard = GUARD_EAN8;
558: break;
559: case UPCA:
560: bars = getBarsEAN13("0" + code);
561: guard = GUARD_UPCA;
562: break;
563: case UPCE:
564: bars = getBarsUPCE(code);
565: guard = GUARD_UPCE;
566: break;
567: case SUPP2:
568: bars = getBarsSupplemental2(code);
569: break;
570: case SUPP5:
571: bars = getBarsSupplemental5(code);
572: break;
573: }
574: float keepBarX = barStartX;
575: boolean print = true;
576: float gd = 0;
577: if (font != null && baseline > 0 && guardBars) {
578: gd = baseline / 2;
579: }
580: if (barColor != null)
581: cb.setColorFill(barColor);
582: for (int k = 0; k < bars.length; ++k) {
583: float w = bars[k] * x;
584: if (print) {
585: if (Arrays.binarySearch(guard, k) >= 0)
586: cb.rectangle(barStartX, barStartY - gd, w
587: - inkSpreading, barHeight + gd);
588: else
589: cb.rectangle(barStartX, barStartY,
590: w - inkSpreading, barHeight);
591: }
592: print = !print;
593: barStartX += w;
594: }
595: cb.fill();
596: if (font != null) {
597: if (textColor != null)
598: cb.setColorFill(textColor);
599: cb.beginText();
600: cb.setFontAndSize(font, size);
601: switch (codeType) {
602: case EAN13:
603: cb.setTextMatrix(0, textStartY);
604: cb.showText(code.substring(0, 1));
605: for (int k = 1; k < 13; ++k) {
606: String c = code.substring(k, k + 1);
607: float len = font.getWidthPoint(c, size);
608: float pX = keepBarX + TEXTPOS_EAN13[k - 1] * x
609: - len / 2;
610: cb.setTextMatrix(pX, textStartY);
611: cb.showText(c);
612: }
613: break;
614: case EAN8:
615: for (int k = 0; k < 8; ++k) {
616: String c = code.substring(k, k + 1);
617: float len = font.getWidthPoint(c, size);
618: float pX = TEXTPOS_EAN8[k] * x - len / 2;
619: cb.setTextMatrix(pX, textStartY);
620: cb.showText(c);
621: }
622: break;
623: case UPCA:
624: cb.setTextMatrix(0, textStartY);
625: cb.showText(code.substring(0, 1));
626: for (int k = 1; k < 11; ++k) {
627: String c = code.substring(k, k + 1);
628: float len = font.getWidthPoint(c, size);
629: float pX = keepBarX + TEXTPOS_EAN13[k] * x - len
630: / 2;
631: cb.setTextMatrix(pX, textStartY);
632: cb.showText(c);
633: }
634: cb.setTextMatrix(keepBarX + x * (11 + 12 * 7),
635: textStartY);
636: cb.showText(code.substring(11, 12));
637: break;
638: case UPCE:
639: cb.setTextMatrix(0, textStartY);
640: cb.showText(code.substring(0, 1));
641: for (int k = 1; k < 7; ++k) {
642: String c = code.substring(k, k + 1);
643: float len = font.getWidthPoint(c, size);
644: float pX = keepBarX + TEXTPOS_EAN13[k - 1] * x
645: - len / 2;
646: cb.setTextMatrix(pX, textStartY);
647: cb.showText(c);
648: }
649: cb
650: .setTextMatrix(keepBarX + x * (9 + 6 * 7),
651: textStartY);
652: cb.showText(code.substring(7, 8));
653: break;
654: case SUPP2:
655: case SUPP5:
656: for (int k = 0; k < code.length(); ++k) {
657: String c = code.substring(k, k + 1);
658: float len = font.getWidthPoint(c, size);
659: float pX = (7.5f + (9 * k)) * x - len / 2;
660: cb.setTextMatrix(pX, textStartY);
661: cb.showText(c);
662: }
663: break;
664: }
665: cb.endText();
666: }
667: return rect;
668: }
669:
670: /** Creates a <CODE>java.awt.Image</CODE>. This image only
671: * contains the bars without any text.
672: * @param foreground the color of the bars
673: * @param background the color of the background
674: * @return the image
675: */
676: public java.awt.Image createAwtImage(Color foreground,
677: Color background) {
678: int f = foreground.getRGB();
679: int g = background.getRGB();
680: Canvas canvas = new Canvas();
681:
682: int width = 0;
683: byte bars[] = null;
684: switch (codeType) {
685: case EAN13:
686: bars = getBarsEAN13(code);
687: width = 11 + 12 * 7;
688: break;
689: case EAN8:
690: bars = getBarsEAN8(code);
691: width = 11 + 8 * 7;
692: break;
693: case UPCA:
694: bars = getBarsEAN13("0" + code);
695: width = 11 + 12 * 7;
696: break;
697: case UPCE:
698: bars = getBarsUPCE(code);
699: width = 9 + 6 * 7;
700: break;
701: case SUPP2:
702: bars = getBarsSupplemental2(code);
703: width = 6 + 2 * 7;
704: break;
705: case SUPP5:
706: bars = getBarsSupplemental5(code);
707: width = 4 + 5 * 7 + 4 * 2;
708: break;
709: default:
710: throw new RuntimeException("Invalid code type.");
711: }
712:
713: boolean print = true;
714: int ptr = 0;
715: int height = (int) barHeight;
716: int pix[] = new int[width * height];
717: for (int k = 0; k < bars.length; ++k) {
718: int w = bars[k];
719: int c = g;
720: if (print)
721: c = f;
722: print = !print;
723: for (int j = 0; j < w; ++j)
724: pix[ptr++] = c;
725: }
726: for (int k = width; k < pix.length; k += width) {
727: System.arraycopy(pix, 0, pix, k, width);
728: }
729: Image img = canvas.createImage(new MemoryImageSource(width,
730: height, pix, 0, width));
731:
732: return img;
733: }
734: }
|