001/* 002 * $Id: BarcodeInter25.java 4784 2011-03-15 08:33:00Z blowagie $ 003 * 004 * This file is part of the iText (R) project. 005 * Copyright (c) 1998-2011 1T3XT BVBA 006 * Authors: Bruno Lowagie, Paulo Soares, et al. 007 * 008 * This program is free software; you can redistribute it and/or modify 009 * it under the terms of the GNU Affero General Public License version 3 010 * as published by the Free Software Foundation with the addition of the 011 * following permission added to Section 15 as permitted in Section 7(a): 012 * FOR ANY PART OF THE COVERED WORK IN WHICH THE COPYRIGHT IS OWNED BY 1T3XT, 013 * 1T3XT DISCLAIMS THE WARRANTY OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. 014 * 015 * This program is distributed in the hope that it will be useful, but 016 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 017 * or FITNESS FOR A PARTICULAR PURPOSE. 018 * See the GNU Affero General Public License for more details. 019 * You should have received a copy of the GNU Affero General Public License 020 * along with this program; if not, see http://www.gnu.org/licenses or write to 021 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 022 * Boston, MA, 02110-1301 USA, or download the license from the following URL: 023 * http://itextpdf.com/terms-of-use/ 024 * 025 * The interactive user interfaces in modified source and object code versions 026 * of this program must display Appropriate Legal Notices, as required under 027 * Section 5 of the GNU Affero General Public License. 028 * 029 * In accordance with Section 7(b) of the GNU Affero General Public License, 030 * a covered work must retain the producer line in every PDF that is created 031 * or manipulated using iText. 032 * 033 * You can be released from the requirements of the license by purchasing 034 * a commercial license. Buying such a license is mandatory as soon as you 035 * develop commercial activities involving the iText software without 036 * disclosing the source code of your own applications. 037 * These activities include: offering paid services to customers as an ASP, 038 * serving PDFs on the fly in a web application, shipping iText with a closed 039 * source product. 040 * 041 * For more information, please contact iText Software Corp. at this 042 * address: sales@itextpdf.com 043 */ 044package com.itextpdf.text.pdf; 045 046import java.awt.Canvas; 047import java.awt.Image; 048import java.awt.image.MemoryImageSource; 049import com.itextpdf.text.error_messages.MessageLocalization; 050 051import com.itextpdf.text.Element; 052import com.itextpdf.text.ExceptionConverter; 053import com.itextpdf.text.Rectangle; 054import com.itextpdf.text.BaseColor; 055 056/** Implements the code interleaved 2 of 5. The text can include 057 * non numeric characters that are printed but do not generate bars. 058 * The default parameters are: 059 * <pre> 060 *x = 0.8f; 061 *n = 2; 062 *font = BaseFont.createFont("Helvetica", "winansi", false); 063 *size = 8; 064 *baseline = size; 065 *barHeight = size * 3; 066 *textAlignment = Element.ALIGN_CENTER; 067 *generateChecksum = false; 068 *checksumText = false; 069 * </pre> 070 * 071 * @author Paulo Soares 072 */ 073public class BarcodeInter25 extends Barcode{ 074 075 /** The bars to generate the code. 076 */ 077 private static final byte BARS[][] = 078 { 079 {0,0,1,1,0}, 080 {1,0,0,0,1}, 081 {0,1,0,0,1}, 082 {1,1,0,0,0}, 083 {0,0,1,0,1}, 084 {1,0,1,0,0}, 085 {0,1,1,0,0}, 086 {0,0,0,1,1}, 087 {1,0,0,1,0}, 088 {0,1,0,1,0} 089 }; 090 091 /** Creates new BarcodeInter25 */ 092 public BarcodeInter25() { 093 try { 094 x = 0.8f; 095 n = 2; 096 font = BaseFont.createFont("Helvetica", "winansi", false); 097 size = 8; 098 baseline = size; 099 barHeight = size * 3; 100 textAlignment = Element.ALIGN_CENTER; 101 generateChecksum = false; 102 checksumText = false; 103 } 104 catch (Exception e) { 105 throw new ExceptionConverter(e); 106 } 107 } 108 109 /** Deletes all the non numeric characters from <CODE>text</CODE>. 110 * @param text the text 111 * @return a <CODE>String</CODE> with only numeric characters 112 */ 113 public static String keepNumbers(String text) { 114 StringBuffer sb = new StringBuffer(); 115 for (int k = 0; k < text.length(); ++k) { 116 char c = text.charAt(k); 117 if (c >= '0' && c <= '9') 118 sb.append(c); 119 } 120 return sb.toString(); 121 } 122 123 /** Calculates the checksum. 124 * @param text the numeric text 125 * @return the checksum 126 */ 127 public static char getChecksum(String text) { 128 int mul = 3; 129 int total = 0; 130 for (int k = text.length() - 1; k >= 0; --k) { 131 int n = text.charAt(k) - '0'; 132 total += mul * n; 133 mul ^= 2; 134 } 135 return (char)(((10 - (total % 10)) % 10) + '0'); 136 } 137 138 /** Creates the bars for the barcode. 139 * @param text the text. It can contain non numeric characters 140 * @return the barcode 141 */ 142 public static byte[] getBarsInter25(String text) { 143 text = keepNumbers(text); 144 if ((text.length() & 1) != 0) 145 throw new IllegalArgumentException(MessageLocalization.getComposedMessage("the.text.length.must.be.even")); 146 byte bars[] = new byte[text.length() * 5 + 7]; 147 int pb = 0; 148 bars[pb++] = 0; 149 bars[pb++] = 0; 150 bars[pb++] = 0; 151 bars[pb++] = 0; 152 int len = text.length() / 2; 153 for (int k = 0; k < len; ++k) { 154 int c1 = text.charAt(k * 2) - '0'; 155 int c2 = text.charAt(k * 2 + 1) - '0'; 156 byte b1[] = BARS[c1]; 157 byte b2[] = BARS[c2]; 158 for (int j = 0; j < 5; ++j) { 159 bars[pb++] = b1[j]; 160 bars[pb++] = b2[j]; 161 } 162 } 163 bars[pb++] = 1; 164 bars[pb++] = 0; 165 bars[pb++] = 0; 166 return bars; 167 } 168 169 /** Gets the maximum area that the barcode and the text, if 170 * any, will occupy. The lower left corner is always (0, 0). 171 * @return the size the barcode occupies. 172 */ 173 public Rectangle getBarcodeSize() { 174 float fontX = 0; 175 float fontY = 0; 176 if (font != null) { 177 if (baseline > 0) 178 fontY = baseline - font.getFontDescriptor(BaseFont.DESCENT, size); 179 else 180 fontY = -baseline + size; 181 String fullCode = code; 182 if (generateChecksum && checksumText) 183 fullCode += getChecksum(fullCode); 184 fontX = font.getWidthPoint(altText != null ? altText : fullCode, size); 185 } 186 String fullCode = keepNumbers(code); 187 int len = fullCode.length(); 188 if (generateChecksum) 189 ++len; 190 float fullWidth = len * (3 * x + 2 * x * n) + (6 + n ) * x; 191 fullWidth = Math.max(fullWidth, fontX); 192 float fullHeight = barHeight + fontY; 193 return new Rectangle(fullWidth, fullHeight); 194 } 195 196 /** Places the barcode in a <CODE>PdfContentByte</CODE>. The 197 * barcode is always placed at coordinates (0, 0). Use the 198 * translation matrix to move it elsewhere.<p> 199 * The bars and text are written in the following colors:<p> 200 * <P><TABLE BORDER=1> 201 * <TR> 202 * <TH><P><CODE>barColor</CODE></TH> 203 * <TH><P><CODE>textColor</CODE></TH> 204 * <TH><P>Result</TH> 205 * </TR> 206 * <TR> 207 * <TD><P><CODE>null</CODE></TD> 208 * <TD><P><CODE>null</CODE></TD> 209 * <TD><P>bars and text painted with current fill color</TD> 210 * </TR> 211 * <TR> 212 * <TD><P><CODE>barColor</CODE></TD> 213 * <TD><P><CODE>null</CODE></TD> 214 * <TD><P>bars and text painted with <CODE>barColor</CODE></TD> 215 * </TR> 216 * <TR> 217 * <TD><P><CODE>null</CODE></TD> 218 * <TD><P><CODE>textColor</CODE></TD> 219 * <TD><P>bars painted with current color<br>text painted with <CODE>textColor</CODE></TD> 220 * </TR> 221 * <TR> 222 * <TD><P><CODE>barColor</CODE></TD> 223 * <TD><P><CODE>textColor</CODE></TD> 224 * <TD><P>bars painted with <CODE>barColor</CODE><br>text painted with <CODE>textColor</CODE></TD> 225 * </TR> 226 * </TABLE> 227 * @param cb the <CODE>PdfContentByte</CODE> where the barcode will be placed 228 * @param barColor the color of the bars. It can be <CODE>null</CODE> 229 * @param textColor the color of the text. It can be <CODE>null</CODE> 230 * @return the dimensions the barcode occupies 231 */ 232 public Rectangle placeBarcode(PdfContentByte cb, BaseColor barColor, BaseColor 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(fullCode = altText != null ? altText : fullCode, size); 239 } 240 String bCode = keepNumbers(code); 241 if (generateChecksum) 242 bCode += getChecksum(bCode); 243 int len = bCode.length(); 244 float fullWidth = len * (3 * x + 2 * x * n) + (6 + n ) * x; 245 float barStartX = 0; 246 float textStartX = 0; 247 switch (textAlignment) { 248 case Element.ALIGN_LEFT: 249 break; 250 case Element.ALIGN_RIGHT: 251 if (fontX > fullWidth) 252 barStartX = fontX - fullWidth; 253 else 254 textStartX = fullWidth - fontX; 255 break; 256 default: 257 if (fontX > fullWidth) 258 barStartX = (fontX - fullWidth) / 2; 259 else 260 textStartX = (fullWidth - fontX) / 2; 261 break; 262 } 263 float barStartY = 0; 264 float textStartY = 0; 265 if (font != null) { 266 if (baseline <= 0) 267 textStartY = barHeight - baseline; 268 else { 269 textStartY = -font.getFontDescriptor(BaseFont.DESCENT, size); 270 barStartY = textStartY + baseline; 271 } 272 } 273 byte bars[] = getBarsInter25(bCode); 274 boolean print = true; 275 if (barColor != null) 276 cb.setColorFill(barColor); 277 for (int k = 0; k < bars.length; ++k) { 278 float w = (bars[k] == 0 ? x : x * n); 279 if (print) 280 cb.rectangle(barStartX, barStartY, w - inkSpreading, barHeight); 281 print = !print; 282 barStartX += w; 283 } 284 cb.fill(); 285 if (font != null) { 286 if (textColor != null) 287 cb.setColorFill(textColor); 288 cb.beginText(); 289 cb.setFontAndSize(font, size); 290 cb.setTextMatrix(textStartX, textStartY); 291 cb.showText(fullCode); 292 cb.endText(); 293 } 294 return getBarcodeSize(); 295 } 296 297 /** Creates a <CODE>java.awt.Image</CODE>. This image only 298 * contains the bars without any text. 299 * @param foreground the color of the bars 300 * @param background the color of the background 301 * @return the image 302 */ 303 public java.awt.Image createAwtImage(java.awt.Color foreground, java.awt.Color background) { 304 int f = foreground.getRGB(); 305 int g = background.getRGB(); 306 Canvas canvas = new Canvas(); 307 308 String bCode = keepNumbers(code); 309 if (generateChecksum) 310 bCode += getChecksum(bCode); 311 int len = bCode.length(); 312 int nn = (int)n; 313 int fullWidth = len * (3 + 2 * nn) + (6 + nn ); 314 byte bars[] = getBarsInter25(bCode); 315 boolean print = true; 316 int ptr = 0; 317 int height = (int)barHeight; 318 int pix[] = new int[fullWidth * height]; 319 for (int k = 0; k < bars.length; ++k) { 320 int w = (bars[k] == 0 ? 1 : nn); 321 int c = g; 322 if (print) 323 c = f; 324 print = !print; 325 for (int j = 0; j < w; ++j) 326 pix[ptr++] = c; 327 } 328 for (int k = fullWidth; k < pix.length; k += fullWidth) { 329 System.arraycopy(pix, 0, pix, k, fullWidth); 330 } 331 Image img = canvas.createImage(new MemoryImageSource(fullWidth, height, pix, 0, fullWidth)); 332 333 return img; 334 } 335}