Small style stuff
[zxing.git] / symbian / QQrDecoder / 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                         return decodeRow(rowNumber, row, findStartGuardPattern(row));
98                 }
99                 Ref<Result> UPCEANReader::decodeRow(int rowNumber, Ref<BitArray> row, int startGuardRange[]){
100                         
101                         std::string tmpResultString;
102                         std::string& tmpResultStringRef = tmpResultString;
103                         int endStart;
104                         try {
105                                 endStart = decodeMiddle(row, startGuardRange, 2 /*reference findGuardPattern*/ , tmpResultStringRef);
106                         } catch (ReaderException re) {
107                                 if (startGuardRange!=NULL) {
108                                         delete [] startGuardRange;
109                                         startGuardRange = NULL;
110                                 }
111                                 throw re;
112                         }
113                         
114                         int* endRange = decodeEnd(row, endStart);
115                                                 
116 #pragma mark QuietZone needs some change
117                         // Make sure there is a quiet zone at least as big as the end pattern after the barcode. The
118                         // spec might want more whitespace, but in practice this is the maximum we can count on.
119 //                      int end = endRange[1];
120 //                      int quietEnd = end + (end - endRange[0]);
121 //                      if (quietEnd >= row->getSize() || !row->isRange(end, quietEnd, false)) {
122 //                              throw ReaderException("Quiet zone asserrt fail.");
123 //                      }
124                         
125                         if (!checkChecksum(tmpResultString)) {
126                                 if (startGuardRange!=NULL) {
127                                         delete [] startGuardRange;
128                                         startGuardRange = NULL;
129                                 }
130                                 if (endRange!=NULL) {
131                                         delete [] endRange;
132                                         endRange = NULL;
133                                 }
134                                 throw ReaderException("Checksum fail.");
135                         }
136                         
137                         Ref<String> resultString(new String(tmpResultString));
138                         
139                         float left = (float) (startGuardRange[1] + startGuardRange[0]) / 2.0f;
140                         float right = (float) (endRange[1] + endRange[0]) / 2.0f;
141                         
142                         std::vector< Ref<ResultPoint> > resultPoints(2);
143                         Ref<OneDResultPoint> resultPoint1(new OneDResultPoint(left, (float) rowNumber));
144                         Ref<OneDResultPoint> resultPoint2(new OneDResultPoint(right, (float) rowNumber));
145                         resultPoints[0] = resultPoint1;
146                         resultPoints[1] = resultPoint2;
147                         
148                         ArrayRef<unsigned char> resultBytes(1);
149                         
150                         if (startGuardRange!=NULL) {
151                                 delete [] startGuardRange;
152                                 startGuardRange = NULL;
153                         }
154                         if (endRange!=NULL) {
155                                 delete [] endRange;
156                                 endRange = NULL;
157                         }
158                         
159                         Ref<Result> res(new Result(resultString, resultBytes, resultPoints, getBarcodeFormat()));
160                         return res;
161                 }
162                 
163                 int* UPCEANReader::findStartGuardPattern(Ref<BitArray> row){
164                         bool foundStart = false;
165                         
166                         int* startRange = NULL;
167                         int nextStart = 0;
168                         while (!foundStart) {
169                                 startRange = findGuardPattern(row, nextStart, false, START_END_PATTERN, sizeof(START_END_PATTERN)/sizeof(int));
170                                 int start = startRange[0];
171                                 nextStart = startRange[1];
172                                 // Make sure there is a quiet zone at least as big as the start pattern before the barcode.
173                                 // If this check would run off the left edge of the image, do not accept this barcode,
174                                 // as it is very likely to be a false positive.
175                                 int quietStart = start - (nextStart - start);
176                                 if (quietStart >= 0) {
177                                         foundStart = row->isRange(quietStart, start, false);
178                                 }
179                                 if (!foundStart) {
180                                         delete [] startRange;
181                                 }
182                         }
183                         return startRange;
184                 }
185                 
186                 int* UPCEANReader::findGuardPattern(Ref<BitArray> row, int rowOffset, bool whiteFirst, const int pattern[], int patternLen){
187                         int patternLength = patternLen;
188                         
189                         int counters[patternLength];
190                         int countersCount = sizeof(counters)/sizeof(int);
191                         for (int i=0; i<countersCount ; i++) {
192                                 counters[i]=0;
193                         }
194                         int width = row->getSize();
195                         bool isWhite = false;
196                         while (rowOffset < width) {
197                                 isWhite = !row->get(rowOffset);
198                                 if (whiteFirst == isWhite) {
199                                         break;
200                                 }
201                                 rowOffset++;
202                         }
203                         
204                         int counterPosition = 0;
205                         int patternStart = rowOffset;
206                         for (int x = rowOffset; x < width; x++) {
207                                 bool pixel = row->get(x);
208                                 if (pixel ^ isWhite) {
209                                         counters[counterPosition]++;
210                                 } else {
211                                         if (counterPosition == patternLength - 1) {
212                                                 if (patternMatchVariance(counters, countersCount, pattern, MAX_INDIVIDUAL_VARIANCE) < MAX_AVG_VARIANCE) {
213                                                         int* resultValue = new int[2];
214                                                         resultValue[0] = patternStart;
215                                                         resultValue[1] = x;
216                                                         return resultValue;
217                                                 }
218                                                 patternStart += counters[0] + counters[1];
219                                                 for (int y = 2; y < patternLength; y++) {
220                                                         counters[y - 2] = counters[y];
221                                                 }
222                                                 counters[patternLength - 2] = 0;
223                                                 counters[patternLength - 1] = 0;
224                                                 counterPosition--;
225                                         } else {
226                                                 counterPosition++;
227                                         }
228                                         counters[counterPosition] = 1;
229                                         isWhite = !isWhite;
230                                 }
231                         }
232                         throw ReaderException("findGuardPattern");
233                 }
234                 
235                 int* UPCEANReader::decodeEnd(Ref<BitArray> row, int endStart){
236                         return findGuardPattern(row, endStart, false, START_END_PATTERN, sizeof(START_END_PATTERN)/sizeof(int));
237                 }
238                 
239 //              int UPCEANReader::decodeDigit(Ref<BitArray> row, int counters[], int countersLen, int rowOffset, int** patterns/*[][]*/, int paterns1Len, int paterns2Len)              
240                 int UPCEANReader::decodeDigit(Ref<BitArray> row, int counters[], int countersLen, int rowOffset, UPC_EAN_PATTERNS patternType){
241                         recordPattern(row, rowOffset, counters, countersLen);
242                         unsigned int bestVariance = MAX_AVG_VARIANCE; // worst variance we'll accept
243                         int bestMatch = -1;
244                         
245                         int max = 0;
246                         switch (patternType) {
247                                 case UPC_EAN_PATTERNS_L_PATTERNS:
248                                         max = L_PATTERNS_LEN;
249                                         for (int i = 0; i < max; i++) {
250                                                 int pattern[countersLen];
251                                                 for(int j = 0; j< countersLen; j++){
252                                                         pattern[j] = L_PATTERNS[i][j];
253                                                 }
254                                                 
255                                                 unsigned int variance = patternMatchVariance(counters, countersLen, pattern, MAX_INDIVIDUAL_VARIANCE);
256                                                 if (variance < bestVariance) {
257                                                         bestVariance = variance;
258                                                         bestMatch = i;
259                                                 }
260                                         }
261                                         break;
262                                 case UPC_EAN_PATTERNS_L_AND_G_PATTERNS:
263                                         max = L_AND_G_PATTERNS_LEN;
264                                         for (int i = 0; i < max; i++) {
265                                                 int pattern[countersLen];
266                                                 for(int j = 0; j< countersLen; j++){
267                                                         pattern[j] = L_AND_G_PATTERNS[i][j];
268                                                 }
269                                                 
270                                                 unsigned int variance = patternMatchVariance(counters, countersLen, pattern, MAX_INDIVIDUAL_VARIANCE);
271                                                 if (variance < bestVariance) {
272                                                         bestVariance = variance;
273                                                         bestMatch = i;
274                                                 }
275                                         }
276                                         break;
277                                 default:
278                                         break;
279                         }
280                         if (bestMatch >= 0) {
281                                 return bestMatch;
282                         } else {
283                                 throw ReaderException("UPCEANReader::decodeDigit: No best mach");
284                         }
285                 }
286                 
287                 
288                 /**
289                  * @return {@link #checkStandardUPCEANChecksum(String)}
290                  */
291                 bool UPCEANReader::checkChecksum(std::string s){
292                         return checkStandardUPCEANChecksum(s);
293                 }
294                 
295                 /**
296                  * Computes the UPC/EAN checksum on a string of digits, and reports
297                  * whether the checksum is correct or not.
298                  *
299                  * @param s string of digits to check
300                  * @return true iff string of digits passes the UPC/EAN checksum algorithm
301                  * @throws ReaderException if the string does not contain only digits
302                  */
303                 bool UPCEANReader::checkStandardUPCEANChecksum(std::string s){
304                         int length = s.length();
305                         if (length == 0) {
306                                 return false;
307                         }
308                         
309                         int sum = 0;
310                         for (int i = length - 2; i >= 0; i -= 2) {
311                                 int digit = (int) s[i] - (int) '0';
312                                 if (digit < 0 || digit > 9) {
313                                         throw ReaderException("checkStandardUPCEANChecksum");
314                                 }
315                                 sum += digit;
316                         }
317                         sum *= 3;
318                         for (int i = length - 1; i >= 0; i -= 2) {
319                                 int digit = (int) s[i] - (int) '0';
320                                 if (digit < 0 || digit > 9) {
321                                         throw ReaderException("checkStandardUPCEANChecksum");
322                                 }
323                                 sum += digit;
324                         }
325                         return sum % 10 == 0;
326                 }
327                 UPCEANReader::~UPCEANReader(){
328                 }
329         }
330 }