Major refactoring of 1D barcode code. Moved into com.google.zxing.oned package. Misc...
[zxing.git] / core / src / com / google / zxing / oned / EAN13Reader.java
1 /*
2  * Copyright 2008 Google Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 package com.google.zxing.oned;
18
19 import com.google.zxing.ReaderException;
20 import com.google.zxing.common.BitArray;
21
22 /**
23  * <p>Implements decoding of the EAN-13 format.</p>
24  *
25  * @author dswitkin@google.com (Daniel Switkin)
26  * @author srowen@google.com (Sean Owen)
27  * @author alasdair@google.com (Alasdair Mackintosh)
28  */
29 public final class EAN13Reader extends AbstractUPCEANReader {
30
31   // For an EAN-13 barcode, the first digit is represented by the parities used
32   // to encode the next six digits, according to the table below. For example,
33   // if the barcode is 5 123456 789012 then the value of the first digit is
34   // signified by using odd for '1', even for '2', even for '3', odd for '4',
35   // odd for '5', and even for '6'. See http://en.wikipedia.org/wiki/EAN-13
36   //
37   //                Parity of next 6 digits
38   //    Digit   0     1     2     3     4     5
39   //       0    Odd   Odd   Odd   Odd   Odd   Odd
40   //       1    Odd   Odd   Even  Odd   Even  Even
41   //       2    Odd   Odd   Even  Even  Odd   Even
42   //       3    Odd   Odd   Even  Even  Even  Odd
43   //       4    Odd   Even  Odd   Odd   Even  Even
44   //       5    Odd   Even  Even  Odd   Odd   Even
45   //       6    Odd   Even  Even  Even  Odd   Odd
46   //       7    Odd   Even  Odd   Even  Odd   Even
47   //       8    Odd   Even  Odd   Even  Even  Odd
48   //       9    Odd   Even  Even  Odd   Even  Odd
49   //
50   // Note that the encoding for '0' uses the same parity as a UPC barcode. Hence
51   // a UPC barcode can be converted to an EAN-13 barcode by prepending a 0.
52   //
53   // The encodong is represented by the following array, which is a bit pattern
54   // using Odd = 0 and Even = 1. For example, 5 is represented by:
55   //
56   //              Odd Even Even Odd Odd Even
57   // in binary:
58   //                0    1    1   0   0    1   == 0x19
59   //
60   private static final int[] FIRST_DIGIT_ENCODINGS = {
61       0x00, 0x0B, 0x0D, 0xE, 0x13, 0x19, 0x1C, 0x15, 0x16, 0x1A
62   };
63
64   protected int decodeMiddle(BitArray row, int[] startRange, StringBuffer resultString) throws ReaderException {
65
66     int[] counters = new int[4];
67     int end = row.getSize();
68     int rowOffset = startRange[1];
69
70     int lgPatternFound = 0;
71
72     for (int x = 0; x < 6 && rowOffset < end; x++) {
73       int bestMatch = decodeDigit(row, counters, rowOffset, L_AND_G_PATTERNS);
74       resultString.append((char) ('0' + bestMatch % 10));
75       for (int i = 0; i < counters.length; i++) {
76         rowOffset += counters[i];
77       }
78       if (bestMatch >= 10) {
79         lgPatternFound |= 1 << (5 - x);
80       }
81     }
82
83     determineFirstDigit(resultString, lgPatternFound);
84
85     int[] middleRange = findGuardPattern(row, rowOffset, true, MIDDLE_PATTERN);
86     rowOffset = middleRange[1];
87
88     for (int x = 0; x < 6 && rowOffset < end; x++) {
89       int bestMatch = decodeDigit(row, counters, rowOffset, L_PATTERNS);
90       resultString.append((char) ('0' + bestMatch));
91       for (int i = 0; i < counters.length; i++) {
92         rowOffset += counters[i];
93       }
94     }
95
96     return rowOffset;
97   }
98
99   /**
100    * Based on pattern of odd-even ('L' and 'G') patterns used to encoded the explicitly-encoded digits
101    * in a barcode, determines the implicitly encoded first digit and adds it to the result string.
102    *
103    * @param resultString string to insert decoded first digit into
104    * @param lgPatternFound int whose bits indicates the pattern of odd/even L/G patterns used to
105    *  encode digits
106    * @throws ReaderException if first digit cannot be determined
107    */
108   private static void determineFirstDigit(StringBuffer resultString, int lgPatternFound) throws ReaderException {
109     for (int d = 0; d < 10; d++) {
110       if (lgPatternFound == FIRST_DIGIT_ENCODINGS[d]) {
111         // OK, if the first digit is a 0, then this is effectively also a UPC-A code.
112         // I think it's best (?) to go ahead and treat it as if it had matched as UPC-A, and return a result
113         // *without* the leading 0
114         if (d != 0) {
115           resultString.insert(0, (char) ('0' + d));
116         }
117         return;
118       }
119     }
120     throw new ReaderException("Unable to determine first digit");
121   }
122
123 }