View Javadoc

1   /*
2    *  This library is free software; you can redistribute it and/or modify it
3    *  under the terms of the GNU Lesser General Public License (LGPL) as
4    *  published by the Free Software Foundation; either version 3.0 of the
5    *  License, or (at your option) any later version.
6    *
7    *  This library is distributed in the hope that it will be useful, but
8    *  WITHOUT ANY WARRANTY; without even the implied warranty of
9    *  MERCHANTABILITY of FITNESS FOR A PARTICULAR PURPOSE. See the GNU
10   *  Lesser General Public License for more details. 
11   *
12   *  This file was contributed to JBarcodeBean by Jose Gaonac'h.
13   *  Copyright (C) 2004 Jose Gaonac'h.
14   */
15  
16  package net.sourceforge.jbarcodebean.model;
17  
18  import net.sourceforge.jbarcodebean.BarcodeException;
19  
20  
21  /**
22   * EAN-13 barcode implementation.
23   * If less than 12 digits are supplied, the symbol is invalid
24   * Only the first 12 digits are considered: the checksum (13th digit) is
25   * always generated (MANDATORY_CHECKSUM).
26   *
27   * @author  Jose Gaonac'h
28   */
29  public class Ean13 extends AbstractBarcodeStrategy implements java.io.Serializable {
30      
31      private static CharacterCode[] codes = {
32          // Left side A values and right side C values
33          new CharacterCode('0', new byte[] {3,2,1,1}, 0),
34          new CharacterCode('1', new byte[] {2,2,2,1}, 1),
35          new CharacterCode('2', new byte[] {2,1,2,2}, 2),
36          new CharacterCode('3', new byte[] {1,4,1,1}, 3),
37          new CharacterCode('4', new byte[] {1,1,3,2}, 4),
38          new CharacterCode('5', new byte[] {1,2,3,1}, 5),
39          new CharacterCode('6', new byte[] {1,1,1,4}, 6),
40          new CharacterCode('7', new byte[] {1,3,1,2}, 7),
41          new CharacterCode('8', new byte[] {1,2,1,3}, 8),
42          new CharacterCode('9', new byte[] {3,1,1,2}, 9),
43          // Left side B values
44          new CharacterCode('a', new byte[] {1,1,2,3}, 0),
45          new CharacterCode('b', new byte[] {1,2,2,2}, 1),
46          new CharacterCode('c', new byte[] {2,2,1,2}, 2),
47          new CharacterCode('d', new byte[] {1,1,4,1}, 3),
48          new CharacterCode('e', new byte[] {2,3,1,1}, 4),
49          new CharacterCode('f', new byte[] {1,3,2,1}, 5),
50          new CharacterCode('g', new byte[] {4,1,1,1}, 6),
51          new CharacterCode('h', new byte[] {2,1,3,1}, 7),
52          new CharacterCode('i', new byte[] {3,1,2,1}, 8),
53          new CharacterCode('j', new byte[] {2,1,1,3}, 9),
54          
55          new CharacterCode('A', new byte[] {1,1,1},     -1),     // Start
56          new CharacterCode('B', new byte[] {1,1,1},     -1),     // Stop
57          new CharacterCode('C', new byte[] {1,1,1,1,1}, -1)      // Center
58      };
59      
60      private static char[] bPattern = {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'};
61      
62      protected String checkSum;
63      
64      public int requiresChecksum() {
65          return MANDATORY_CHECKSUM;
66      }
67      
68      protected CharacterCode[] getCodes() {
69          return codes;
70      }
71      
72      // Compute checksum and store it locally.
73      protected void computeChecksum(String text, int len) {
74          int even = 0;
75          int odd = 0;
76          int tot;
77          
78          checkSum = "";
79          
80          if (text.length() == len) {
81              
82              for (int i=len-1; i>=0; i-=2) {
83                  even += Integer.parseInt(text.substring(i, i+1));
84                  if (i <= 0) break;
85                  odd += Integer.parseInt(text.substring(i-1, i));
86              }
87              even *= 3;
88              tot = even + odd;
89              even = tot/10;
90              odd = tot%10;
91              if (odd != 0) even++;
92              
93              checkSum = new Integer(even*10 - tot).toString();
94          }
95      }
96      
97      protected String augmentWithChecksum(String text) throws BarcodeException {
98          // Checksum has been computed before inserting B codes and center bars
99          return text + checkSum;
100     }
101     
102     protected String postprocess(String text) {
103         return text;
104     }
105     
106     /*
107       There are 3 representations of digits in a EAN/UPC symbol: A, B, and C
108       A or B representations are used for the 6 left digits, while C
109       representations are used on the 6 right digits. The C representation is the 
110       opposite of A representations: just exchange white anf black bars. This is
111       done automatically, thanks to the insertion of the center bars code (odd number of bars)
112       which reverses the process: the first module in left-side digits is a space, but it is
113       a bar in right-side digits... Therefore we can use the same 'CharacterCode' for left
114       side 'A's and right side 'C's.
115       The combinations of A and B representations in the left side determines the
116       system digit (SD): this digit, which is the first in the symbol, is not encoded
117       as bar / spaces.
118       The following table list the possible layout of A and B codes in the left
119       part of symbol and the coresponding SD:
120       
121       Layout               --> SD
122       A  A  A  A  A  A         0
123       A  A  B  A  B  B         1
124       A  A  B  B  A  B         2
125       A  A  B  B  B  A         3
126       A  B  A  A  B  B         4
127       A  B  B  A  A  B         5
128       A  B  B  B  A  A         6
129       A  B  A  B  A  B         7
130       A  B  A  B  B  A         8
131       A  B  B  A  B  A         9
132      
133      */
134     protected String preprocess(String text) {
135         if (text.length() < 12) return text;
136         text = text.substring(0, 12);
137         
138         computeChecksum(text, 12);
139         char[] t = (text.substring(1, 7) + "C" + text.substring(7)).toCharArray();
140         switch (text.charAt(0)) {
141             case '0':
142                 // A A A A A A
143                 break;
144             case '1':
145                 // A A B A B B
146                 t[2] = bPattern[getCharacterCode(t[2]).check];
147                 t[4] = bPattern[getCharacterCode(t[4]).check];
148                 t[5] = bPattern[getCharacterCode(t[5]).check];
149                 break;
150             case '2':
151                 // A A B B A B
152                 t[2] = bPattern[getCharacterCode(t[2]).check];
153                 t[3] = bPattern[getCharacterCode(t[3]).check];
154                 t[5] = bPattern[getCharacterCode(t[5]).check];
155                 break;
156             case '3':
157                 // A A B B B A
158                 t[2] = bPattern[getCharacterCode(t[2]).check];
159                 t[3] = bPattern[getCharacterCode(t[3]).check];
160                 t[4] = bPattern[getCharacterCode(t[4]).check];
161                 break;
162             case '4':
163                 // A B A A B B
164                 t[1] = bPattern[getCharacterCode(t[1]).check];
165                 t[4] = bPattern[getCharacterCode(t[4]).check];
166                 t[5] = bPattern[getCharacterCode(t[5]).check];
167                 break;
168             case '5':
169                 // A B B A A B
170                 t[1] = bPattern[getCharacterCode(t[1]).check];
171                 t[2] = bPattern[getCharacterCode(t[2]).check];
172                 t[5] = bPattern[getCharacterCode(t[5]).check];
173                 break;
174             case '6':
175                 // A B B B A A
176                 t[1] = bPattern[getCharacterCode(t[1]).check];
177                 t[2] = bPattern[getCharacterCode(t[2]).check];
178                 t[3] = bPattern[getCharacterCode(t[3]).check];
179                 break;
180             case '7':
181                 // A B A B A B
182                 t[1] = bPattern[getCharacterCode(t[1]).check];
183                 t[3] = bPattern[getCharacterCode(t[3]).check];
184                 t[5] = bPattern[getCharacterCode(t[5]).check];
185                 break;
186             case '8':
187                 // A B A B B A
188                 t[1] = bPattern[getCharacterCode(t[1]).check];
189                 t[3] = bPattern[getCharacterCode(t[3]).check];
190                 t[4] = bPattern[getCharacterCode(t[4]).check];
191                 break;
192             case '9':
193                 // A B B A B A
194                 t[1] = bPattern[getCharacterCode(t[1]).check];
195                 t[2] = bPattern[getCharacterCode(t[2]).check];
196                 t[4] = bPattern[getCharacterCode(t[4]).check];
197                 break;
198         }
199         return new String(t);
200     }
201     
202     protected boolean isInterleaved() {
203         return false;
204     }
205     
206     protected char getStartSentinel() {
207         return 'A';
208     }
209     
210     protected char getStopSentinel() {
211         return 'B';
212     }
213     
214     /**
215      * Always returns 11 (eleven).
216      */
217     protected byte getMarginWidth() {
218         return 11;
219     }
220     
221     protected String getBarcodeLabelText(String text) {
222         if (text.length() < 12) return text;
223         return text.substring(0, 12) + checkSum;
224     }
225     
226 }