5 * Created by Lukasz Warchol on 10-01-21.
6 * Copyright 2010 ZXing authors All rights reserved.
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
12 * http://www.apache.org/licenses/LICENSE-2.0
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.
21 #include "UPCEANReader.h"
22 #include <zxing/oned/OneDResultPoint.h>
23 #include <zxing/ReaderException.h>
28 * Start/end guard pattern.
30 static const int START_END_PATTERN[3] = {1, 1, 1};
33 * Pattern marking the middle of a UPC/EAN pattern, separating the two halves.
35 static const int MIDDLE_PATTERN_LEN = 5;
36 static const int MIDDLE_PATTERN[MIDDLE_PATTERN_LEN] = {1, 1, 1, 1, 1};
39 * "Odd", or "L" patterns used to encode UPC/EAN digits.
41 const int L_PATTERNS_LEN = 10;
42 const int L_PATTERNS_SUB_LEN = 4;
43 const int L_PATTERNS[10][4] = {
57 * As above but also including the "even", or "G" patterns used to encode UPC/EAN digits.
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] = {
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
85 const int UPCEANReader::getMIDDLE_PATTERN_LEN(){
86 return MIDDLE_PATTERN_LEN;
88 const int* UPCEANReader::getMIDDLE_PATTERN(){
89 return MIDDLE_PATTERN;
92 UPCEANReader::UPCEANReader(){
96 Ref<Result> UPCEANReader::decodeRow(int rowNumber, Ref<BitArray> row){
97 return decodeRow(rowNumber, row, findStartGuardPattern(row));
99 Ref<Result> UPCEANReader::decodeRow(int rowNumber, Ref<BitArray> row, int startGuardRange[]){
101 std::string tmpResultString;
102 std::string& tmpResultStringRef = tmpResultString;
105 endStart = decodeMiddle(row, startGuardRange, 2 /*reference findGuardPattern*/ , tmpResultStringRef);
106 } catch (ReaderException re) {
107 if (startGuardRange!=NULL) {
108 delete [] startGuardRange;
109 startGuardRange = NULL;
114 int* endRange = decodeEnd(row, endStart);
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.");
125 if (!checkChecksum(tmpResultString)) {
126 if (startGuardRange!=NULL) {
127 delete [] startGuardRange;
128 startGuardRange = NULL;
130 if (endRange!=NULL) {
134 throw ReaderException("Checksum fail.");
137 Ref<String> resultString(new String(tmpResultString));
139 float left = (float) (startGuardRange[1] + startGuardRange[0]) / 2.0f;
140 float right = (float) (endRange[1] + endRange[0]) / 2.0f;
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;
148 ArrayRef<unsigned char> resultBytes(1);
150 if (startGuardRange!=NULL) {
151 delete [] startGuardRange;
152 startGuardRange = NULL;
154 if (endRange!=NULL) {
159 Ref<Result> res(new Result(resultString, resultBytes, resultPoints, getBarcodeFormat()));
163 int* UPCEANReader::findStartGuardPattern(Ref<BitArray> row){
164 bool foundStart = false;
166 int* startRange = NULL;
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);
180 delete [] startRange;
186 int* UPCEANReader::findGuardPattern(Ref<BitArray> row, int rowOffset, bool whiteFirst, const int pattern[], int patternLen){
187 int patternLength = patternLen;
189 int counters[patternLength];
190 int countersCount = sizeof(counters)/sizeof(int);
191 for (int i=0; i<countersCount ; i++) {
194 int width = row->getSize();
195 bool isWhite = false;
196 while (rowOffset < width) {
197 isWhite = !row->get(rowOffset);
198 if (whiteFirst == isWhite) {
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]++;
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;
218 patternStart += counters[0] + counters[1];
219 for (int y = 2; y < patternLength; y++) {
220 counters[y - 2] = counters[y];
222 counters[patternLength - 2] = 0;
223 counters[patternLength - 1] = 0;
228 counters[counterPosition] = 1;
232 throw ReaderException("findGuardPattern");
235 int* UPCEANReader::decodeEnd(Ref<BitArray> row, int endStart){
236 return findGuardPattern(row, endStart, false, START_END_PATTERN, sizeof(START_END_PATTERN)/sizeof(int));
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
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];
255 unsigned int variance = patternMatchVariance(counters, countersLen, pattern, MAX_INDIVIDUAL_VARIANCE);
256 if (variance < bestVariance) {
257 bestVariance = variance;
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];
270 unsigned int variance = patternMatchVariance(counters, countersLen, pattern, MAX_INDIVIDUAL_VARIANCE);
271 if (variance < bestVariance) {
272 bestVariance = variance;
280 if (bestMatch >= 0) {
283 throw ReaderException("UPCEANReader::decodeDigit: No best mach");
289 * @return {@link #checkStandardUPCEANChecksum(String)}
291 bool UPCEANReader::checkChecksum(std::string s){
292 return checkStandardUPCEANChecksum(s);
296 * Computes the UPC/EAN checksum on a string of digits, and reports
297 * whether the checksum is correct or not.
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
303 bool UPCEANReader::checkStandardUPCEANChecksum(std::string s){
304 int length = s.length();
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");
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");
325 return sum % 10 == 0;
327 UPCEANReader::~UPCEANReader(){