133bd47636e614e08f7601bddf57c5b987ce4be7
[zxing.git] / cpp / core / src / zxing / oned / UPCEANReader.cpp
1 /*
2  *  UPCEANReader.cpp
3  *  ZXing
4  *
5  *  Created by Lukasz Warchol on 10-01-21.
6  *  Copyright 2010 ZXing authors All rights reserved.
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  *      http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  */
20
21 #include "UPCEANReader.h"
22 #include <zxing/oned/OneDResultPoint.h>
23 #include <zxing/ReaderException.h>
24 namespace zxing {
25   namespace oned {
26     
27     /**
28      * Start/end guard pattern.
29      */
30     static const int START_END_PATTERN[3] = {1, 1, 1};
31     
32     /**
33      * Pattern marking the middle of a UPC/EAN pattern, separating the two halves.
34      */
35     static const int MIDDLE_PATTERN_LEN = 5;
36     static const int MIDDLE_PATTERN[MIDDLE_PATTERN_LEN] = {1, 1, 1, 1, 1};
37     
38     /**
39      * "Odd", or "L" patterns used to encode UPC/EAN digits.
40      */
41     const int L_PATTERNS_LEN = 10;
42     const int L_PATTERNS_SUB_LEN = 4;
43     const int L_PATTERNS[10][4] = {
44       {3, 2, 1, 1}, // 0
45       {2, 2, 2, 1}, // 1
46       {2, 1, 2, 2}, // 2
47       {1, 4, 1, 1}, // 3
48       {1, 1, 3, 2}, // 4
49       {1, 2, 3, 1}, // 5
50       {1, 1, 1, 4}, // 6
51       {1, 3, 1, 2}, // 7
52       {1, 2, 1, 3}, // 8
53       {3, 1, 1, 2}  // 9
54     };
55     
56     /**
57      * As above but also including the "even", or "G" patterns used to encode UPC/EAN digits.
58      */
59     const int L_AND_G_PATTERNS_LEN = 20;
60     const int L_AND_G_PATTERNS_SUB_LEN = 4;
61     const int L_AND_G_PATTERNS[L_AND_G_PATTERNS_LEN][L_AND_G_PATTERNS_SUB_LEN] = {
62       {3, 2, 1, 1}, // 0
63       {2, 2, 2, 1}, // 1
64       {2, 1, 2, 2}, // 2
65       {1, 4, 1, 1}, // 3
66       {1, 1, 3, 2}, // 4
67       {1, 2, 3, 1}, // 5
68       {1, 1, 1, 4}, // 6
69       {1, 3, 1, 2}, // 7
70       {1, 2, 1, 3}, // 8
71       {3, 1, 1, 2}, // 9
72       {1, 1, 2, 3}, // 10 reversed 0
73       {1, 2, 2, 2}, // 11 reversed 1
74       {2, 2, 1, 2}, // 12 reversed 2
75       {1, 1, 4, 1}, // 13 reversed 3
76       {2, 3, 1, 1}, // 14 reversed 4
77       {1, 3, 2, 1}, // 15 reversed 5
78       {4, 1, 1, 1}, // 16 reversed 6
79       {2, 1, 3, 1}, // 17 reversed 7
80       {3, 1, 2, 1}, // 18 reversed 8
81       {2, 1, 1, 3}  // 19 reversed 9
82     };
83     
84
85     const int UPCEANReader::getMIDDLE_PATTERN_LEN(){
86       return MIDDLE_PATTERN_LEN;
87     }
88     const int* UPCEANReader::getMIDDLE_PATTERN(){
89       return MIDDLE_PATTERN;
90     }
91     
92     UPCEANReader::UPCEANReader(){
93     }
94     
95     
96     Ref<Result> UPCEANReader::decodeRow(int rowNumber, Ref<BitArray> row) {
97                         int* start = NULL;
98                         try {
99                                 start = findStartGuardPattern(row);
100                                 Ref<Result> result = decodeRow(rowNumber, row, start);
101                                 delete [] start;
102                                 return result;
103                         } catch (ReaderException const& re) {
104                                 delete [] start;
105                                 throw re;
106                         }
107     }
108     
109     Ref<Result> UPCEANReader::decodeRow(int rowNumber, Ref<BitArray> row, int startGuardRange[]){
110       int* endRange = NULL;
111       try {
112                                 std::string tmpResultString;
113         std::string& tmpResultStringRef = tmpResultString;
114         int endStart;
115         endStart = decodeMiddle(row, startGuardRange, 2 /*reference findGuardPattern*/ , tmpResultStringRef);
116       
117         endRange = decodeEnd(row, endStart);
118                         
119         // Make sure there is a quiet zone at least as big as the end pattern after the barcode. The
120         // spec might want more whitespace, but in practice this is the maximum we can count on.
121         size_t end = endRange[1];
122         size_t quietEnd = end + (end - endRange[0]);
123         if (quietEnd >= row->getSize() || !row->isRange(end, quietEnd, false)) {
124           throw ReaderException("Quiet zone asserrt fail.");
125         }
126
127         if (!checkChecksum(tmpResultString)) {
128           throw ReaderException("Checksum fail.");
129         }
130       
131         Ref<String> resultString(new String(tmpResultString));
132       
133         float left = (float) (startGuardRange[1] + startGuardRange[0]) / 2.0f;
134         float right = (float) (endRange[1] + endRange[0]) / 2.0f;
135       
136         std::vector< Ref<ResultPoint> > resultPoints(2);
137         Ref<OneDResultPoint> resultPoint1(new OneDResultPoint(left, (float) rowNumber));
138         Ref<OneDResultPoint> resultPoint2(new OneDResultPoint(right, (float) rowNumber));
139         resultPoints[0] = resultPoint1;
140         resultPoints[1] = resultPoint2;
141       
142         ArrayRef<unsigned char> resultBytes(1);
143       
144         Ref<Result> res(new Result(resultString, resultBytes, resultPoints, getBarcodeFormat()));
145         delete [] endRange;
146         return res;
147       } catch (ReaderException const& re) {
148         delete [] endRange;
149                                 throw re;
150                         }
151
152     }
153     
154     int* UPCEANReader::findStartGuardPattern(Ref<BitArray> row){
155       bool foundStart = false;
156       
157       int* startRange = NULL;
158       int nextStart = 0;
159       try {
160         while (!foundStart) {
161           delete [] startRange;
162           startRange = NULL;
163           startRange = findGuardPattern(row, nextStart, false, START_END_PATTERN, sizeof(START_END_PATTERN)/sizeof(int));
164           int start = startRange[0];
165           nextStart = startRange[1];
166           // Make sure there is a quiet zone at least as big as the start pattern before the barcode.
167           // If this check would run off the left edge of the image, do not accept this barcode,
168           // as it is very likely to be a false positive.
169           int quietStart = start - (nextStart - start);
170           if (quietStart >= 0) {
171             foundStart = row->isRange(quietStart, start, false);
172           }
173         }
174         return startRange;
175       } catch (ReaderException const& re) {
176         delete [] startRange;
177         throw re;
178       }
179     }
180     
181     // TODO(flyashi): Return a pair<int, int> for return value to avoid using the heap.
182     int* UPCEANReader::findGuardPattern(Ref<BitArray> row, int rowOffset, bool whiteFirst, const int pattern[], int patternLen){
183       int patternLength = patternLen;
184       int counters[patternLength];
185       int countersCount = sizeof(counters) / sizeof(int);
186       for (int i = 0; i < countersCount; i++) {
187         counters[i] = 0;
188       }
189       int width = row->getSize();
190       bool isWhite = false;
191       while (rowOffset < width) {
192         isWhite = !row->get(rowOffset);
193         if (whiteFirst == isWhite) {
194           break;
195         }
196         rowOffset++;
197       }
198       
199       int counterPosition = 0;
200       int patternStart = rowOffset;
201       for (int x = rowOffset; x < width; x++) {
202         bool pixel = row->get(x);
203         if (pixel ^ isWhite) {
204           counters[counterPosition]++;
205         } else {
206           if (counterPosition == patternLength - 1) {
207             if (patternMatchVariance(counters, countersCount, pattern, MAX_INDIVIDUAL_VARIANCE) < MAX_AVG_VARIANCE) {
208               int* resultValue = new int[2];
209               resultValue[0] = patternStart;
210               resultValue[1] = x;
211               return resultValue;
212             }
213             patternStart += counters[0] + counters[1];
214             for (int y = 2; y < patternLength; y++) {
215               counters[y - 2] = counters[y];
216             }
217             counters[patternLength - 2] = 0;
218             counters[patternLength - 1] = 0;
219             counterPosition--;
220           } else {
221             counterPosition++;
222           }
223           counters[counterPosition] = 1;
224           isWhite = !isWhite;
225         }
226       }
227       throw ReaderException("findGuardPattern");
228     }
229     
230     int* UPCEANReader::decodeEnd(Ref<BitArray> row, int endStart){
231       return findGuardPattern(row, endStart, false, START_END_PATTERN, sizeof(START_END_PATTERN)/sizeof(int));
232     }
233     
234 //    int UPCEANReader::decodeDigit(Ref<BitArray> row, int counters[], int countersLen, int rowOffset, int** patterns/*[][]*/, int paterns1Len, int paterns2Len)    
235     int UPCEANReader::decodeDigit(Ref<BitArray> row, int counters[], int countersLen, int rowOffset, UPC_EAN_PATTERNS patternType){
236       recordPattern(row, rowOffset, counters, countersLen);
237       unsigned int bestVariance = MAX_AVG_VARIANCE; // worst variance we'll accept
238       int bestMatch = -1;
239       
240       int max = 0;
241       switch (patternType) {
242         case UPC_EAN_PATTERNS_L_PATTERNS:
243           max = L_PATTERNS_LEN;
244           for (int i = 0; i < max; i++) {
245             int pattern[countersLen];
246             for(int j = 0; j< countersLen; j++){
247               pattern[j] = L_PATTERNS[i][j];
248             }
249             
250             unsigned int variance = patternMatchVariance(counters, countersLen, pattern, MAX_INDIVIDUAL_VARIANCE);
251             if (variance < bestVariance) {
252               bestVariance = variance;
253               bestMatch = i;
254             }
255           }
256           break;
257         case UPC_EAN_PATTERNS_L_AND_G_PATTERNS:
258           max = L_AND_G_PATTERNS_LEN;
259           for (int i = 0; i < max; i++) {
260             int pattern[countersLen];
261             for(int j = 0; j< countersLen; j++){
262               pattern[j] = L_AND_G_PATTERNS[i][j];
263             }
264             
265             unsigned int variance = patternMatchVariance(counters, countersLen, pattern, MAX_INDIVIDUAL_VARIANCE);
266             if (variance < bestVariance) {
267               bestVariance = variance;
268               bestMatch = i;
269             }
270           }
271           break;
272         default:
273           break;
274       }
275       if (bestMatch >= 0) {
276         return bestMatch;
277       } else {
278         throw ReaderException("UPCEANReader::decodeDigit: No best mach");
279       }
280     }
281     
282     
283     /**
284      * @return {@link #checkStandardUPCEANChecksum(String)}
285      */
286     bool UPCEANReader::checkChecksum(std::string s){
287       return checkStandardUPCEANChecksum(s);
288     }
289     
290     /**
291      * Computes the UPC/EAN checksum on a string of digits, and reports
292      * whether the checksum is correct or not.
293      *
294      * @param s string of digits to check
295      * @return true iff string of digits passes the UPC/EAN checksum algorithm
296      * @throws ReaderException if the string does not contain only digits
297      */
298     bool UPCEANReader::checkStandardUPCEANChecksum(std::string s){
299       int length = s.length();
300       if (length == 0) {
301         return false;
302       }
303       
304       int sum = 0;
305       for (int i = length - 2; i >= 0; i -= 2) {
306         int digit = (int) s[i] - (int) '0';
307         if (digit < 0 || digit > 9) {
308           throw ReaderException("checkStandardUPCEANChecksum");
309         }
310         sum += digit;
311       }
312       sum *= 3;
313       for (int i = length - 1; i >= 0; i -= 2) {
314         int digit = (int) s[i] - (int) '0';
315         if (digit < 0 || digit > 9) {
316           throw ReaderException("checkStandardUPCEANChecksum");
317         }
318         sum += digit;
319       }
320       return sum % 10 == 0;
321     }
322     UPCEANReader::~UPCEANReader(){
323     }
324   }
325 }