Issue 198
[zxing.git] / core / src / com / google / zxing / oned / EAN13Reader.java
1 /*
2  * Copyright 2008 ZXing authors
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.BarcodeFormat;
21 import com.google.zxing.common.BitArray;
22
23 /**
24  * <p>Implements decoding of the EAN-13 format.</p>
25  *
26  * @author dswitkin@google.com (Daniel Switkin)
27  * @author Sean Owen
28  * @author alasdair@google.com (Alasdair Mackintosh)
29  */
30 public final class EAN13Reader extends AbstractUPCEANReader {
31
32   // For an EAN-13 barcode, the first digit is represented by the parities used
33   // to encode the next six digits, according to the table below. For example,
34   // if the barcode is 5 123456 789012 then the value of the first digit is
35   // signified by using odd for '1', even for '2', even for '3', odd for '4',
36   // odd for '5', and even for '6'. See http://en.wikipedia.org/wiki/EAN-13
37   //
38   //                Parity of next 6 digits
39   //    Digit   0     1     2     3     4     5
40   //       0    Odd   Odd   Odd   Odd   Odd   Odd
41   //       1    Odd   Odd   Even  Odd   Even  Even
42   //       2    Odd   Odd   Even  Even  Odd   Even
43   //       3    Odd   Odd   Even  Even  Even  Odd
44   //       4    Odd   Even  Odd   Odd   Even  Even
45   //       5    Odd   Even  Even  Odd   Odd   Even
46   //       6    Odd   Even  Even  Even  Odd   Odd
47   //       7    Odd   Even  Odd   Even  Odd   Even
48   //       8    Odd   Even  Odd   Even  Even  Odd
49   //       9    Odd   Even  Even  Odd   Even  Odd
50   //
51   // Note that the encoding for '0' uses the same parity as a UPC barcode. Hence
52   // a UPC barcode can be converted to an EAN-13 barcode by prepending a 0.
53   //
54   // The encoding is represented by the following array, which is a bit pattern
55   // using Odd = 0 and Even = 1. For example, 5 is represented by:
56   //
57   //              Odd Even Even Odd Odd Even
58   // in binary:
59   //                0    1    1   0   0    1   == 0x19
60   //
61   public static final int[] FIRST_DIGIT_ENCODINGS = {
62       0x00, 0x0B, 0x0D, 0xE, 0x13, 0x19, 0x1C, 0x15, 0x16, 0x1A
63   };
64
65   private final int[] decodeMiddleCounters;
66
67   public EAN13Reader() {
68     decodeMiddleCounters = new int[4];
69   }
70
71   protected int decodeMiddle(BitArray row, int[] startRange, StringBuffer resultString) throws ReaderException {
72     int[] counters = decodeMiddleCounters;
73     counters[0] = 0;
74     counters[1] = 0;
75     counters[2] = 0;
76     counters[3] = 0;
77     int end = row.getSize();
78     int rowOffset = startRange[1];
79
80     int lgPatternFound = 0;
81
82     for (int x = 0; x < 6 && rowOffset < end; x++) {
83       int bestMatch = decodeDigit(row, counters, rowOffset, L_AND_G_PATTERNS);
84       resultString.append((char) ('0' + bestMatch % 10));
85       for (int i = 0; i < counters.length; i++) {
86         rowOffset += counters[i];
87       }
88       if (bestMatch >= 10) {
89         lgPatternFound |= 1 << (5 - x);
90       }
91     }
92
93     determineFirstDigit(resultString, lgPatternFound);
94
95     int[] middleRange = findGuardPattern(row, rowOffset, true, MIDDLE_PATTERN);
96     rowOffset = middleRange[1];
97
98     for (int x = 0; x < 6 && rowOffset < end; x++) {
99       int bestMatch = decodeDigit(row, counters, rowOffset, L_PATTERNS);
100       resultString.append((char) ('0' + bestMatch));
101       for (int i = 0; i < counters.length; i++) {
102         rowOffset += counters[i];
103       }
104     }
105
106     return rowOffset;
107   }
108
109   BarcodeFormat getBarcodeFormat() {
110     return BarcodeFormat.EAN_13;
111   }
112
113   /**
114    * Based on pattern of odd-even ('L' and 'G') patterns used to encoded the explicitly-encoded digits
115    * in a barcode, determines the implicitly encoded first digit and adds it to the result string.
116    *
117    * @param resultString string to insert decoded first digit into
118    * @param lgPatternFound int whose bits indicates the pattern of odd/even L/G patterns used to
119    * encode digits
120    * @throws ReaderException if first digit cannot be determined
121    */
122   private static void determineFirstDigit(StringBuffer resultString, int lgPatternFound) throws ReaderException {
123     for (int d = 0; d < 10; d++) {
124       if (lgPatternFound == FIRST_DIGIT_ENCODINGS[d]) {
125         resultString.insert(0, (char) ('0' + d));
126         return;
127       }
128     }
129     throw ReaderException.getInstance();
130   }
131
132 }