001: /*
002: * $Id: BarcodeInter25.java 2374 2006-09-15 05:11:54Z xlv $
003: *
004: * Copyright 2002-2006 by Paulo Soares.
005: *
006: * The contents of this file are subject to the Mozilla Public License Version 1.1
007: * (the "License"); you may not use this file except in compliance with the License.
008: * You may obtain a copy of the License at http://www.mozilla.org/MPL/
009: *
010: * Software distributed under the License is distributed on an "AS IS" basis,
011: * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
012: * for the specific language governing rights and limitations under the License.
013: *
014: * The Original Code is 'iText, a free JAVA-PDF library'.
015: *
016: * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by
017: * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie.
018: * All Rights Reserved.
019: * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer
020: * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved.
021: *
022: * Contributor(s): all the names of the contributors are added in the source code
023: * where applicable.
024: *
025: * Alternatively, the contents of this file may be used under the terms of the
026: * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the
027: * provisions of LGPL are applicable instead of those above. If you wish to
028: * allow use of your version of this file only under the terms of the LGPL
029: * License and not to allow others to use your version of this file under
030: * the MPL, indicate your decision by deleting the provisions above and
031: * replace them with the notice and other provisions required by the LGPL.
032: * If you do not delete the provisions above, a recipient may use your version
033: * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE.
034: *
035: * This library is free software; you can redistribute it and/or modify it
036: * under the terms of the MPL as stated above or under the terms of the GNU
037: * Library General Public License as published by the Free Software Foundation;
038: * either version 2 of the License, or any later version.
039: *
040: * This library is distributed in the hope that it will be useful, but WITHOUT
041: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
042: * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more
043: * details.
044: *
045: * If you didn't download this code from the following link, you should check if
046: * you aren't using an obsolete version:
047: * http://www.lowagie.com/iText/
048: */
049: package com.lowagie.text.pdf;
050:
051: import java.awt.Canvas;
052: import java.awt.Color;
053: import java.awt.Image;
054: import java.awt.image.MemoryImageSource;
055:
056: import com.lowagie.text.Element;
057: import com.lowagie.text.ExceptionConverter;
058: import com.lowagie.text.Rectangle;
059:
060: /** Implements the code interleaved 2 of 5. The text can include
061: * non numeric characters that are printed but do not generate bars.
062: * The default parameters are:
063: * <pre>
064: *x = 0.8f;
065: *n = 2;
066: *font = BaseFont.createFont("Helvetica", "winansi", false);
067: *size = 8;
068: *baseline = size;
069: *barHeight = size * 3;
070: *textAlignment = Element.ALIGN_CENTER;
071: *generateChecksum = false;
072: *checksumText = false;
073: * </pre>
074: *
075: * @author Paulo Soares (psoares@consiste.pt)
076: */
077: public class BarcodeInter25 extends Barcode {
078:
079: /** The bars to generate the code.
080: */
081: private static final byte BARS[][] = { { 0, 0, 1, 1, 0 },
082: { 1, 0, 0, 0, 1 }, { 0, 1, 0, 0, 1 }, { 1, 1, 0, 0, 0 },
083: { 0, 0, 1, 0, 1 }, { 1, 0, 1, 0, 0 }, { 0, 1, 1, 0, 0 },
084: { 0, 0, 0, 1, 1 }, { 1, 0, 0, 1, 0 }, { 0, 1, 0, 1, 0 } };
085:
086: /** Creates new BarcodeInter25 */
087: public BarcodeInter25() {
088: try {
089: x = 0.8f;
090: n = 2;
091: font = BaseFont.createFont("Helvetica", "winansi", false);
092: size = 8;
093: baseline = size;
094: barHeight = size * 3;
095: textAlignment = Element.ALIGN_CENTER;
096: generateChecksum = false;
097: checksumText = false;
098: } catch (Exception e) {
099: throw new ExceptionConverter(e);
100: }
101: }
102:
103: /** Deletes all the non numeric characters from <CODE>text</CODE>.
104: * @param text the text
105: * @return a <CODE>String</CODE> with only numeric characters
106: */
107: public static String keepNumbers(String text) {
108: StringBuffer sb = new StringBuffer();
109: for (int k = 0; k < text.length(); ++k) {
110: char c = text.charAt(k);
111: if (c >= '0' && c <= '9')
112: sb.append(c);
113: }
114: return sb.toString();
115: }
116:
117: /** Calculates the checksum.
118: * @param text the numeric text
119: * @return the checksum
120: */
121: public static char getChecksum(String text) {
122: int mul = 3;
123: int total = 0;
124: for (int k = text.length() - 1; k >= 0; --k) {
125: int n = text.charAt(k) - '0';
126: total += mul * n;
127: mul ^= 2;
128: }
129: return (char) (((10 - (total % 10)) % 10) + '0');
130: }
131:
132: /** Creates the bars for the barcode.
133: * @param text the text. It can contain non numeric characters
134: * @return the barcode
135: */
136: public static byte[] getBarsInter25(String text) {
137: text = keepNumbers(text);
138: if ((text.length() & 1) != 0)
139: throw new IllegalArgumentException(
140: "The text length must be even.");
141: byte bars[] = new byte[text.length() * 5 + 7];
142: int pb = 0;
143: bars[pb++] = 0;
144: bars[pb++] = 0;
145: bars[pb++] = 0;
146: bars[pb++] = 0;
147: int len = text.length() / 2;
148: for (int k = 0; k < len; ++k) {
149: int c1 = text.charAt(k * 2) - '0';
150: int c2 = text.charAt(k * 2 + 1) - '0';
151: byte b1[] = BARS[c1];
152: byte b2[] = BARS[c2];
153: for (int j = 0; j < 5; ++j) {
154: bars[pb++] = b1[j];
155: bars[pb++] = b2[j];
156: }
157: }
158: bars[pb++] = 1;
159: bars[pb++] = 0;
160: bars[pb++] = 0;
161: return bars;
162: }
163:
164: /** Gets the maximum area that the barcode and the text, if
165: * any, will occupy. The lower left corner is always (0, 0).
166: * @return the size the barcode occupies.
167: */
168: public Rectangle getBarcodeSize() {
169: float fontX = 0;
170: float fontY = 0;
171: if (font != null) {
172: if (baseline > 0)
173: fontY = baseline
174: - font
175: .getFontDescriptor(BaseFont.DESCENT,
176: size);
177: else
178: fontY = -baseline + size;
179: String fullCode = code;
180: if (generateChecksum && checksumText)
181: fullCode += getChecksum(fullCode);
182: fontX = font.getWidthPoint(altText != null ? altText
183: : fullCode, size);
184: }
185: String fullCode = keepNumbers(code);
186: int len = fullCode.length();
187: if (generateChecksum)
188: ++len;
189: float fullWidth = len * (3 * x + 2 * x * n) + (6 + n) * x;
190: fullWidth = Math.max(fullWidth, fontX);
191: float fullHeight = barHeight + fontY;
192: return new Rectangle(fullWidth, fullHeight);
193: }
194:
195: /** Places the barcode in a <CODE>PdfContentByte</CODE>. The
196: * barcode is always placed at coodinates (0, 0). Use the
197: * translation matrix to move it elsewhere.<p>
198: * The bars and text are written in the following colors:<p>
199: * <P><TABLE BORDER=1>
200: * <TR>
201: * <TH><P><CODE>barColor</CODE></TH>
202: * <TH><P><CODE>textColor</CODE></TH>
203: * <TH><P>Result</TH>
204: * </TR>
205: * <TR>
206: * <TD><P><CODE>null</CODE></TD>
207: * <TD><P><CODE>null</CODE></TD>
208: * <TD><P>bars and text painted with current fill color</TD>
209: * </TR>
210: * <TR>
211: * <TD><P><CODE>barColor</CODE></TD>
212: * <TD><P><CODE>null</CODE></TD>
213: * <TD><P>bars and text painted with <CODE>barColor</CODE></TD>
214: * </TR>
215: * <TR>
216: * <TD><P><CODE>null</CODE></TD>
217: * <TD><P><CODE>textColor</CODE></TD>
218: * <TD><P>bars painted with current color<br>text painted with <CODE>textColor</CODE></TD>
219: * </TR>
220: * <TR>
221: * <TD><P><CODE>barColor</CODE></TD>
222: * <TD><P><CODE>textColor</CODE></TD>
223: * <TD><P>bars painted with <CODE>barColor</CODE><br>text painted with <CODE>textColor</CODE></TD>
224: * </TR>
225: * </TABLE>
226: * @param cb the <CODE>PdfContentByte</CODE> where the barcode will be placed
227: * @param barColor the color of the bars. It can be <CODE>null</CODE>
228: * @param textColor the color of the text. It can be <CODE>null</CODE>
229: * @return the dimensions the barcode occupies
230: */
231: public Rectangle placeBarcode(PdfContentByte cb, Color barColor,
232: Color textColor) {
233: String fullCode = code;
234: float fontX = 0;
235: if (font != null) {
236: if (generateChecksum && checksumText)
237: fullCode += getChecksum(fullCode);
238: fontX = font.getWidthPoint(
239: fullCode = altText != null ? altText : fullCode,
240: size);
241: }
242: String bCode = keepNumbers(code);
243: if (generateChecksum)
244: bCode += getChecksum(bCode);
245: int len = bCode.length();
246: float fullWidth = len * (3 * x + 2 * x * n) + (6 + n) * x;
247: float barStartX = 0;
248: float textStartX = 0;
249: switch (textAlignment) {
250: case Element.ALIGN_LEFT:
251: break;
252: case Element.ALIGN_RIGHT:
253: if (fontX > fullWidth)
254: barStartX = fontX - fullWidth;
255: else
256: textStartX = fullWidth - fontX;
257: break;
258: default:
259: if (fontX > fullWidth)
260: barStartX = (fontX - fullWidth) / 2;
261: else
262: textStartX = (fullWidth - fontX) / 2;
263: break;
264: }
265: float barStartY = 0;
266: float textStartY = 0;
267: if (font != null) {
268: if (baseline <= 0)
269: textStartY = barHeight - baseline;
270: else {
271: textStartY = -font.getFontDescriptor(BaseFont.DESCENT,
272: size);
273: barStartY = textStartY + baseline;
274: }
275: }
276: byte bars[] = getBarsInter25(bCode);
277: boolean print = true;
278: if (barColor != null)
279: cb.setColorFill(barColor);
280: for (int k = 0; k < bars.length; ++k) {
281: float w = (bars[k] == 0 ? x : x * n);
282: if (print)
283: cb.rectangle(barStartX, barStartY, w - inkSpreading,
284: barHeight);
285: print = !print;
286: barStartX += w;
287: }
288: cb.fill();
289: if (font != null) {
290: if (textColor != null)
291: cb.setColorFill(textColor);
292: cb.beginText();
293: cb.setFontAndSize(font, size);
294: cb.setTextMatrix(textStartX, textStartY);
295: cb.showText(fullCode);
296: cb.endText();
297: }
298: return getBarcodeSize();
299: }
300:
301: /** Creates a <CODE>java.awt.Image</CODE>. This image only
302: * contains the bars without any text.
303: * @param foreground the color of the bars
304: * @param background the color of the background
305: * @return the image
306: */
307: public java.awt.Image createAwtImage(Color foreground,
308: Color background) {
309: int f = foreground.getRGB();
310: int g = background.getRGB();
311: Canvas canvas = new Canvas();
312:
313: String bCode = keepNumbers(code);
314: if (generateChecksum)
315: bCode += getChecksum(bCode);
316: int len = bCode.length();
317: int nn = (int) n;
318: int fullWidth = len * (3 + 2 * nn) + (6 + nn);
319: byte bars[] = getBarsInter25(bCode);
320: boolean print = true;
321: int ptr = 0;
322: int height = (int) barHeight;
323: int pix[] = new int[fullWidth * height];
324: for (int k = 0; k < bars.length; ++k) {
325: int w = (bars[k] == 0 ? 1 : nn);
326: int c = g;
327: if (print)
328: c = f;
329: print = !print;
330: for (int j = 0; j < w; ++j)
331: pix[ptr++] = c;
332: }
333: for (int k = fullWidth; k < pix.length; k += fullWidth) {
334: System.arraycopy(pix, 0, pix, k, fullWidth);
335: }
336: Image img = canvas.createImage(new MemoryImageSource(fullWidth,
337: height, pix, 0, fullWidth));
338:
339: return img;
340: }
341: }
|