001/* 002 * $Id: BarcodeEAN.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.MemoryImageSource; 048import java.util.Arrays; 049import com.itextpdf.text.error_messages.MessageLocalization; 050 051import com.itextpdf.text.ExceptionConverter; 052import com.itextpdf.text.Rectangle; 053import com.itextpdf.text.BaseColor; 054 055/** Generates barcodes in several formats: EAN13, EAN8, UPCA, UPCE, 056 * supplemental 2 and 5. The default parameters are: 057 * <pre> 058 *x = 0.8f; 059 *font = BaseFont.createFont("Helvetica", "winansi", false); 060 *size = 8; 061 *baseline = size; 062 *barHeight = size * 3; 063 *guardBars = true; 064 *codeType = EAN13; 065 *code = ""; 066 * </pre> 067 * 068 * @author Paulo Soares 069 */ 070public class BarcodeEAN extends Barcode{ 071 072 /** The bar positions that are guard bars.*/ 073 private static final int GUARD_EMPTY[] = {}; 074 /** The bar positions that are guard bars.*/ 075 private static final int GUARD_UPCA[] = {0, 2, 4, 6, 28, 30, 52, 54, 56, 58}; 076 /** The bar positions that are guard bars.*/ 077 private static final int GUARD_EAN13[] = {0, 2, 28, 30, 56, 58}; 078 /** The bar positions that are guard bars.*/ 079 private static final int GUARD_EAN8[] = {0, 2, 20, 22, 40, 42}; 080 /** The bar positions that are guard bars.*/ 081 private static final int GUARD_UPCE[] = {0, 2, 28, 30, 32}; 082 /** The x coordinates to place the text.*/ 083 private static final float TEXTPOS_EAN13[] = {6.5f, 13.5f, 20.5f, 27.5f, 34.5f, 41.5f, 53.5f, 60.5f, 67.5f, 74.5f, 81.5f, 88.5f}; 084 /** The x coordinates to place the text.*/ 085 private static final float TEXTPOS_EAN8[] = {6.5f, 13.5f, 20.5f, 27.5f, 39.5f, 46.5f, 53.5f, 60.5f}; 086 /** The basic bar widths.*/ 087 private static final byte BARS[][] = 088 { 089 {3, 2, 1, 1}, // 0 090 {2, 2, 2, 1}, // 1 091 {2, 1, 2, 2}, // 2 092 {1, 4, 1, 1}, // 3 093 {1, 1, 3, 2}, // 4 094 {1, 2, 3, 1}, // 5 095 {1, 1, 1, 4}, // 6 096 {1, 3, 1, 2}, // 7 097 {1, 2, 1, 3}, // 8 098 {3, 1, 1, 2} // 9 099 }; 100 101 /** The total number of bars for EAN13.*/ 102 private static final int TOTALBARS_EAN13 = 11 + 12 * 4; 103 /** The total number of bars for EAN8.*/ 104 private static final int TOTALBARS_EAN8 = 11 + 8 * 4; 105 /** The total number of bars for UPCE.*/ 106 private static final int TOTALBARS_UPCE = 9 + 6 * 4; 107 /** The total number of bars for supplemental 2.*/ 108 private static final int TOTALBARS_SUPP2 = 13; 109 /** The total number of bars for supplemental 5.*/ 110 private static final int TOTALBARS_SUPP5 = 31; 111 /** Marker for odd parity.*/ 112 private static final int ODD = 0; 113 /** Marker for even parity.*/ 114 private static final int EVEN = 1; 115 116 /** Sequence of parities to be used with EAN13.*/ 117 private static final byte PARITY13[][] = 118 { 119 {ODD, ODD, ODD, ODD, ODD, ODD}, // 0 120 {ODD, ODD, EVEN, ODD, EVEN, EVEN}, // 1 121 {ODD, ODD, EVEN, EVEN, ODD, EVEN}, // 2 122 {ODD, ODD, EVEN, EVEN, EVEN, ODD}, // 3 123 {ODD, EVEN, ODD, ODD, EVEN, EVEN}, // 4 124 {ODD, EVEN, EVEN, ODD, ODD, EVEN}, // 5 125 {ODD, EVEN, EVEN, EVEN, ODD, ODD}, // 6 126 {ODD, EVEN, ODD, EVEN, ODD, EVEN}, // 7 127 {ODD, EVEN, ODD, EVEN, EVEN, ODD}, // 8 128 {ODD, EVEN, EVEN, ODD, EVEN, ODD} // 9 129 }; 130 131 /** Sequence of parities to be used with supplemental 2.*/ 132 private static final byte PARITY2[][] = 133 { 134 {ODD, ODD}, // 0 135 {ODD, EVEN}, // 1 136 {EVEN, ODD}, // 2 137 {EVEN, EVEN} // 3 138 }; 139 140 /** Sequence of parities to be used with supplemental 2.*/ 141 private static final byte PARITY5[][] = 142 { 143 {EVEN, EVEN, ODD, ODD, ODD}, // 0 144 {EVEN, ODD, EVEN, ODD, ODD}, // 1 145 {EVEN, ODD, ODD, EVEN, ODD}, // 2 146 {EVEN, ODD, ODD, ODD, EVEN}, // 3 147 {ODD, EVEN, EVEN, ODD, ODD}, // 4 148 {ODD, ODD, EVEN, EVEN, ODD}, // 5 149 {ODD, ODD, ODD, EVEN, EVEN}, // 6 150 {ODD, EVEN, ODD, EVEN, ODD}, // 7 151 {ODD, EVEN, ODD, ODD, EVEN}, // 8 152 {ODD, ODD, EVEN, ODD, EVEN} // 9 153 }; 154 155 /** Sequence of parities to be used with UPCE.*/ 156 private static final byte PARITYE[][] = 157 { 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 } 182 catch (Exception e) { 183 throw new ExceptionConverter(e); 184 } 185 } 186 187 /** Calculates the EAN parity character. 188 * @param code the code 189 * @return the parity character 190 */ 191 public static int calculateEANParity(String code) { 192 int mul = 3; 193 int total = 0; 194 for (int k = code.length() - 1; k >= 0; --k) { 195 int n = code.charAt(k) - '0'; 196 total += mul * n; 197 mul ^= 2; 198 } 199 return (10 - (total % 10)) % 10; 200 } 201 202 /** Converts an UPCA code into an UPCE code. If the code can not 203 * be converted a <CODE>null</CODE> is returned. 204 * @param text the code to convert. It must have 12 numeric characters 205 * @return the 8 converted digits or <CODE>null</CODE> if the 206 * code could not be converted 207 */ 208 static public String convertUPCAtoUPCE(String text) { 209 if (text.length() != 12 || !(text.startsWith("0") || text.startsWith("1"))) 210 return null; 211 if (text.substring(3, 6).equals("000") || text.substring(3, 6).equals("100") 212 || text.substring(3, 6).equals("200")) { 213 if (text.substring(6, 8).equals("00")) 214 return text.substring(0, 1) + text.substring(1, 3) + text.substring(8, 11) + text.substring(3, 4) + text.substring(11); 215 } 216 else if (text.substring(4, 6).equals("00")) { 217 if (text.substring(6, 9).equals("000")) 218 return text.substring(0, 1) + text.substring(1, 4) + text.substring(9, 11) + "3" + text.substring(11); 219 } 220 else if (text.substring(5, 6).equals("0")) { 221 if (text.substring(6, 10).equals("0000")) 222 return text.substring(0, 1) + text.substring(1, 5) + text.substring(10, 11) + "4" + text.substring(11); 223 } 224 else if (text.charAt(10) >= '5') { 225 if (text.substring(6, 10).equals("0000")) 226 return text.substring(0, 1) + text.substring(1, 6) + text.substring(10, 11) + text.substring(11); 227 } 228 return null; 229 } 230 231 /** Creates the bars for the barcode EAN13 and UPCA. 232 * @param _code the text with 13 digits 233 * @return the barcode 234 */ 235 public static byte[] getBarsEAN13(String _code) { 236 int code[] = new int[_code.length()]; 237 for (int k = 0; k < code.length; ++k) 238 code[k] = _code.charAt(k) - '0'; 239 byte bars[] = new byte[TOTALBARS_EAN13]; 240 int pb = 0; 241 bars[pb++] = 1; 242 bars[pb++] = 1; 243 bars[pb++] = 1; 244 byte sequence[] = PARITY13[code[0]]; 245 for (int k = 0; k < sequence.length; ++k) { 246 int c = code[k + 1]; 247 byte stripes[] = BARS[c]; 248 if (sequence[k] == ODD) { 249 bars[pb++] = stripes[0]; 250 bars[pb++] = stripes[1]; 251 bars[pb++] = stripes[2]; 252 bars[pb++] = stripes[3]; 253 } 254 else { 255 bars[pb++] = stripes[3]; 256 bars[pb++] = stripes[2]; 257 bars[pb++] = stripes[1]; 258 bars[pb++] = stripes[0]; 259 } 260 } 261 bars[pb++] = 1; 262 bars[pb++] = 1; 263 bars[pb++] = 1; 264 bars[pb++] = 1; 265 bars[pb++] = 1; 266 for (int k = 7; k < 13; ++k) { 267 int c = code[k]; 268 byte stripes[] = BARS[c]; 269 bars[pb++] = stripes[0]; 270 bars[pb++] = stripes[1]; 271 bars[pb++] = stripes[2]; 272 bars[pb++] = stripes[3]; 273 } 274 bars[pb++] = 1; 275 bars[pb++] = 1; 276 bars[pb++] = 1; 277 return bars; 278 } 279 280 /** Creates the bars for the barcode EAN8. 281 * @param _code the text with 8 digits 282 * @return the barcode 283 */ 284 public static byte[] getBarsEAN8(String _code) { 285 int code[] = new int[_code.length()]; 286 for (int k = 0; k < code.length; ++k) 287 code[k] = _code.charAt(k) - '0'; 288 byte bars[] = new byte[TOTALBARS_EAN8]; 289 int pb = 0; 290 bars[pb++] = 1; 291 bars[pb++] = 1; 292 bars[pb++] = 1; 293 for (int k = 0; k < 4; ++k) { 294 int c = code[k]; 295 byte stripes[] = BARS[c]; 296 bars[pb++] = stripes[0]; 297 bars[pb++] = stripes[1]; 298 bars[pb++] = stripes[2]; 299 bars[pb++] = stripes[3]; 300 } 301 bars[pb++] = 1; 302 bars[pb++] = 1; 303 bars[pb++] = 1; 304 bars[pb++] = 1; 305 bars[pb++] = 1; 306 for (int k = 4; k < 8; ++k) { 307 int c = code[k]; 308 byte stripes[] = BARS[c]; 309 bars[pb++] = stripes[0]; 310 bars[pb++] = stripes[1]; 311 bars[pb++] = stripes[2]; 312 bars[pb++] = stripes[3]; 313 } 314 bars[pb++] = 1; 315 bars[pb++] = 1; 316 bars[pb++] = 1; 317 return bars; 318 } 319 320 /** Creates the bars for the barcode UPCE. 321 * @param _code the text with 8 digits 322 * @return the barcode 323 */ 324 public static byte[] getBarsUPCE(String _code) { 325 int code[] = new int[_code.length()]; 326 for (int k = 0; k < code.length; ++k) 327 code[k] = _code.charAt(k) - '0'; 328 byte bars[] = new byte[TOTALBARS_UPCE]; 329 boolean flip = (code[0] != 0); 330 int pb = 0; 331 bars[pb++] = 1; 332 bars[pb++] = 1; 333 bars[pb++] = 1; 334 byte sequence[] = PARITYE[code[code.length - 1]]; 335 for (int k = 1; k < code.length - 1; ++k) { 336 int c = code[k]; 337 byte stripes[] = BARS[c]; 338 if (sequence[k - 1] == (flip ? EVEN : ODD)) { 339 bars[pb++] = stripes[0]; 340 bars[pb++] = stripes[1]; 341 bars[pb++] = stripes[2]; 342 bars[pb++] = stripes[3]; 343 } 344 else { 345 bars[pb++] = stripes[3]; 346 bars[pb++] = stripes[2]; 347 bars[pb++] = stripes[1]; 348 bars[pb++] = stripes[0]; 349 } 350 } 351 bars[pb++] = 1; 352 bars[pb++] = 1; 353 bars[pb++] = 1; 354 bars[pb++] = 1; 355 bars[pb++] = 1; 356 bars[pb++] = 1; 357 return bars; 358 } 359 360 /** Creates the bars for the barcode supplemental 2. 361 * @param _code the text with 2 digits 362 * @return the barcode 363 */ 364 public static byte[] getBarsSupplemental2(String _code) { 365 int code[] = new int[2]; 366 for (int k = 0; k < code.length; ++k) 367 code[k] = _code.charAt(k) - '0'; 368 byte bars[] = new byte[TOTALBARS_SUPP2]; 369 int pb = 0; 370 int parity = (code[0] * 10 + code[1]) % 4; 371 bars[pb++] = 1; 372 bars[pb++] = 1; 373 bars[pb++] = 2; 374 byte sequence[] = PARITY2[parity]; 375 for (int k = 0; k < sequence.length; ++k) { 376 if (k == 1) { 377 bars[pb++] = 1; 378 bars[pb++] = 1; 379 } 380 int c = code[k]; 381 byte stripes[] = BARS[c]; 382 if (sequence[k] == ODD) { 383 bars[pb++] = stripes[0]; 384 bars[pb++] = stripes[1]; 385 bars[pb++] = stripes[2]; 386 bars[pb++] = stripes[3]; 387 } 388 else { 389 bars[pb++] = stripes[3]; 390 bars[pb++] = stripes[2]; 391 bars[pb++] = stripes[1]; 392 bars[pb++] = stripes[0]; 393 } 394 } 395 return bars; 396 } 397 398 /** Creates the bars for the barcode supplemental 5. 399 * @param _code the text with 5 digits 400 * @return the barcode 401 */ 402 public static byte[] getBarsSupplemental5(String _code) { 403 int code[] = new int[5]; 404 for (int k = 0; k < code.length; ++k) 405 code[k] = _code.charAt(k) - '0'; 406 byte bars[] = new byte[TOTALBARS_SUPP5]; 407 int pb = 0; 408 int parity = (((code[0] + code[2] + code[4]) * 3) + ((code[1] + code[3]) * 9)) % 10; 409 bars[pb++] = 1; 410 bars[pb++] = 1; 411 bars[pb++] = 2; 412 byte sequence[] = PARITY5[parity]; 413 for (int k = 0; k < sequence.length; ++k) { 414 if (k != 0) { 415 bars[pb++] = 1; 416 bars[pb++] = 1; 417 } 418 int c = code[k]; 419 byte stripes[] = BARS[c]; 420 if (sequence[k] == ODD) { 421 bars[pb++] = stripes[0]; 422 bars[pb++] = stripes[1]; 423 bars[pb++] = stripes[2]; 424 bars[pb++] = stripes[3]; 425 } 426 else { 427 bars[pb++] = stripes[3]; 428 bars[pb++] = stripes[2]; 429 bars[pb++] = stripes[1]; 430 bars[pb++] = stripes[0]; 431 } 432 } 433 return bars; 434 } 435 436 /** Gets the maximum area that the barcode and the text, if 437 * any, will occupy. The lower left corner is always (0, 0). 438 * @return the size the barcode occupies. 439 */ 440 public Rectangle getBarcodeSize() { 441 float width = 0; 442 float height = barHeight; 443 if (font != null) { 444 if (baseline <= 0) 445 height += -baseline + size; 446 else 447 height += baseline - font.getFontDescriptor(BaseFont.DESCENT, size); 448 } 449 switch (codeType) { 450 case EAN13: 451 width = x * (11 + 12 * 7); 452 if (font != null) { 453 width += font.getWidthPoint(code.charAt(0), size); 454 } 455 break; 456 case EAN8: 457 width = x * (11 + 8 * 7); 458 break; 459 case UPCA: 460 width = x * (11 + 12 * 7); 461 if (font != null) { 462 width += font.getWidthPoint(code.charAt(0), size) + font.getWidthPoint(code.charAt(11), size); 463 } 464 break; 465 case UPCE: 466 width = x * (9 + 6 * 7); 467 if (font != null) { 468 width += font.getWidthPoint(code.charAt(0), size) + font.getWidthPoint(code.charAt(7), size); 469 } 470 break; 471 case SUPP2: 472 width = x * (6 + 2 * 7); 473 break; 474 case SUPP5: 475 width = x * (4 + 5 * 7 + 4 * 2); 476 break; 477 default: 478 throw new RuntimeException(MessageLocalization.getComposedMessage("invalid.code.type")); 479 } 480 return new Rectangle(width, height); 481 } 482 483 /** Places the barcode in a <CODE>PdfContentByte</CODE>. The 484 * barcode is always placed at coordinates (0, 0). Use the 485 * translation matrix to move it elsewhere.<p> 486 * The bars and text are written in the following colors:<p> 487 * <P><TABLE BORDER=1> 488 * <TR> 489 * <TH><P><CODE>barColor</CODE></TH> 490 * <TH><P><CODE>textColor</CODE></TH> 491 * <TH><P>Result</TH> 492 * </TR> 493 * <TR> 494 * <TD><P><CODE>null</CODE></TD> 495 * <TD><P><CODE>null</CODE></TD> 496 * <TD><P>bars and text painted with current fill color</TD> 497 * </TR> 498 * <TR> 499 * <TD><P><CODE>barColor</CODE></TD> 500 * <TD><P><CODE>null</CODE></TD> 501 * <TD><P>bars and text painted with <CODE>barColor</CODE></TD> 502 * </TR> 503 * <TR> 504 * <TD><P><CODE>null</CODE></TD> 505 * <TD><P><CODE>textColor</CODE></TD> 506 * <TD><P>bars painted with current color<br>text painted with <CODE>textColor</CODE></TD> 507 * </TR> 508 * <TR> 509 * <TD><P><CODE>barColor</CODE></TD> 510 * <TD><P><CODE>textColor</CODE></TD> 511 * <TD><P>bars painted with <CODE>barColor</CODE><br>text painted with <CODE>textColor</CODE></TD> 512 * </TR> 513 * </TABLE> 514 * @param cb the <CODE>PdfContentByte</CODE> where the barcode will be placed 515 * @param barColor the color of the bars. It can be <CODE>null</CODE> 516 * @param textColor the color of the text. It can be <CODE>null</CODE> 517 * @return the dimensions the barcode occupies 518 */ 519 public Rectangle placeBarcode(PdfContentByte cb, BaseColor barColor, BaseColor textColor) { 520 Rectangle rect = getBarcodeSize(); 521 float barStartX = 0; 522 float barStartY = 0; 523 float textStartY = 0; 524 if (font != null) { 525 if (baseline <= 0) 526 textStartY = barHeight - baseline; 527 else { 528 textStartY = -font.getFontDescriptor(BaseFont.DESCENT, size); 529 barStartY = textStartY + baseline; 530 } 531 } 532 switch (codeType) { 533 case EAN13: 534 case UPCA: 535 case UPCE: 536 if (font != null) 537 barStartX += font.getWidthPoint(code.charAt(0), size); 538 break; 539 } 540 byte bars[] = null; 541 int guard[] = GUARD_EMPTY; 542 switch (codeType) { 543 case EAN13: 544 bars = getBarsEAN13(code); 545 guard = GUARD_EAN13; 546 break; 547 case EAN8: 548 bars = getBarsEAN8(code); 549 guard = GUARD_EAN8; 550 break; 551 case UPCA: 552 bars = getBarsEAN13("0" + code); 553 guard = GUARD_UPCA; 554 break; 555 case UPCE: 556 bars = getBarsUPCE(code); 557 guard = GUARD_UPCE; 558 break; 559 case SUPP2: 560 bars = getBarsSupplemental2(code); 561 break; 562 case SUPP5: 563 bars = getBarsSupplemental5(code); 564 break; 565 } 566 float keepBarX = barStartX; 567 boolean print = true; 568 float gd = 0; 569 if (font != null && baseline > 0 && guardBars) { 570 gd = baseline / 2; 571 } 572 if (barColor != null) 573 cb.setColorFill(barColor); 574 for (int k = 0; k < bars.length; ++k) { 575 float w = bars[k] * x; 576 if (print) { 577 if (Arrays.binarySearch(guard, k) >= 0) 578 cb.rectangle(barStartX, barStartY - gd, w - inkSpreading, barHeight + gd); 579 else 580 cb.rectangle(barStartX, barStartY, w - inkSpreading, barHeight); 581 } 582 print = !print; 583 barStartX += w; 584 } 585 cb.fill(); 586 if (font != null) { 587 if (textColor != null) 588 cb.setColorFill(textColor); 589 cb.beginText(); 590 cb.setFontAndSize(font, size); 591 switch (codeType) { 592 case EAN13: 593 cb.setTextMatrix(0, textStartY); 594 cb.showText(code.substring(0, 1)); 595 for (int k = 1; k < 13; ++k) { 596 String c = code.substring(k, k + 1); 597 float len = font.getWidthPoint(c, size); 598 float pX = keepBarX + TEXTPOS_EAN13[k - 1] * x - len / 2; 599 cb.setTextMatrix(pX, textStartY); 600 cb.showText(c); 601 } 602 break; 603 case EAN8: 604 for (int k = 0; k < 8; ++k) { 605 String c = code.substring(k, k + 1); 606 float len = font.getWidthPoint(c, size); 607 float pX = TEXTPOS_EAN8[k] * x - len / 2; 608 cb.setTextMatrix(pX, textStartY); 609 cb.showText(c); 610 } 611 break; 612 case UPCA: 613 cb.setTextMatrix(0, textStartY); 614 cb.showText(code.substring(0, 1)); 615 for (int k = 1; k < 11; ++k) { 616 String c = code.substring(k, k + 1); 617 float len = font.getWidthPoint(c, size); 618 float pX = keepBarX + TEXTPOS_EAN13[k] * x - len / 2; 619 cb.setTextMatrix(pX, textStartY); 620 cb.showText(c); 621 } 622 cb.setTextMatrix(keepBarX + x * (11 + 12 * 7), textStartY); 623 cb.showText(code.substring(11, 12)); 624 break; 625 case UPCE: 626 cb.setTextMatrix(0, textStartY); 627 cb.showText(code.substring(0, 1)); 628 for (int k = 1; k < 7; ++k) { 629 String c = code.substring(k, k + 1); 630 float len = font.getWidthPoint(c, size); 631 float pX = keepBarX + TEXTPOS_EAN13[k - 1] * x - len / 2; 632 cb.setTextMatrix(pX, textStartY); 633 cb.showText(c); 634 } 635 cb.setTextMatrix(keepBarX + x * (9 + 6 * 7), textStartY); 636 cb.showText(code.substring(7, 8)); 637 break; 638 case SUPP2: 639 case SUPP5: 640 for (int k = 0; k < code.length(); ++k) { 641 String c = code.substring(k, k + 1); 642 float len = font.getWidthPoint(c, size); 643 float pX = (7.5f + (9 * k)) * x - len / 2; 644 cb.setTextMatrix(pX, textStartY); 645 cb.showText(c); 646 } 647 break; 648 } 649 cb.endText(); 650 } 651 return rect; 652 } 653 654 /** Creates a <CODE>java.awt.Image</CODE>. This image only 655 * contains the bars without any text. 656 * @param foreground the color of the bars 657 * @param background the color of the background 658 * @return the image 659 */ 660 public java.awt.Image createAwtImage(java.awt.Color foreground, java.awt.Color background) { 661 int f = foreground.getRGB(); 662 int g = background.getRGB(); 663 Canvas canvas = new Canvas(); 664 665 int width = 0; 666 byte bars[] = null; 667 switch (codeType) { 668 case EAN13: 669 bars = getBarsEAN13(code); 670 width = 11 + 12 * 7; 671 break; 672 case EAN8: 673 bars = getBarsEAN8(code); 674 width = 11 + 8 * 7; 675 break; 676 case UPCA: 677 bars = getBarsEAN13("0" + code); 678 width = 11 + 12 * 7; 679 break; 680 case UPCE: 681 bars = getBarsUPCE(code); 682 width = 9 + 6 * 7; 683 break; 684 case SUPP2: 685 bars = getBarsSupplemental2(code); 686 width = 6 + 2 * 7; 687 break; 688 case SUPP5: 689 bars = getBarsSupplemental5(code); 690 width = 4 + 5 * 7 + 4 * 2; 691 break; 692 default: 693 throw new RuntimeException(MessageLocalization.getComposedMessage("invalid.code.type")); 694 } 695 696 boolean print = true; 697 int ptr = 0; 698 int height = (int)barHeight; 699 int pix[] = new int[width * height]; 700 for (int k = 0; k < bars.length; ++k) { 701 int w = bars[k]; 702 int c = g; 703 if (print) 704 c = f; 705 print = !print; 706 for (int j = 0; j < w; ++j) 707 pix[ptr++] = c; 708 } 709 for (int k = width; k < pix.length; k += width) { 710 System.arraycopy(pix, 0, pix, k, width); 711 } 712 java.awt.Image img = canvas.createImage(new MemoryImageSource(width, height, pix, 0, width)); 713 714 return img; 715 } 716}