#include <zxing/oned/OneDResultPoint.h>
#include <zxing/ReaderException.h>
namespace zxing {
- namespace oned {
-
- /**
- * Start/end guard pattern.
- */
- static const int START_END_PATTERN[3] = {1, 1, 1};
-
- /**
- * Pattern marking the middle of a UPC/EAN pattern, separating the two halves.
- */
- static const int MIDDLE_PATTERN_LEN = 5;
- static const int MIDDLE_PATTERN[MIDDLE_PATTERN_LEN] = {1, 1, 1, 1, 1};
-
- /**
- * "Odd", or "L" patterns used to encode UPC/EAN digits.
- */
- const int L_PATTERNS_LEN = 10;
- const int L_PATTERNS_SUB_LEN = 4;
- const int L_PATTERNS[10][4] = {
- {3, 2, 1, 1}, // 0
- {2, 2, 2, 1}, // 1
- {2, 1, 2, 2}, // 2
- {1, 4, 1, 1}, // 3
- {1, 1, 3, 2}, // 4
- {1, 2, 3, 1}, // 5
- {1, 1, 1, 4}, // 6
- {1, 3, 1, 2}, // 7
- {1, 2, 1, 3}, // 8
- {3, 1, 1, 2} // 9
- };
-
- /**
- * As above but also including the "even", or "G" patterns used to encode UPC/EAN digits.
- */
- const int L_AND_G_PATTERNS_LEN = 20;
- const int L_AND_G_PATTERNS_SUB_LEN = 4;
- const int L_AND_G_PATTERNS[L_AND_G_PATTERNS_LEN][L_AND_G_PATTERNS_SUB_LEN] = {
- {3, 2, 1, 1}, // 0
- {2, 2, 2, 1}, // 1
- {2, 1, 2, 2}, // 2
- {1, 4, 1, 1}, // 3
- {1, 1, 3, 2}, // 4
- {1, 2, 3, 1}, // 5
- {1, 1, 1, 4}, // 6
- {1, 3, 1, 2}, // 7
- {1, 2, 1, 3}, // 8
- {3, 1, 1, 2}, // 9
- {1, 1, 2, 3}, // 10 reversed 0
- {1, 2, 2, 2}, // 11 reversed 1
- {2, 2, 1, 2}, // 12 reversed 2
- {1, 1, 4, 1}, // 13 reversed 3
- {2, 3, 1, 1}, // 14 reversed 4
- {1, 3, 2, 1}, // 15 reversed 5
- {4, 1, 1, 1}, // 16 reversed 6
- {2, 1, 3, 1}, // 17 reversed 7
- {3, 1, 2, 1}, // 18 reversed 8
- {2, 1, 1, 3} // 19 reversed 9
- };
-
+ namespace oned {
+
+ /**
+ * Start/end guard pattern.
+ */
+ static const int START_END_PATTERN[3] = {1, 1, 1};
+
+ /**
+ * Pattern marking the middle of a UPC/EAN pattern, separating the two halves.
+ */
+ static const int MIDDLE_PATTERN_LEN = 5;
+ static const int MIDDLE_PATTERN[MIDDLE_PATTERN_LEN] = {1, 1, 1, 1, 1};
+
+ /**
+ * "Odd", or "L" patterns used to encode UPC/EAN digits.
+ */
+ const int L_PATTERNS_LEN = 10;
+ const int L_PATTERNS_SUB_LEN = 4;
+ const int L_PATTERNS[10][4] = {
+ {3, 2, 1, 1}, // 0
+ {2, 2, 2, 1}, // 1
+ {2, 1, 2, 2}, // 2
+ {1, 4, 1, 1}, // 3
+ {1, 1, 3, 2}, // 4
+ {1, 2, 3, 1}, // 5
+ {1, 1, 1, 4}, // 6
+ {1, 3, 1, 2}, // 7
+ {1, 2, 1, 3}, // 8
+ {3, 1, 1, 2} // 9
+ };
+
+ /**
+ * As above but also including the "even", or "G" patterns used to encode UPC/EAN digits.
+ */
+ const int L_AND_G_PATTERNS_LEN = 20;
+ const int L_AND_G_PATTERNS_SUB_LEN = 4;
+ const int L_AND_G_PATTERNS[L_AND_G_PATTERNS_LEN][L_AND_G_PATTERNS_SUB_LEN] = {
+ {3, 2, 1, 1}, // 0
+ {2, 2, 2, 1}, // 1
+ {2, 1, 2, 2}, // 2
+ {1, 4, 1, 1}, // 3
+ {1, 1, 3, 2}, // 4
+ {1, 2, 3, 1}, // 5
+ {1, 1, 1, 4}, // 6
+ {1, 3, 1, 2}, // 7
+ {1, 2, 1, 3}, // 8
+ {3, 1, 1, 2}, // 9
+ {1, 1, 2, 3}, // 10 reversed 0
+ {1, 2, 2, 2}, // 11 reversed 1
+ {2, 2, 1, 2}, // 12 reversed 2
+ {1, 1, 4, 1}, // 13 reversed 3
+ {2, 3, 1, 1}, // 14 reversed 4
+ {1, 3, 2, 1}, // 15 reversed 5
+ {4, 1, 1, 1}, // 16 reversed 6
+ {2, 1, 3, 1}, // 17 reversed 7
+ {3, 1, 2, 1}, // 18 reversed 8
+ {2, 1, 1, 3} // 19 reversed 9
+ };
+
- const int UPCEANReader::getMIDDLE_PATTERN_LEN(){
- return MIDDLE_PATTERN_LEN;
- }
- const int* UPCEANReader::getMIDDLE_PATTERN(){
- return MIDDLE_PATTERN;
- }
-
- UPCEANReader::UPCEANReader(){
- }
-
-
- Ref<Result> UPCEANReader::decodeRow(int rowNumber, Ref<BitArray> row){
- return decodeRow(rowNumber, row, findStartGuardPattern(row));
- }
- Ref<Result> UPCEANReader::decodeRow(int rowNumber, Ref<BitArray> row, int startGuardRange[]){
-
- std::string tmpResultString;
- std::string& tmpResultStringRef = tmpResultString;
- int endStart;
+ const int UPCEANReader::getMIDDLE_PATTERN_LEN(){
+ return MIDDLE_PATTERN_LEN;
+ }
+ const int* UPCEANReader::getMIDDLE_PATTERN(){
+ return MIDDLE_PATTERN;
+ }
+
+ UPCEANReader::UPCEANReader(){
+ }
+
+
+ Ref<Result> UPCEANReader::decodeRow(int rowNumber, Ref<BitArray> row) {
+ int* start = NULL;
try {
- endStart = decodeMiddle(row, startGuardRange, 2 /*reference findGuardPattern*/ , tmpResultStringRef);
- } catch (ReaderException re) {
- if (startGuardRange!=NULL) {
- delete [] startGuardRange;
- startGuardRange = NULL;
- }
+ start = findStartGuardPattern(row);
+ Ref<Result> result = decodeRow(rowNumber, row, start);
+ delete [] start;
+ return result;
+ } catch (ReaderException const& re) {
+ delete [] start;
throw re;
}
-
- int* endRange = decodeEnd(row, endStart);
-
- // Make sure there is a quiet zone at least as big as the end pattern after the barcode. The
- // spec might want more whitespace, but in practice this is the maximum we can count on.
- size_t end = endRange[1];
- size_t quietEnd = end + (end - endRange[0]);
- if (quietEnd >= row->getSize() || !row->isRange(end, quietEnd, false)) {
- throw ReaderException("Quiet zone asserrt fail.");
- }
-
- if (!checkChecksum(tmpResultString)) {
- if (startGuardRange!=NULL) {
- delete [] startGuardRange;
- startGuardRange = NULL;
- }
- if (endRange!=NULL) {
- delete [] endRange;
- endRange = NULL;
- }
- throw ReaderException("Checksum fail.");
- }
-
- Ref<String> resultString(new String(tmpResultString));
-
- float left = (float) (startGuardRange[1] + startGuardRange[0]) / 2.0f;
- float right = (float) (endRange[1] + endRange[0]) / 2.0f;
-
- std::vector< Ref<ResultPoint> > resultPoints(2);
- Ref<OneDResultPoint> resultPoint1(new OneDResultPoint(left, (float) rowNumber));
- Ref<OneDResultPoint> resultPoint2(new OneDResultPoint(right, (float) rowNumber));
- resultPoints[0] = resultPoint1;
- resultPoints[1] = resultPoint2;
-
- ArrayRef<unsigned char> resultBytes(1);
-
- if (startGuardRange!=NULL) {
- delete [] startGuardRange;
- startGuardRange = NULL;
- }
- if (endRange!=NULL) {
- delete [] endRange;
- endRange = NULL;
- }
-
- Ref<Result> res(new Result(resultString, resultBytes, resultPoints, getBarcodeFormat()));
- return res;
- }
-
- int* UPCEANReader::findStartGuardPattern(Ref<BitArray> row){
- bool foundStart = false;
-
- int* startRange = NULL;
- int nextStart = 0;
- while (!foundStart) {
- startRange = findGuardPattern(row, nextStart, false, START_END_PATTERN, sizeof(START_END_PATTERN)/sizeof(int));
- int start = startRange[0];
- nextStart = startRange[1];
- // Make sure there is a quiet zone at least as big as the start pattern before the barcode.
- // If this check would run off the left edge of the image, do not accept this barcode,
- // as it is very likely to be a false positive.
- int quietStart = start - (nextStart - start);
- if (quietStart >= 0) {
- foundStart = row->isRange(quietStart, start, false);
- }
- if (!foundStart) {
- delete [] startRange;
- }
- }
- return startRange;
- }
-
- int* UPCEANReader::findGuardPattern(Ref<BitArray> row, int rowOffset, bool whiteFirst, const int pattern[], int patternLen){
- int patternLength = patternLen;
-
- int counters[patternLength];
- int countersCount = sizeof(counters)/sizeof(int);
- for (int i=0; i<countersCount ; i++) {
- counters[i]=0;
- }
- int width = row->getSize();
- bool isWhite = false;
- while (rowOffset < width) {
- isWhite = !row->get(rowOffset);
- if (whiteFirst == isWhite) {
- break;
- }
- rowOffset++;
- }
-
- int counterPosition = 0;
- int patternStart = rowOffset;
- for (int x = rowOffset; x < width; x++) {
- bool pixel = row->get(x);
- if (pixel ^ isWhite) {
- counters[counterPosition]++;
- } else {
- if (counterPosition == patternLength - 1) {
- if (patternMatchVariance(counters, countersCount, pattern, MAX_INDIVIDUAL_VARIANCE) < MAX_AVG_VARIANCE) {
- int* resultValue = new int[2];
- resultValue[0] = patternStart;
- resultValue[1] = x;
- return resultValue;
- }
- patternStart += counters[0] + counters[1];
- for (int y = 2; y < patternLength; y++) {
- counters[y - 2] = counters[y];
- }
- counters[patternLength - 2] = 0;
- counters[patternLength - 1] = 0;
- counterPosition--;
- } else {
- counterPosition++;
- }
- counters[counterPosition] = 1;
- isWhite = !isWhite;
- }
- }
- throw ReaderException("findGuardPattern");
- }
-
- int* UPCEANReader::decodeEnd(Ref<BitArray> row, int endStart){
- return findGuardPattern(row, endStart, false, START_END_PATTERN, sizeof(START_END_PATTERN)/sizeof(int));
- }
-
-// int UPCEANReader::decodeDigit(Ref<BitArray> row, int counters[], int countersLen, int rowOffset, int** patterns/*[][]*/, int paterns1Len, int paterns2Len)
- int UPCEANReader::decodeDigit(Ref<BitArray> row, int counters[], int countersLen, int rowOffset, UPC_EAN_PATTERNS patternType){
- recordPattern(row, rowOffset, counters, countersLen);
- unsigned int bestVariance = MAX_AVG_VARIANCE; // worst variance we'll accept
- int bestMatch = -1;
-
- int max = 0;
- switch (patternType) {
- case UPC_EAN_PATTERNS_L_PATTERNS:
- max = L_PATTERNS_LEN;
- for (int i = 0; i < max; i++) {
- int pattern[countersLen];
- for(int j = 0; j< countersLen; j++){
- pattern[j] = L_PATTERNS[i][j];
- }
-
- unsigned int variance = patternMatchVariance(counters, countersLen, pattern, MAX_INDIVIDUAL_VARIANCE);
- if (variance < bestVariance) {
- bestVariance = variance;
- bestMatch = i;
- }
- }
- break;
- case UPC_EAN_PATTERNS_L_AND_G_PATTERNS:
- max = L_AND_G_PATTERNS_LEN;
- for (int i = 0; i < max; i++) {
- int pattern[countersLen];
- for(int j = 0; j< countersLen; j++){
- pattern[j] = L_AND_G_PATTERNS[i][j];
- }
-
- unsigned int variance = patternMatchVariance(counters, countersLen, pattern, MAX_INDIVIDUAL_VARIANCE);
- if (variance < bestVariance) {
- bestVariance = variance;
- bestMatch = i;
- }
- }
- break;
- default:
- break;
- }
- if (bestMatch >= 0) {
- return bestMatch;
- } else {
- throw ReaderException("UPCEANReader::decodeDigit: No best mach");
- }
- }
-
-
- /**
- * @return {@link #checkStandardUPCEANChecksum(String)}
- */
- bool UPCEANReader::checkChecksum(std::string s){
- return checkStandardUPCEANChecksum(s);
- }
-
- /**
- * Computes the UPC/EAN checksum on a string of digits, and reports
- * whether the checksum is correct or not.
- *
- * @param s string of digits to check
- * @return true iff string of digits passes the UPC/EAN checksum algorithm
- * @throws ReaderException if the string does not contain only digits
- */
- bool UPCEANReader::checkStandardUPCEANChecksum(std::string s){
- int length = s.length();
- if (length == 0) {
- return false;
- }
-
- int sum = 0;
- for (int i = length - 2; i >= 0; i -= 2) {
- int digit = (int) s[i] - (int) '0';
- if (digit < 0 || digit > 9) {
- throw ReaderException("checkStandardUPCEANChecksum");
- }
- sum += digit;
- }
- sum *= 3;
- for (int i = length - 1; i >= 0; i -= 2) {
- int digit = (int) s[i] - (int) '0';
- if (digit < 0 || digit > 9) {
- throw ReaderException("checkStandardUPCEANChecksum");
- }
- sum += digit;
+ }
+
+ Ref<Result> UPCEANReader::decodeRow(int rowNumber, Ref<BitArray> row, int startGuardRange[]){
+ int* endRange = NULL;
+ try {
+ std::string tmpResultString;
+ std::string& tmpResultStringRef = tmpResultString;
+ int endStart;
+ endStart = decodeMiddle(row, startGuardRange, 2 /*reference findGuardPattern*/ , tmpResultStringRef);
+
+ endRange = decodeEnd(row, endStart);
+
+ // Make sure there is a quiet zone at least as big as the end pattern after the barcode. The
+ // spec might want more whitespace, but in practice this is the maximum we can count on.
+ size_t end = endRange[1];
+ size_t quietEnd = end + (end - endRange[0]);
+ if (quietEnd >= row->getSize() || !row->isRange(end, quietEnd, false)) {
+ throw ReaderException("Quiet zone asserrt fail.");
+ }
+
+ if (!checkChecksum(tmpResultString)) {
+ throw ReaderException("Checksum fail.");
+ }
+
+ Ref<String> resultString(new String(tmpResultString));
+
+ float left = (float) (startGuardRange[1] + startGuardRange[0]) / 2.0f;
+ float right = (float) (endRange[1] + endRange[0]) / 2.0f;
+
+ std::vector< Ref<ResultPoint> > resultPoints(2);
+ Ref<OneDResultPoint> resultPoint1(new OneDResultPoint(left, (float) rowNumber));
+ Ref<OneDResultPoint> resultPoint2(new OneDResultPoint(right, (float) rowNumber));
+ resultPoints[0] = resultPoint1;
+ resultPoints[1] = resultPoint2;
+
+ ArrayRef<unsigned char> resultBytes(1);
+
+ Ref<Result> res(new Result(resultString, resultBytes, resultPoints, getBarcodeFormat()));
+ delete [] endRange;
+ return res;
+ } catch (ReaderException const& re) {
+ delete [] endRange;
+ throw re;
}
- return sum % 10 == 0;
- }
- UPCEANReader::~UPCEANReader(){
- }
- }
+
+ }
+
+ int* UPCEANReader::findStartGuardPattern(Ref<BitArray> row){
+ bool foundStart = false;
+
+ int* startRange = NULL;
+ int nextStart = 0;
+ try {
+ while (!foundStart) {
+ delete [] startRange;
+ startRange = NULL;
+ startRange = findGuardPattern(row, nextStart, false, START_END_PATTERN, sizeof(START_END_PATTERN)/sizeof(int));
+ int start = startRange[0];
+ nextStart = startRange[1];
+ // Make sure there is a quiet zone at least as big as the start pattern before the barcode.
+ // If this check would run off the left edge of the image, do not accept this barcode,
+ // as it is very likely to be a false positive.
+ int quietStart = start - (nextStart - start);
+ if (quietStart >= 0) {
+ foundStart = row->isRange(quietStart, start, false);
+ }
+ }
+ return startRange;
+ } catch (ReaderException const& re) {
+ delete [] startRange;
+ throw re;
+ }
+ }
+
+ // TODO(flyashi): Return a pair<int, int> for return value to avoid using the heap.
+ int* UPCEANReader::findGuardPattern(Ref<BitArray> row, int rowOffset, bool whiteFirst, const int pattern[], int patternLen){
+ int patternLength = patternLen;
+ int counters[patternLength];
+ int countersCount = sizeof(counters) / sizeof(int);
+ for (int i = 0; i < countersCount; i++) {
+ counters[i] = 0;
+ }
+ int width = row->getSize();
+ bool isWhite = false;
+ while (rowOffset < width) {
+ isWhite = !row->get(rowOffset);
+ if (whiteFirst == isWhite) {
+ break;
+ }
+ rowOffset++;
+ }
+
+ int counterPosition = 0;
+ int patternStart = rowOffset;
+ for (int x = rowOffset; x < width; x++) {
+ bool pixel = row->get(x);
+ if (pixel ^ isWhite) {
+ counters[counterPosition]++;
+ } else {
+ if (counterPosition == patternLength - 1) {
+ if (patternMatchVariance(counters, countersCount, pattern, MAX_INDIVIDUAL_VARIANCE) < MAX_AVG_VARIANCE) {
+ int* resultValue = new int[2];
+ resultValue[0] = patternStart;
+ resultValue[1] = x;
+ return resultValue;
+ }
+ patternStart += counters[0] + counters[1];
+ for (int y = 2; y < patternLength; y++) {
+ counters[y - 2] = counters[y];
+ }
+ counters[patternLength - 2] = 0;
+ counters[patternLength - 1] = 0;
+ counterPosition--;
+ } else {
+ counterPosition++;
+ }
+ counters[counterPosition] = 1;
+ isWhite = !isWhite;
+ }
+ }
+ throw ReaderException("findGuardPattern");
+ }
+
+ int* UPCEANReader::decodeEnd(Ref<BitArray> row, int endStart){
+ return findGuardPattern(row, endStart, false, START_END_PATTERN, sizeof(START_END_PATTERN)/sizeof(int));
+ }
+
+// int UPCEANReader::decodeDigit(Ref<BitArray> row, int counters[], int countersLen, int rowOffset, int** patterns/*[][]*/, int paterns1Len, int paterns2Len)
+ int UPCEANReader::decodeDigit(Ref<BitArray> row, int counters[], int countersLen, int rowOffset, UPC_EAN_PATTERNS patternType){
+ recordPattern(row, rowOffset, counters, countersLen);
+ unsigned int bestVariance = MAX_AVG_VARIANCE; // worst variance we'll accept
+ int bestMatch = -1;
+
+ int max = 0;
+ switch (patternType) {
+ case UPC_EAN_PATTERNS_L_PATTERNS:
+ max = L_PATTERNS_LEN;
+ for (int i = 0; i < max; i++) {
+ int pattern[countersLen];
+ for(int j = 0; j< countersLen; j++){
+ pattern[j] = L_PATTERNS[i][j];
+ }
+
+ unsigned int variance = patternMatchVariance(counters, countersLen, pattern, MAX_INDIVIDUAL_VARIANCE);
+ if (variance < bestVariance) {
+ bestVariance = variance;
+ bestMatch = i;
+ }
+ }
+ break;
+ case UPC_EAN_PATTERNS_L_AND_G_PATTERNS:
+ max = L_AND_G_PATTERNS_LEN;
+ for (int i = 0; i < max; i++) {
+ int pattern[countersLen];
+ for(int j = 0; j< countersLen; j++){
+ pattern[j] = L_AND_G_PATTERNS[i][j];
+ }
+
+ unsigned int variance = patternMatchVariance(counters, countersLen, pattern, MAX_INDIVIDUAL_VARIANCE);
+ if (variance < bestVariance) {
+ bestVariance = variance;
+ bestMatch = i;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ if (bestMatch >= 0) {
+ return bestMatch;
+ } else {
+ throw ReaderException("UPCEANReader::decodeDigit: No best mach");
+ }
+ }
+
+
+ /**
+ * @return {@link #checkStandardUPCEANChecksum(String)}
+ */
+ bool UPCEANReader::checkChecksum(std::string s){
+ return checkStandardUPCEANChecksum(s);
+ }
+
+ /**
+ * Computes the UPC/EAN checksum on a string of digits, and reports
+ * whether the checksum is correct or not.
+ *
+ * @param s string of digits to check
+ * @return true iff string of digits passes the UPC/EAN checksum algorithm
+ * @throws ReaderException if the string does not contain only digits
+ */
+ bool UPCEANReader::checkStandardUPCEANChecksum(std::string s){
+ int length = s.length();
+ if (length == 0) {
+ return false;
+ }
+
+ int sum = 0;
+ for (int i = length - 2; i >= 0; i -= 2) {
+ int digit = (int) s[i] - (int) '0';
+ if (digit < 0 || digit > 9) {
+ throw ReaderException("checkStandardUPCEANChecksum");
+ }
+ sum += digit;
+ }
+ sum *= 3;
+ for (int i = length - 1; i >= 0; i -= 2) {
+ int digit = (int) s[i] - (int) '0';
+ if (digit < 0 || digit > 9) {
+ throw ReaderException("checkStandardUPCEANChecksum");
+ }
+ sum += digit;
+ }
+ return sum % 10 == 0;
+ }
+ UPCEANReader::~UPCEANReader(){
+ }
+ }
}