From: dswitkin@google.com Date: Fri, 13 Aug 2010 16:20:03 +0000 (+0000) Subject: Began removing the excessive use of exceptions in the 1D readers by drawing X-Git-Url: http://git.rot13.org/?p=zxing.git;a=commitdiff_plain;h=30f0e5e9eeab4a85a378809bfa7007b128694138 Began removing the excessive use of exceptions in the 1D readers by drawing a line in the sand: no one may throw an exception from decodeRow(). Next up is to throw fewer exceptions internally. git-svn-id: http://zxing.googlecode.com/svn/trunk@1527 59b500cc-1b3d-0410-9834-0bbf25fbcc57 --- diff --git a/cpp/core/src/zxing/common/Counted.h b/cpp/core/src/zxing/common/Counted.h index f79b5d86..306ed6cd 100644 --- a/cpp/core/src/zxing/common/Counted.h +++ b/cpp/core/src/zxing/common/Counted.h @@ -193,6 +193,10 @@ public: return x == 0 ? object_ != 0 : true; } + bool empty() const { + return object_ == 0; + } + template friend std::ostream& operator<<(std::ostream &out, Ref& ref); }; diff --git a/cpp/core/src/zxing/oned/Code128Reader.cpp b/cpp/core/src/zxing/oned/Code128Reader.cpp index 36ab5dc5..4668a038 100644 --- a/cpp/core/src/zxing/oned/Code128Reader.cpp +++ b/cpp/core/src/zxing/oned/Code128Reader.cpp @@ -2,7 +2,6 @@ * Code128Reader.cpp * ZXing * - * Created by Lukasz Warchol on 10-01-15. * Copyright 2010 ZXing authors All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -28,7 +27,7 @@ namespace zxing { namespace oned { - + const int CODE_PATTERNS_LENGTH = 107; const int countersLength = 6; static const int CODE_PATTERNS[CODE_PATTERNS_LENGTH][countersLength] = { @@ -140,11 +139,11 @@ namespace zxing { {2, 1, 1, 2, 3, 2}, /* 105 */ {2, 3, 3, 1, 1, 1} }; - - + + Code128Reader::Code128Reader(){ } - + int* Code128Reader::findStartPattern(Ref row){ int width = row->getSize(); int rowOffset = 0; @@ -154,13 +153,13 @@ namespace zxing { } rowOffset++; } - + int counterPosition = 0; int counters[countersLength] = {0,0,0,0,0,0}; int patternStart = rowOffset; bool isWhite = false; int patternLength = sizeof(counters) / sizeof(int); - + for (int i = rowOffset; i < width; i++) { bool pixel = row->get(i); if (pixel ^ isWhite) { @@ -170,7 +169,8 @@ namespace zxing { unsigned int bestVariance = MAX_AVG_VARIANCE; int bestMatch = -1; for (int startCode = CODE_START_A; startCode <= CODE_START_C; startCode++) { - unsigned int variance = patternMatchVariance(counters, sizeof(counters)/sizeof(int), CODE_PATTERNS[startCode], MAX_INDIVIDUAL_VARIANCE); + unsigned int variance = patternMatchVariance(counters, sizeof(counters) / sizeof(int), + CODE_PATTERNS[startCode], MAX_INDIVIDUAL_VARIANCE); if (variance < bestVariance) { bestVariance = variance; bestMatch = startCode; @@ -178,7 +178,8 @@ namespace zxing { } if (bestMatch >= 0) { // Look for whitespace before start pattern, >= 50% of width of start pattern - if (row->isRange(fmaxl(0, patternStart - (i - patternStart) / 2), patternStart, false)) { + if (row->isRange(fmaxl(0, patternStart - (i - patternStart) / 2), patternStart, + false)) { int* resultValue = new int[3]; resultValue[0] = patternStart; resultValue[1] = i; @@ -202,19 +203,21 @@ namespace zxing { } throw ReaderException(""); } - - int Code128Reader::decodeCode(Ref row, int counters[], int countersCount, int rowOffset){ + + int Code128Reader::decodeCode(Ref row, int counters[], int countersCount, + int rowOffset){ recordPattern(row, rowOffset, counters, countersCount); unsigned int bestVariance = MAX_AVG_VARIANCE; // worst variance we'll accept int bestMatch = -1; for (int d = 0; d < CODE_PATTERNS_LENGTH; d++) { int pattern[countersLength]; - + for(int ind = 0; ind< countersLength; ind++){ pattern[ind] = CODE_PATTERNS[d][ind]; } // memcpy(pattern, CODE_PATTERNS[d], countersLength); - unsigned int variance = patternMatchVariance(counters, countersCount, pattern, MAX_INDIVIDUAL_VARIANCE); + unsigned int variance = patternMatchVariance(counters, countersCount, pattern, + MAX_INDIVIDUAL_VARIANCE); if (variance < bestVariance) { bestVariance = variance; bestMatch = d; @@ -227,265 +230,258 @@ namespace zxing { throw ReaderException(""); } } - - Ref Code128Reader::decodeRow(int rowNumber, Ref row){ - - int* startPatternInfo = findStartPattern(row); - int startCode = startPatternInfo[2]; - int codeSet; - switch (startCode) { - case CODE_START_A: - codeSet = CODE_CODE_A; - break; - case CODE_START_B: - codeSet = CODE_CODE_B; - break; - case CODE_START_C: - codeSet = CODE_CODE_C; - break; - default: - delete [] startPatternInfo; - throw ReaderException(""); - } - - bool done = false; - bool isNextShifted = false; - - std::string tmpResultString; - std::stringstream tmpResultSStr; // used if its Code 128C - - int lastStart = startPatternInfo[0]; - int nextStart = startPatternInfo[1]; - int counters[countersLength] = {0,0,0,0,0,0}; - - int lastCode = 0; - int code = 0; - int checksumTotal = startCode; - int multiplier = 0; - bool lastCharacterWasPrintable = true; - - while (!done) { - - bool unshift = isNextShifted; - isNextShifted = false; - - // Save off last code - lastCode = code; - - // Decode another code from image - try { - code = decodeCode(row, counters, sizeof(counters)/sizeof(int), nextStart); - } catch (ReaderException re) { - delete [] startPatternInfo; - throw re; - } - - // Remember whether the last code was printable or not (excluding CODE_STOP) - if (code != CODE_STOP) { - lastCharacterWasPrintable = true; - } - - // Add to checksum computation (if not CODE_STOP of course) - if (code != CODE_STOP) { - multiplier++; - checksumTotal += multiplier * code; - } - - // Advance to where the next code will to start - lastStart = nextStart; - int _countersLength = sizeof(counters) / sizeof(int); - for (int i = 0; i < _countersLength; i++) { - nextStart += counters[i]; - } - - // Take care of illegal start codes - switch (code) { - case CODE_START_A: - case CODE_START_B: - case CODE_START_C: - delete [] startPatternInfo; - throw ReaderException(""); - } - - switch (codeSet) { - - case CODE_CODE_A: - if (code < 64) { - tmpResultString.append(1, (char) (' ' + code)); - } else if (code < 96) { - tmpResultString.append(1, (char) (code - 64)); - } else { - // Don't let CODE_STOP, which always appears, affect whether whether we think the last - // code was printable or not. - if (code != CODE_STOP) { - lastCharacterWasPrintable = false; - } - switch (code) { - case CODE_FNC_1: - case CODE_FNC_2: - case CODE_FNC_3: - case CODE_FNC_4_A: - // do nothing? - break; - case CODE_SHIFT: - isNextShifted = true; - codeSet = CODE_CODE_B; - break; - case CODE_CODE_B: - codeSet = CODE_CODE_B; - break; - case CODE_CODE_C: - codeSet = CODE_CODE_C; - break; - case CODE_STOP: - done = true; - break; - } - } - break; - case CODE_CODE_B: - if (code < 96) { - tmpResultString.append(1, (char) (' ' + code)); - } else { - if (code != CODE_STOP) { - lastCharacterWasPrintable = false; - } - switch (code) { - case CODE_FNC_1: - case CODE_FNC_2: - case CODE_FNC_3: - case CODE_FNC_4_B: - // do nothing? - break; - case CODE_SHIFT: - isNextShifted = true; - codeSet = CODE_CODE_C; - break; - case CODE_CODE_A: - codeSet = CODE_CODE_A; - break; - case CODE_CODE_C: - codeSet = CODE_CODE_C; - break; - case CODE_STOP: - done = true; - break; - } - } - break; - case CODE_CODE_C: - // the code read in this case is the number encoded directly - if (code < 100) { - if (code < 10) - tmpResultSStr << '0'; - tmpResultSStr << code; - } else { - if (code != CODE_STOP) { - lastCharacterWasPrintable = false; - } - switch (code) { - case CODE_FNC_1: - // do nothing? - break; - case CODE_CODE_A: - codeSet = CODE_CODE_A; - break; - case CODE_CODE_B: - codeSet = CODE_CODE_B; - break; - case CODE_STOP: - done = true; - break; - } - } - break; - } - - // Unshift back to another code set if we were shifted - if (unshift) { - switch (codeSet) { - case CODE_CODE_A: - codeSet = CODE_CODE_C; - break; - case CODE_CODE_B: - codeSet = CODE_CODE_A; - break; - case CODE_CODE_C: - codeSet = CODE_CODE_B; - break; - } - } - - } - - // Check for ample whitespace following pattern, but, to do this we first need to remember that - // we fudged decoding CODE_STOP since it actually has 7 bars, not 6. There is a black bar left - // to read off. Would be slightly better to properly read. Here we just skip it: - int width = row->getSize(); - while (nextStart < width && row->get(nextStart)) { - nextStart++; - } - if (!row->isRange(nextStart, fminl(width, nextStart + (nextStart - lastStart) / 2), false)) { - delete [] startPatternInfo; - throw ReaderException(""); - } - - // Pull out from sum the value of the penultimate check code - checksumTotal -= multiplier * lastCode; - // lastCode is the checksum then: - if (checksumTotal % 103 != lastCode) { - delete [] startPatternInfo; - throw ReaderException(""); - } - - if (codeSet == CODE_CODE_C) - tmpResultString.append(tmpResultSStr.str()); - - // Need to pull out the check digits from string - int resultLength = tmpResultString.length(); - // Only bother if the result had at least one character, and if the checksum digit happened to - // be a printable character. If it was just interpreted as a control code, nothing to remove. - if (resultLength > 0 && lastCharacterWasPrintable) { - if (codeSet == CODE_CODE_C) { - tmpResultString.erase(resultLength - 2, resultLength); - } else { - tmpResultString.erase(resultLength - 1, resultLength); - } - } - - Ref resultString(new String(tmpResultString)); -// String resultString(tmpResultString); - - if (tmpResultString.length() == 0) { - delete [] startPatternInfo; - // Almost surely a false positive - throw ReaderException(""); + + Ref Code128Reader::decodeRow(int rowNumber, Ref row) { + int* startPatternInfo = NULL; + try { + startPatternInfo = findStartPattern(row); + int startCode = startPatternInfo[2]; + int codeSet; + switch (startCode) { + case CODE_START_A: + codeSet = CODE_CODE_A; + break; + case CODE_START_B: + codeSet = CODE_CODE_B; + break; + case CODE_START_C: + codeSet = CODE_CODE_C; + break; + default: + throw ReaderException(""); + } + + bool done = false; + bool isNextShifted = false; + + std::string tmpResultString; + std::stringstream tmpResultSStr; // used if its Code 128C + + int lastStart = startPatternInfo[0]; + int nextStart = startPatternInfo[1]; + int counters[countersLength] = {0,0,0,0,0,0}; + + int lastCode = 0; + int code = 0; + int checksumTotal = startCode; + int multiplier = 0; + bool lastCharacterWasPrintable = true; + + while (!done) { + bool unshift = isNextShifted; + isNextShifted = false; + + // Save off last code + lastCode = code; + + // Decode another code from image + try { + code = decodeCode(row, counters, sizeof(counters)/sizeof(int), nextStart); + } catch (ReaderException re) { + throw re; + } + + // Remember whether the last code was printable or not (excluding CODE_STOP) + if (code != CODE_STOP) { + lastCharacterWasPrintable = true; + } + + // Add to checksum computation (if not CODE_STOP of course) + if (code != CODE_STOP) { + multiplier++; + checksumTotal += multiplier * code; + } + + // Advance to where the next code will to start + lastStart = nextStart; + int _countersLength = sizeof(counters) / sizeof(int); + for (int i = 0; i < _countersLength; i++) { + nextStart += counters[i]; + } + + // Take care of illegal start codes + switch (code) { + case CODE_START_A: + case CODE_START_B: + case CODE_START_C: + throw ReaderException(""); + } + + switch (codeSet) { + + case CODE_CODE_A: + if (code < 64) { + tmpResultString.append(1, (char) (' ' + code)); + } else if (code < 96) { + tmpResultString.append(1, (char) (code - 64)); + } else { + // Don't let CODE_STOP, which always appears, affect whether whether we think the + // last code was printable or not. + if (code != CODE_STOP) { + lastCharacterWasPrintable = false; + } + switch (code) { + case CODE_FNC_1: + case CODE_FNC_2: + case CODE_FNC_3: + case CODE_FNC_4_A: + // do nothing? + break; + case CODE_SHIFT: + isNextShifted = true; + codeSet = CODE_CODE_B; + break; + case CODE_CODE_B: + codeSet = CODE_CODE_B; + break; + case CODE_CODE_C: + codeSet = CODE_CODE_C; + break; + case CODE_STOP: + done = true; + break; + } + } + break; + case CODE_CODE_B: + if (code < 96) { + tmpResultString.append(1, (char) (' ' + code)); + } else { + if (code != CODE_STOP) { + lastCharacterWasPrintable = false; + } + switch (code) { + case CODE_FNC_1: + case CODE_FNC_2: + case CODE_FNC_3: + case CODE_FNC_4_B: + // do nothing? + break; + case CODE_SHIFT: + isNextShifted = true; + codeSet = CODE_CODE_C; + break; + case CODE_CODE_A: + codeSet = CODE_CODE_A; + break; + case CODE_CODE_C: + codeSet = CODE_CODE_C; + break; + case CODE_STOP: + done = true; + break; + } + } + break; + case CODE_CODE_C: + // the code read in this case is the number encoded directly + if (code < 100) { + if (code < 10) + tmpResultSStr << '0'; + tmpResultSStr << code; + } else { + if (code != CODE_STOP) { + lastCharacterWasPrintable = false; + } + switch (code) { + case CODE_FNC_1: + // do nothing? + break; + case CODE_CODE_A: + codeSet = CODE_CODE_A; + break; + case CODE_CODE_B: + codeSet = CODE_CODE_B; + break; + case CODE_STOP: + done = true; + break; + } + } + break; + } + + // Unshift back to another code set if we were shifted + if (unshift) { + switch (codeSet) { + case CODE_CODE_A: + codeSet = CODE_CODE_C; + break; + case CODE_CODE_B: + codeSet = CODE_CODE_A; + break; + case CODE_CODE_C: + codeSet = CODE_CODE_B; + break; + } + } + + } + + // Check for ample whitespace following pattern, but, to do this we first need to remember that + // we fudged decoding CODE_STOP since it actually has 7 bars, not 6. There is a black bar left + // to read off. Would be slightly better to properly read. Here we just skip it: + int width = row->getSize(); + while (nextStart < width && row->get(nextStart)) { + nextStart++; + } + if (!row->isRange(nextStart, fminl(width, nextStart + (nextStart - lastStart) / 2), false)) { + throw ReaderException(""); + } + + // Pull out from sum the value of the penultimate check code + checksumTotal -= multiplier * lastCode; + // lastCode is the checksum then: + if (checksumTotal % 103 != lastCode) { + throw ReaderException(""); + } + + if (codeSet == CODE_CODE_C) + tmpResultString.append(tmpResultSStr.str()); + + // Need to pull out the check digits from string + int resultLength = tmpResultString.length(); + // Only bother if the result had at least one character, and if the checksum digit happened to + // be a printable character. If it was just interpreted as a control code, nothing to remove. + if (resultLength > 0 && lastCharacterWasPrintable) { + if (codeSet == CODE_CODE_C) { + tmpResultString.erase(resultLength - 2, resultLength); + } else { + tmpResultString.erase(resultLength - 1, resultLength); + } + } + + Ref resultString(new String(tmpResultString)); + if (tmpResultString.length() == 0) { + // Almost surely a false positive + throw ReaderException(""); + } + + float left = (float) (startPatternInfo[1] + startPatternInfo[0]) / 2.0f; + float right = (float) (nextStart + lastStart) / 2.0f; + + std::vector< Ref > resultPoints(2); + Ref resultPoint1(new OneDResultPoint(left, (float) rowNumber)); + Ref resultPoint2(new OneDResultPoint(right, (float) rowNumber)); + resultPoints[0] = resultPoint1; + resultPoints[1] = resultPoint2; + + delete [] startPatternInfo; + ArrayRef resultBytes(1); + return Ref(new Result(resultString, resultBytes, resultPoints, + BarcodeFormat_CODE_128)); + } catch (ReaderException const& re) { + delete [] startPatternInfo; + return Ref(); } - - float left = (float) (startPatternInfo[1] + startPatternInfo[0]) / 2.0f; - float right = (float) (nextStart + lastStart) / 2.0f; - - std::vector< Ref > resultPoints(2); - Ref resultPoint1(new OneDResultPoint(left, (float) rowNumber)); - Ref resultPoint2(new OneDResultPoint(right, (float) rowNumber)); - resultPoints[0] = resultPoint1; - resultPoints[1] = resultPoint2; - - ArrayRef resultBytes(1); - - delete [] startPatternInfo; - startPatternInfo = NULL; - - Ref res(new Result(resultString, resultBytes, resultPoints, BarcodeFormat_CODE_128)); - return res; } - + void Code128Reader::append(char* s, char c){ int len = strlen(s); s[len] = c; s[len + 1] = '\0'; } - + Code128Reader::~Code128Reader(){ } } diff --git a/cpp/core/src/zxing/oned/Code39Reader.cpp b/cpp/core/src/zxing/oned/Code39Reader.cpp index 9a32f517..bcf1b68f 100644 --- a/cpp/core/src/zxing/oned/Code39Reader.cpp +++ b/cpp/core/src/zxing/oned/Code39Reader.cpp @@ -2,7 +2,6 @@ * Code39Reader.cpp * ZXing * - * Created by Lukasz Warchol on 10-01-26. * Copyright 2010 ZXing authors All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -69,19 +68,19 @@ namespace oned { * digit, not data, and verify that the checksum passes. */ Code39Reader::Code39Reader(bool usingCheckDigit_) : - alphabet_string(ALPHABET_STRING), + alphabet_string(ALPHABET_STRING), usingCheckDigit(usingCheckDigit_), extendedMode(false) { } Code39Reader::Code39Reader(bool usingCheckDigit_, bool extendedMode_) : - alphabet_string(ALPHABET_STRING), + alphabet_string(ALPHABET_STRING), usingCheckDigit(usingCheckDigit_), extendedMode(extendedMode_) { } - Ref Code39Reader::decodeRow(int rowNumber, Ref row){ + Ref Code39Reader::decodeRow(int rowNumber, Ref row) { int* start = NULL; try { start = findAsteriskPattern(row); @@ -175,7 +174,7 @@ namespace oned { return res; } catch (ReaderException const& re) { delete [] start; - throw re; + return Ref(); } } diff --git a/cpp/core/src/zxing/oned/EAN13Reader.cpp b/cpp/core/src/zxing/oned/EAN13Reader.cpp index a29ca921..95a4584d 100644 --- a/cpp/core/src/zxing/oned/EAN13Reader.cpp +++ b/cpp/core/src/zxing/oned/EAN13Reader.cpp @@ -2,7 +2,6 @@ * EAN13Reader.cpp * ZXing * - * Created by Lukasz Warchol on 10-01-22. * Copyright 2010 ZXing authors All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -23,24 +22,25 @@ namespace zxing { namespace oned { - - static const int FIRST_DIGIT_ENCODINGS[10] = {0x00, 0x0B, 0x0D, 0xE, 0x13, 0x19, 0x1C, 0x15, 0x16, 0x1A}; - - + + static const int FIRST_DIGIT_ENCODINGS[10] = { + 0x00, 0x0B, 0x0D, 0xE, 0x13, 0x19, 0x1C, 0x15, 0x16, 0x1A + }; + EAN13Reader::EAN13Reader() { } - - int EAN13Reader::decodeMiddle(Ref row, int startRange[], int startRangeLen, std::string& resultString){ + + int EAN13Reader::decodeMiddle(Ref row, int startRange[], int startRangeLen, + std::string& resultString){ const int countersLen = 4; int counters[countersLen] = { 0, 0, 0, 0 }; - - + int end = row->getSize(); int rowOffset = startRange[1]; - int lgPatternFound = 0; - + for (int x = 0; x < 6 && rowOffset < end; x++) { - int bestMatch = decodeDigit(row, counters, countersLen, rowOffset, UPC_EAN_PATTERNS_L_AND_G_PATTERNS); + int bestMatch = decodeDigit(row, counters, countersLen, rowOffset, + UPC_EAN_PATTERNS_L_AND_G_PATTERNS); resultString.append(1, (char) ('0' + bestMatch % 10)); for (int i = 0; i < countersLen; i++) { rowOffset += counters[i]; @@ -49,31 +49,33 @@ namespace zxing { lgPatternFound |= 1 << (5 - x); } } - + determineFirstDigit(resultString, lgPatternFound); - + int* middleRange = 0; - try { - middleRange = findGuardPattern(row, rowOffset, true, (int*)getMIDDLE_PATTERN(), getMIDDLE_PATTERN_LEN()); - rowOffset = middleRange[1]; - - for (int x = 0; x < 6 && rowOffset < end; x++) { - int bestMatch = decodeDigit(row, counters, countersLen, rowOffset, UPC_EAN_PATTERNS_L_PATTERNS); - resultString.append(1, (char) ('0' + bestMatch)); - for (int i = 0; i < countersLen; i++) { - rowOffset += counters[i]; - } - } - - delete [] middleRange; - return rowOffset; - } catch (ReaderException const& re) { - delete [] middleRange; - throw re; - } + try { + middleRange = findGuardPattern(row, rowOffset, true, (int*)getMIDDLE_PATTERN(), + getMIDDLE_PATTERN_LEN()); + rowOffset = middleRange[1]; + + for (int x = 0; x < 6 && rowOffset < end; x++) { + int bestMatch = decodeDigit(row, counters, countersLen, rowOffset, + UPC_EAN_PATTERNS_L_PATTERNS); + resultString.append(1, (char) ('0' + bestMatch)); + for (int i = 0; i < countersLen; i++) { + rowOffset += counters[i]; + } + } + + delete [] middleRange; + return rowOffset; + } catch (ReaderException const& re) { + delete [] middleRange; + throw re; + } } - - void EAN13Reader::determineFirstDigit(std::string& resultString, int lgPatternFound){ + + void EAN13Reader::determineFirstDigit(std::string& resultString, int lgPatternFound) { for (int d = 0; d < 10; d++) { if (lgPatternFound == FIRST_DIGIT_ENCODINGS[d]) { resultString.insert(0, 1, (char) ('0' + d)); @@ -82,7 +84,7 @@ namespace zxing { } throw ReaderException("determineFirstDigit"); } - + BarcodeFormat EAN13Reader::getBarcodeFormat(){ return BarcodeFormat_EAN_13; } diff --git a/cpp/core/src/zxing/oned/EAN8Reader.cpp b/cpp/core/src/zxing/oned/EAN8Reader.cpp index f54d0cfb..75bc4ad2 100644 --- a/cpp/core/src/zxing/oned/EAN8Reader.cpp +++ b/cpp/core/src/zxing/oned/EAN8Reader.cpp @@ -2,7 +2,6 @@ * EAN8Reader.cpp * ZXing * - * Created by Lukasz Warchol on 10-01-25. * Copyright 2010 ZXing authors All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -23,45 +22,49 @@ namespace zxing { namespace oned { - + EAN8Reader::EAN8Reader(){ } - - int EAN8Reader::decodeMiddle(Ref row, int startRange[], int startRangeLen, std::string& resultString){ + + int EAN8Reader::decodeMiddle(Ref row, int startRange[], int startRangeLen, + std::string& resultString){ const int countersLen = 4; int counters[countersLen] = { 0, 0, 0, 0 }; - + int end = row->getSize(); int rowOffset = startRange[1]; - + for (int x = 0; x < 4 && rowOffset < end; x++) { - int bestMatch = decodeDigit(row, counters, countersLen, rowOffset, UPC_EAN_PATTERNS_L_PATTERNS); + int bestMatch = decodeDigit(row, counters, countersLen, rowOffset, + UPC_EAN_PATTERNS_L_PATTERNS); resultString.append(1, (char) ('0' + bestMatch)); for (int i = 0; i < countersLen; i++) { rowOffset += counters[i]; } } - - int* middleRange = 0; - try { - middleRange = findGuardPattern(row, rowOffset, true, (int*)getMIDDLE_PATTERN(), getMIDDLE_PATTERN_LEN()); - rowOffset = middleRange[1]; - - for (int x = 0; x < 4 && rowOffset < end; x++) { - int bestMatch = decodeDigit(row, counters, countersLen, rowOffset, UPC_EAN_PATTERNS_L_PATTERNS); - resultString.append(1, (char) ('0' + bestMatch)); - for (int i = 0; i < countersLen; i++) { - rowOffset += counters[i]; - } - } - delete [] middleRange; - return rowOffset; - } catch (ReaderException const& re) { - delete [] middleRange; - throw re; - } + int* middleRange = 0; + try { + middleRange = findGuardPattern(row, rowOffset, true, (int*)getMIDDLE_PATTERN(), + getMIDDLE_PATTERN_LEN()); + rowOffset = middleRange[1]; + + for (int x = 0; x < 4 && rowOffset < end; x++) { + int bestMatch = decodeDigit(row, counters, countersLen, rowOffset, + UPC_EAN_PATTERNS_L_PATTERNS); + resultString.append(1, (char) ('0' + bestMatch)); + for (int i = 0; i < countersLen; i++) { + rowOffset += counters[i]; + } + } + + delete [] middleRange; + return rowOffset; + } catch (ReaderException const& re) { + delete [] middleRange; + throw re; + } } - + BarcodeFormat EAN8Reader::getBarcodeFormat(){ return BarcodeFormat_EAN_8; } diff --git a/cpp/core/src/zxing/oned/ITFReader.cpp b/cpp/core/src/zxing/oned/ITFReader.cpp index 0a45bd55..dca48a64 100644 --- a/cpp/core/src/zxing/oned/ITFReader.cpp +++ b/cpp/core/src/zxing/oned/ITFReader.cpp @@ -2,7 +2,6 @@ * ITFReader.cpp * ZXing * - * Created by Lukasz Warchol on 10-01-26. * Copyright 2010 ZXing authors All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -26,12 +25,12 @@ namespace zxing { namespace oned { - + static const int W = 3; // Pixel width of a wide line static const int N = 1; // Pixed width of a narrow line - + const int DEFAULT_ALLOWED_LENGTHS[4] = { 6, 10, 14, 44 }; - + /** * Start/end guard pattern. * @@ -40,10 +39,10 @@ namespace zxing { */ static const int START_PATTERN_LEN = 4; static const int START_PATTERN[START_PATTERN_LEN] = {N, N, N, N}; - + static const int END_PATTERN_REVERSED_LEN = 3; static const int END_PATTERN_REVERSED[END_PATTERN_REVERSED_LEN] = {N, N, W}; - + /** * Patterns of Wide / Narrow lines to indicate each digit */ @@ -60,62 +59,61 @@ namespace zxing { {W, N, N, W, N}, // 8 {N, W, N, W, N} // 9 }; - - + + ITFReader::ITFReader() : narrowLineWidth(-1) { } - - - Ref ITFReader::decodeRow(int rowNumber, Ref row){ - int* startRange = 0; + + + Ref ITFReader::decodeRow(int rowNumber, Ref row) { + int* startRange = 0; int* endRange = 0; - try { - // Find out where the Middle section (payload) starts & ends - startRange = decodeStart(row); + try { + // Find out where the Middle section (payload) starts & ends + startRange = decodeStart(row); endRange = decodeEnd(row); - - std::string tmpResult; - decodeMiddle(row, startRange[1], endRange[0], tmpResult); - - // To avoid false positives with 2D barcodes (and other patterns), make - // an assumption that the decoded string must be 6, 10 or 14 digits. - int length = tmpResult.length(); - bool lengthOK = false; - if (length == 6 || length == 10 || length == 14) { - lengthOK = true; - } - if (!lengthOK) { - throw ReaderException("not enough characters count"); - } - - Ref resultString(new String(tmpResult)); - - std::vector< Ref > resultPoints(2); - Ref resultPoint1(new OneDResultPoint(startRange[1], (float) rowNumber)); - Ref resultPoint2(new OneDResultPoint(endRange[0], (float) rowNumber)); - resultPoints[0] = resultPoint1; - resultPoints[1] = resultPoint2; - - ArrayRef resultBytes(1); - - Ref res(new Result(resultString, resultBytes, resultPoints, BarcodeFormat_ITF)); - delete [] startRange; - delete [] endRange; - return res; + + std::string tmpResult; + decodeMiddle(row, startRange[1], endRange[0], tmpResult); + + // To avoid false positives with 2D barcodes (and other patterns), make + // an assumption that the decoded string must be 6, 10 or 14 digits. + int length = tmpResult.length(); + bool lengthOK = false; + if (length == 6 || length == 10 || length == 14) { + lengthOK = true; + } + if (!lengthOK) { + throw ReaderException("not enough characters count"); + } + + Ref resultString(new String(tmpResult)); + + std::vector< Ref > resultPoints(2); + Ref resultPoint1(new OneDResultPoint(startRange[1], (float) rowNumber)); + Ref resultPoint2(new OneDResultPoint(endRange[0], (float) rowNumber)); + resultPoints[0] = resultPoint1; + resultPoints[1] = resultPoint2; + + delete [] startRange; + delete [] endRange; + ArrayRef resultBytes(1); + return Ref(new Result(resultString, resultBytes, resultPoints, BarcodeFormat_ITF)); } catch (ReaderException re) { delete [] startRange; delete [] endRange; - throw re; + return Ref(); } } - + /** * @param row row of black/white values to search * @param payloadStart offset of start pattern * @param resultString {@link StringBuffer} to append decoded chars to * @throws ReaderException if decoding could not complete successfully */ - void ITFReader::decodeMiddle(Ref row, int payloadStart, int payloadEnd, std::string& resultString){ + void ITFReader::decodeMiddle(Ref row, int payloadStart, int payloadEnd, + std::string& resultString) { // Digits are interleaved in pairs - 5 black lines for one digit, and the // 5 // interleaved white lines for the second digit. @@ -126,14 +124,14 @@ namespace zxing { for (int i=0; i row){ + int* ITFReader::decodeStart(Ref row) { int endStart = skipWhiteSpace(row); -/// static int* findGuardPattern(Ref row, int rowOffset, bool whiteFirst, const int pattern[], int patternLen); int* startPattern = 0; try { - startPattern = findGuardPattern(row, endStart, START_PATTERN, START_PATTERN_LEN); - - // Determine the width of a narrow line in pixels. We can do this by - // getting the width of the start pattern and dividing by 4 because its - // made up of 4 narrow lines. - narrowLineWidth = (startPattern[1] - startPattern[0]) >> 2; - - validateQuietZone(row, startPattern[0]); - - return startPattern; + startPattern = findGuardPattern(row, endStart, START_PATTERN, START_PATTERN_LEN); + + // Determine the width of a narrow line in pixels. We can do this by + // getting the width of the start pattern and dividing by 4 because its + // made up of 4 narrow lines. + narrowLineWidth = (startPattern[1] - startPattern[0]) >> 2; + validateQuietZone(row, startPattern[0]); + return startPattern; } catch (ReaderException re) { - delete [] startPattern; + delete [] startPattern; throw re; - } + } } - + /** * Identify where the end of the middle / payload section ends. * @@ -192,8 +187,8 @@ namespace zxing { * block' * @throws ReaderException */ - - int* ITFReader::decodeEnd(Ref row){ + + int* ITFReader::decodeEnd(Ref row) { // For convenience, reverse the row and then // search from 'the start' for the end block row->reverse(); @@ -201,28 +196,28 @@ namespace zxing { try { int endStart = skipWhiteSpace(row); endPattern = findGuardPattern(row, endStart, END_PATTERN_REVERSED, END_PATTERN_REVERSED_LEN); - + // The start & end patterns must be pre/post fixed by a quiet zone. This // zone must be at least 10 times the width of a narrow line. // ref: http://www.barcode-1.net/i25code.html validateQuietZone(row, endPattern[0]); - + // Now recalculate the indices of where the 'endblock' starts & stops to // accommodate // the reversed nature of the search int temp = endPattern[0]; endPattern[0] = row->getSize() - endPattern[1]; endPattern[1] = row->getSize() - temp; - + row->reverse(); return endPattern; } catch (ReaderException re) { delete [] endPattern; row->reverse(); throw re; - } + } } - + /** * The start & end patterns must be pre/post fixed by a quiet zone. This * zone must be at least 10 times the width of a narrow line. Scan back until @@ -238,10 +233,10 @@ namespace zxing { * @param startPattern index into row of the start or end pattern. * @throws ReaderException if the quiet zone cannot be found, a ReaderException is thrown. */ - void ITFReader::validateQuietZone(Ref row, int startPattern){ + void ITFReader::validateQuietZone(Ref row, int startPattern) { //#pragma mark needs some corrections // int quietCount = narrowLineWidth * 10; // expect to find this many pixels of quiet zone -// +// // for (int i = startPattern - 1; quietCount > 0 && i >= 0; i--) { // if (row->get(i)) { // break; @@ -253,7 +248,7 @@ namespace zxing { // throw ReaderException("Unable to find the necessary number of quiet zone pixels"); // } } - + /** * Skip all whitespace until we get to the first black line. * @@ -261,7 +256,7 @@ namespace zxing { * @return index of the first black line. * @throws ReaderException Throws exception if no black lines are found in the row */ - int ITFReader::skipWhiteSpace(Ref row){ + int ITFReader::skipWhiteSpace(Ref row) { int width = row->getSize(); int endStart = 0; while (endStart < width) { @@ -275,7 +270,7 @@ namespace zxing { } return endStart; } - + /** * @param row row of black/white values to search * @param rowOffset position to start search @@ -285,8 +280,8 @@ namespace zxing { * ints * @throws ReaderException if pattern is not found */ - - int* ITFReader::findGuardPattern(Ref row, int rowOffset, const int pattern[], int patternLen){ + int* ITFReader::findGuardPattern(Ref row, int rowOffset, const int pattern[], + int patternLen) { // TODO: This is very similar to implementation in UPCEANReader. Consider if they can be // merged to a single method. int patternLength = patternLen; @@ -296,7 +291,7 @@ namespace zxing { } int width = row->getSize(); bool isWhite = false; - + int counterPosition = 0; int patternStart = rowOffset; for (int x = rowOffset; x < width; x++) { @@ -305,7 +300,8 @@ namespace zxing { counters[counterPosition]++; } else { if (counterPosition == patternLength - 1) { - if (patternMatchVariance(counters, patternLength, pattern, MAX_INDIVIDUAL_VARIANCE) < MAX_AVG_VARIANCE) { + if (patternMatchVariance(counters, patternLength, pattern, + MAX_INDIVIDUAL_VARIANCE) < MAX_AVG_VARIANCE) { int* resultValue = new int[2]; resultValue[0] = patternStart; resultValue[1] = x; @@ -327,7 +323,7 @@ namespace zxing { } throw ReaderException(""); } - + /** * Attempts to decode a sequence of ITF black/white lines into single * digit. @@ -341,11 +337,12 @@ namespace zxing { int bestMatch = -1; int max = PATTERNS_LEN; for (int i = 0; i < max; i++) { - int pattern[countersLen]; + int pattern[countersLen]; for(int ind = 0; ind(new ITFReader())); } } - - Ref MultiFormatOneDReader::decodeRow(int rowNumber, Ref row){ + + Ref MultiFormatOneDReader::decodeRow(int rowNumber, Ref row) { int size = readers.size(); for (int i = 0; i < size; i++) { OneDReader* reader = readers[i]; - try { - return reader->decodeRow(rowNumber, row); - } catch (ReaderException re) { - // continue + Ref result = reader->decodeRow(rowNumber, row); + if (!result.empty()) { + return result; } } - throw ReaderException("No code detected"); + return Ref(); } } } diff --git a/cpp/core/src/zxing/oned/MultiFormatUPCEANReader.cpp b/cpp/core/src/zxing/oned/MultiFormatUPCEANReader.cpp index a11243c8..eaa7ed6c 100644 --- a/cpp/core/src/zxing/oned/MultiFormatUPCEANReader.cpp +++ b/cpp/core/src/zxing/oned/MultiFormatUPCEANReader.cpp @@ -2,7 +2,6 @@ * MultiFormatUPCEANReader.cpp * ZXing * - * Created by Lukasz Warchol on 10-01-25. * Copyright 2010 ZXing authors All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -30,7 +29,7 @@ namespace zxing { namespace oned { - + MultiFormatUPCEANReader::MultiFormatUPCEANReader(DecodeHints hints) : readers() { if (hints.containsFormat(BarcodeFormat_EAN_13)) { readers.push_back(Ref(new EAN13Reader())); @@ -51,17 +50,16 @@ namespace zxing { } } - Ref MultiFormatUPCEANReader::decodeRow(int rowNumber, Ref row){ + Ref MultiFormatUPCEANReader::decodeRow(int rowNumber, Ref row) { // Compute this location once and reuse it on multiple implementations int size = readers.size(); for (int i = 0; i < size; i++) { Ref reader = readers[i]; - Ref result; - try { - result = reader->decodeRow(rowNumber, row);//decodeRow(rowNumber, row, startGuardPattern); - } catch (ReaderException re) { - continue; + Ref result = reader->decodeRow(rowNumber, row); + if (result.empty()) { + continue; } + // Special case: a 12-digit code encoded in UPC-A is identical to a "0" // followed by those 12 digits encoded as EAN-13. Each will recognize such a code, // UPC-A as a 12-digit string and EAN-13 as a 13-digit string starting with "0". @@ -76,13 +74,14 @@ namespace zxing { const std::string& text = (result->getText())->getText(); if (text[0] == '0') { Ref resultString(new String(text.substr(1))); - Ref res(new Result(resultString, result->getRawBytes(), result->getResultPoints(), BarcodeFormat_UPC_A)); + Ref res(new Result(resultString, result->getRawBytes(), + result->getResultPoints(), BarcodeFormat_UPC_A)); return res; } } return result; } - throw ReaderException("No EAN code detected"); + return Ref(); } } } diff --git a/cpp/core/src/zxing/oned/OneDReader.cpp b/cpp/core/src/zxing/oned/OneDReader.cpp index 05f9a9bb..0ab71b70 100644 --- a/cpp/core/src/zxing/oned/OneDReader.cpp +++ b/cpp/core/src/zxing/oned/OneDReader.cpp @@ -2,7 +2,6 @@ * OneDReader.cpp * ZXing * - * Created by Lukasz Warchol on 10-01-15. * Copyright 2010 ZXing authors All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -27,17 +26,15 @@ namespace zxing { namespace oned { using namespace std; - + OneDReader::OneDReader() { } - - Ref OneDReader::decode(Ref image, DecodeHints hints) { + Ref OneDReader::decode(Ref image, DecodeHints hints) { try { return doDecode(image, hints); - }catch (ReaderException re) { + } catch (ReaderException re) { if (hints.getTryHarder() && image->isRotateSupported()) { - Ref rotatedImage(image->rotateCounterClockwise()); Ref result(doDecode(rotatedImage, hints)); /* @@ -63,8 +60,8 @@ namespace zxing { } } } - - Ref OneDReader::doDecode(Ref image, DecodeHints hints){ + + Ref OneDReader::doDecode(Ref image, DecodeHints hints) { int width = image->getWidth(); int height = image->getHeight(); Ref row(new BitArray(width)); @@ -77,9 +74,8 @@ namespace zxing { } else { maxLines = 15; // 15 rows spaced 1/32 apart is roughly the middle half of the image } - + for (int x = 0; x < maxLines; x++) { - // Scanning from the middle out. Determine which row we're looking at next: int rowStepsAboveOrBelow = (x + 1) >> 1; bool isAbove = (x & 0x01) == 0; // i.e. is x even? @@ -88,52 +84,49 @@ namespace zxing { // Oops, if we run off the top or bottom, stop break; } - + // Estimate black point for this row and load it: try { row = image->getBlackRow(rowNumber, row); - }catch (ReaderException re) { + } catch (ReaderException re) { continue; - }catch (IllegalArgumentException re) { + } catch (IllegalArgumentException re) { continue; } - + // While we have the image data in a BitArray, it's fairly cheap to reverse it in place to // handle decoding upside down barcodes. for (int attempt = 0; attempt < 2; attempt++) { if (attempt == 1) { // trying again? row->reverse(); // reverse the row and continue } - try { - // Look for a barcode - Ref result = decodeRow(rowNumber, row); - // We found our barcode - if (attempt == 1) { - // // But it was upside down, so note that - // result.putMetadata(ResultMetadataType.ORIENTATION, new Integer(180)); - // // And remember to flip the result points horizontally. - std::vector > points(result->getResultPoints()); - // if there's exactly two points (which there should be), flip the x coordinate - // if there's not exactly 2, I don't know what do do with it - if (points.size() == 2) { - Ref pointZero(new OneDResultPoint(width - points[0]->getX() - 1, points[0]->getY())); - points[0] = pointZero; - Ref pointOne(new OneDResultPoint(width - points[1]->getX() - 1, points[1]->getY())); - points[1] = pointOne; + // Look for a barcode + Ref result = decodeRow(rowNumber, row); + // We found our barcode + if (!result.empty()) { + // // But it was upside down, so note that + // result.putMetadata(ResultMetadataType.ORIENTATION, new Integer(180)); + // // And remember to flip the result points horizontally. + std::vector > points(result->getResultPoints()); + // if there's exactly two points (which there should be), flip the x coordinate + // if there's not exactly 2, I don't know what do do with it + if (points.size() == 2) { + Ref pointZero(new OneDResultPoint(width - points[0]->getX() - 1, points[0]->getY())); + points[0] = pointZero; - result.reset(new Result(result->getText(),result->getRawBytes(),points,result->getBarcodeFormat())); - } - } - return result; - } catch (ReaderException re) { - // continue -- just couldn't decode this row - } + Ref pointOne(new OneDResultPoint(width - points[1]->getX() - 1, points[1]->getY())); + points[1] = pointOne; + + result.reset(new Result(result->getText(),result->getRawBytes(),points,result->getBarcodeFormat())); + } + return result; + } } } throw ReaderException("doDecode() failed"); } - + unsigned int OneDReader::patternMatchVariance(int counters[], int countersSize, const int pattern[], int maxIndividualVariance) { int numCounters = countersSize; unsigned int total = 0; @@ -152,7 +145,7 @@ namespace zxing { // more "significant digits" unsigned int unitBarWidth = (total << INTEGER_MATH_SHIFT) / patternLength; maxIndividualVariance = (maxIndividualVariance * unitBarWidth) >> INTEGER_MATH_SHIFT; - + unsigned int totalVariance = 0; for (int x = 0; x < numCounters; x++) { int counter = counters[x] << INTEGER_MATH_SHIFT; @@ -165,7 +158,7 @@ namespace zxing { } return totalVariance / total; } - + void OneDReader::recordPattern(Ref row, int start, int counters[], int countersCount){ int numCounters = countersCount;//sizeof(counters) / sizeof(int); for (int i = 0; i < numCounters; i++) { @@ -199,7 +192,7 @@ namespace zxing { throw ReaderException("recordPattern"); } } - + OneDReader::~OneDReader() { } } diff --git a/cpp/core/src/zxing/oned/OneDReader.h b/cpp/core/src/zxing/oned/OneDReader.h index 14ee60b3..bace9a81 100644 --- a/cpp/core/src/zxing/oned/OneDReader.h +++ b/cpp/core/src/zxing/oned/OneDReader.h @@ -27,16 +27,20 @@ namespace zxing { class OneDReader : public Reader { private: static const int INTEGER_MATH_SHIFT = 8; - + Ref doDecode(Ref image, DecodeHints hints); public: static const int PATTERN_MATCH_RESULT_SCALE_FACTOR = 1 << INTEGER_MATH_SHIFT; - + OneDReader(); virtual Ref decode(Ref image, DecodeHints hints); + + // Implementations must not throw any exceptions. If a barcode is not found on this row, + // a empty ref should be returned e.g. return Ref(); virtual Ref decodeRow(int rowNumber, Ref row) = 0; - - static unsigned int patternMatchVariance(int counters[], int countersSize, const int pattern[], int maxIndividualVariance); + + static unsigned int patternMatchVariance(int counters[], int countersSize, + const int pattern[], int maxIndividualVariance); static void recordPattern(Ref row, int start, int counters[], int countersCount); virtual ~OneDReader(); }; diff --git a/cpp/core/src/zxing/oned/OneDResultPoint.cpp b/cpp/core/src/zxing/oned/OneDResultPoint.cpp index 0ac8dc3c..3e68b66a 100644 --- a/cpp/core/src/zxing/oned/OneDResultPoint.cpp +++ b/cpp/core/src/zxing/oned/OneDResultPoint.cpp @@ -2,7 +2,6 @@ * OneDResultPoint.cpp * ZXing * - * Created by Lukasz Warchol on 10-01-20. * Copyright 2010 ZXing authors All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -22,14 +21,14 @@ namespace zxing { namespace oned { - - OneDResultPoint::OneDResultPoint(float posX, float posY) : posX_(posX), posY_(posY){ + + OneDResultPoint::OneDResultPoint(float posX, float posY) : posX_(posX), posY_(posY) { } - + float OneDResultPoint::getX() const { return posX_; } - + float OneDResultPoint::getY() const { return posY_; } diff --git a/cpp/core/src/zxing/oned/UPCAReader.cpp b/cpp/core/src/zxing/oned/UPCAReader.cpp index 3638318f..e2075c13 100644 --- a/cpp/core/src/zxing/oned/UPCAReader.cpp +++ b/cpp/core/src/zxing/oned/UPCAReader.cpp @@ -2,7 +2,6 @@ * UPCAReader.cpp * ZXing * - * Created by Lukasz Warchol on 10-01-25. * Copyright 2010 ZXing authors All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -25,33 +24,38 @@ namespace zxing { namespace oned { UPCAReader::UPCAReader() : ean13Reader() { } - - Ref UPCAReader::decodeRow(int rowNumber, Ref row){ - return maybeReturnResult(ean13Reader.decodeRow(rowNumber, row)); + + Ref UPCAReader::decodeRow(int rowNumber, Ref row) { + return maybeReturnResult(ean13Reader.decodeRow(rowNumber, row)); } - Ref UPCAReader::decodeRow(int rowNumber, Ref row, int startGuardRange[]){ + + Ref UPCAReader::decodeRow(int rowNumber, Ref row, int startGuardRange[]) { return maybeReturnResult(ean13Reader.decodeRow(rowNumber, row, startGuardRange)); } - Ref UPCAReader::decode(Ref image, DecodeHints hints){ + + Ref UPCAReader::decode(Ref image, DecodeHints hints) { return maybeReturnResult(ean13Reader.decode(image, hints)); } - - int UPCAReader::decodeMiddle(Ref row, int startRange[], int startRangeLen, std::string& resultString){ + + int UPCAReader::decodeMiddle(Ref row, int startRange[], int startRangeLen, + std::string& resultString) { return ean13Reader.decodeMiddle(row, startRange, startRangeLen, resultString); } - - Ref UPCAReader::maybeReturnResult(Ref result){ + + Ref UPCAReader::maybeReturnResult(Ref result) { + if (result.empty()) { + return result; + } const std::string& text = (result->getText())->getText(); if (text[0] == '0') { Ref resultString(new String(text.substr(1))); - Ref res(new Result(resultString, result->getRawBytes(), result->getResultPoints(), BarcodeFormat_UPC_A)); + Ref res(new Result(resultString, result->getRawBytes(), result->getResultPoints(), + BarcodeFormat_UPC_A)); return res; - } else { - throw ReaderException("Not UPC-A barcode."); } + return Ref(); } - BarcodeFormat UPCAReader::getBarcodeFormat(){ return BarcodeFormat_UPC_A; } diff --git a/cpp/core/src/zxing/oned/UPCEANReader.cpp b/cpp/core/src/zxing/oned/UPCEANReader.cpp index 133bd476..cec13e46 100644 --- a/cpp/core/src/zxing/oned/UPCEANReader.cpp +++ b/cpp/core/src/zxing/oned/UPCEANReader.cpp @@ -2,7 +2,6 @@ * UPCEANReader.cpp * ZXing * - * Created by Lukasz Warchol on 10-01-21. * Copyright 2010 ZXing authors All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -21,20 +20,21 @@ #include "UPCEANReader.h" #include #include + 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. */ @@ -52,7 +52,7 @@ namespace zxing { {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. */ @@ -80,19 +80,20 @@ namespace zxing { {3, 1, 2, 1}, // 18 reversed 8 {2, 1, 1, 3} // 19 reversed 9 }; - - const int UPCEANReader::getMIDDLE_PATTERN_LEN(){ + + const int UPCEANReader::getMIDDLE_PATTERN_LEN() { return MIDDLE_PATTERN_LEN; } - const int* UPCEANReader::getMIDDLE_PATTERN(){ + + const int* UPCEANReader::getMIDDLE_PATTERN() { return MIDDLE_PATTERN; } - - UPCEANReader::UPCEANReader(){ + + UPCEANReader::UPCEANReader() { } - - + + Ref UPCEANReader::decodeRow(int rowNumber, Ref row) { int* start = NULL; try { @@ -102,22 +103,21 @@ namespace zxing { return result; } catch (ReaderException const& re) { delete [] start; - throw re; + return Ref(); } } - - Ref UPCEANReader::decodeRow(int rowNumber, Ref row, int startGuardRange[]){ + + Ref UPCEANReader::decodeRow(int rowNumber, Ref row, int startGuardRange[]) { int* endRange = NULL; try { std::string tmpResultString; std::string& tmpResultStringRef = tmpResultString; - int endStart; - endStart = decodeMiddle(row, startGuardRange, 2 /*reference findGuardPattern*/ , tmpResultStringRef); - + int 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. + + // 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)) { @@ -127,20 +127,20 @@ namespace zxing { if (!checkChecksum(tmpResultString)) { throw ReaderException("Checksum fail."); } - + Ref 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 > resultPoints(2); Ref resultPoint1(new OneDResultPoint(left, (float) rowNumber)); Ref resultPoint2(new OneDResultPoint(right, (float) rowNumber)); resultPoints[0] = resultPoint1; resultPoints[1] = resultPoint2; - + ArrayRef resultBytes(1); - + Ref res(new Result(resultString, resultBytes, resultPoints, getBarcodeFormat())); delete [] endRange; return res; @@ -148,19 +148,18 @@ namespace zxing { delete [] endRange; throw re; } - } - - int* UPCEANReader::findStartGuardPattern(Ref row){ + + int* UPCEANReader::findStartGuardPattern(Ref 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)); + 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. @@ -177,9 +176,10 @@ namespace zxing { throw re; } } - + // TODO(flyashi): Return a pair for return value to avoid using the heap. - int* UPCEANReader::findGuardPattern(Ref row, int rowOffset, bool whiteFirst, const int pattern[], int patternLen){ + int* UPCEANReader::findGuardPattern(Ref row, int rowOffset, bool whiteFirst, + const int pattern[], int patternLen) { int patternLength = patternLen; int counters[patternLength]; int countersCount = sizeof(counters) / sizeof(int); @@ -195,7 +195,7 @@ namespace zxing { } rowOffset++; } - + int counterPosition = 0; int patternStart = rowOffset; for (int x = rowOffset; x < width; x++) { @@ -204,7 +204,8 @@ namespace zxing { counters[counterPosition]++; } else { if (counterPosition == patternLength - 1) { - if (patternMatchVariance(counters, countersCount, pattern, MAX_INDIVIDUAL_VARIANCE) < MAX_AVG_VARIANCE) { + if (patternMatchVariance(counters, countersCount, pattern, + MAX_INDIVIDUAL_VARIANCE) < MAX_AVG_VARIANCE) { int* resultValue = new int[2]; resultValue[0] = patternStart; resultValue[1] = x; @@ -226,17 +227,19 @@ namespace zxing { } throw ReaderException("findGuardPattern"); } - - int* UPCEANReader::decodeEnd(Ref row, int endStart){ - return findGuardPattern(row, endStart, false, START_END_PATTERN, sizeof(START_END_PATTERN)/sizeof(int)); + + int* UPCEANReader::decodeEnd(Ref row, int endStart) { + return findGuardPattern(row, endStart, false, START_END_PATTERN, + sizeof(START_END_PATTERN) / sizeof(int)); } - -// int UPCEANReader::decodeDigit(Ref row, int counters[], int countersLen, int rowOffset, int** patterns/*[][]*/, int paterns1Len, int paterns2Len) - int UPCEANReader::decodeDigit(Ref row, int counters[], int countersLen, int rowOffset, UPC_EAN_PATTERNS patternType){ + +// int UPCEANReader::decodeDigit(Ref row, int counters[], int countersLen, int rowOffset, int** patterns/*[][]*/, int paterns1Len, int paterns2Len) + int UPCEANReader::decodeDigit(Ref 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: @@ -246,8 +249,9 @@ namespace zxing { for(int j = 0; j< countersLen; j++){ pattern[j] = L_PATTERNS[i][j]; } - - unsigned int variance = patternMatchVariance(counters, countersLen, pattern, MAX_INDIVIDUAL_VARIANCE); + + unsigned int variance = patternMatchVariance(counters, countersLen, pattern, + MAX_INDIVIDUAL_VARIANCE); if (variance < bestVariance) { bestVariance = variance; bestMatch = i; @@ -261,8 +265,9 @@ namespace zxing { 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); + + unsigned int variance = patternMatchVariance(counters, countersLen, pattern, + MAX_INDIVIDUAL_VARIANCE); if (variance < bestVariance) { bestVariance = variance; bestMatch = i; @@ -278,15 +283,15 @@ namespace zxing { throw ReaderException("UPCEANReader::decodeDigit: No best mach"); } } - - + + /** * @return {@link #checkStandardUPCEANChecksum(String)} */ - bool UPCEANReader::checkChecksum(std::string s){ + 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. @@ -295,12 +300,12 @@ namespace zxing { * @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){ + 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'; @@ -319,7 +324,8 @@ namespace zxing { } return sum % 10 == 0; } - UPCEANReader::~UPCEANReader(){ + + UPCEANReader::~UPCEANReader() { } } } diff --git a/cpp/core/src/zxing/oned/UPCEReader.cpp b/cpp/core/src/zxing/oned/UPCEReader.cpp index fdea388f..ad12c257 100644 --- a/cpp/core/src/zxing/oned/UPCEReader.cpp +++ b/cpp/core/src/zxing/oned/UPCEReader.cpp @@ -2,7 +2,6 @@ * UPCEReader.cpp * ZXing * - * Created by Lukasz Warchol on 10-01-26. * Copyright 2010 ZXing authors All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -23,13 +22,13 @@ namespace zxing { namespace oned { - + /** * The pattern that marks the middle, and end, of a UPC-E pattern. * There is no "second half" to a UPC-E barcode. */ static const int MIDDLE_END_PATTERN[6] = {1, 1, 1, 1, 1, 1}; - + /** * See {@link #L_AND_G_PATTERNS}; these values similarly represent patterns of * even-odd parity encodings of digits that imply both the number system (0 or 1) @@ -39,20 +38,23 @@ namespace zxing { {0x38, 0x34, 0x32, 0x31, 0x2C, 0x26, 0x23, 0x2A, 0x29, 0x25}, {0x07, 0x0B, 0x0D, 0x0E, 0x13, 0x19, 0x1C, 0x15, 0x16, 0x1A} }; - - UPCEReader::UPCEReader(){} - - int UPCEReader::decodeMiddle(Ref row, int startRange[], int startRangeLen, std::string& resultString){ + + UPCEReader::UPCEReader() { + } + + int UPCEReader::decodeMiddle(Ref row, int startRange[], int startRangeLen, + std::string& resultString) { const int countersLen = 4; int counters[countersLen] = { 0, 0, 0, 0 }; - + int end = row->getSize(); int rowOffset = startRange[1]; - + int lgPatternFound = 0; - + for (int x = 0; x < 6 && rowOffset < end; x++) { - int bestMatch = decodeDigit(row, counters, countersLen, rowOffset, UPC_EAN_PATTERNS_L_AND_G_PATTERNS); + int bestMatch = decodeDigit(row, counters, countersLen, rowOffset, + UPC_EAN_PATTERNS_L_AND_G_PATTERNS); resultString.append(1, (char) ('0' + bestMatch % 10)); for (int i = 0; i < countersLen; i++) { rowOffset += counters[i]; @@ -61,22 +63,23 @@ namespace zxing { lgPatternFound |= 1 << (5 - x); } } - + determineNumSysAndCheckDigit(resultString, lgPatternFound); - + return rowOffset; } - - int* UPCEReader::decodeEnd(Ref row, int endStart){ - return findGuardPattern(row, endStart, true, MIDDLE_END_PATTERN, sizeof(MIDDLE_END_PATTERN)/sizeof(int)); + + int* UPCEReader::decodeEnd(Ref row, int endStart) { + return findGuardPattern(row, endStart, true, MIDDLE_END_PATTERN, + sizeof(MIDDLE_END_PATTERN) / sizeof(int)); } - + bool UPCEReader::checkChecksum(std::string s){ return UPCEANReader::checkChecksum(convertUPCEtoUPCA(s)); } - - - void UPCEReader::determineNumSysAndCheckDigit(std::string& resultString, int lgPatternFound){ + + + void UPCEReader::determineNumSysAndCheckDigit(std::string& resultString, int lgPatternFound) { for (int numSys = 0; numSys <= 1; numSys++) { for (int d = 0; d < 10; d++) { if (lgPatternFound == NUMSYS_AND_CHECK_DIGIT_PATTERNS[numSys][d]) { @@ -88,7 +91,7 @@ namespace zxing { } throw ReaderException("determineNumSysAndCheckDigit exception"); } - + /** * Expands a UPC-E value back into its full, equivalent UPC-A code value. * @@ -127,9 +130,9 @@ namespace zxing { result.append(1, upce[7]); return result; } - - - BarcodeFormat UPCEReader::getBarcodeFormat(){ + + + BarcodeFormat UPCEReader::getBarcodeFormat() { return BarcodeFormat_UPC_E; } }