return x == 0 ? object_ != 0 : true;
}
+ bool empty() const {
+ return object_ == 0;
+ }
+
template<class Y>
friend std::ostream& operator<<(std::ostream &out, Ref<Y>& ref);
};
* 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");
namespace zxing {
namespace oned {
-
+
const int CODE_PATTERNS_LENGTH = 107;
const int countersLength = 6;
static const int CODE_PATTERNS[CODE_PATTERNS_LENGTH][countersLength] = {
{2, 1, 1, 2, 3, 2}, /* 105 */
{2, 3, 3, 1, 1, 1}
};
-
-
+
+
Code128Reader::Code128Reader(){
}
-
+
int* Code128Reader::findStartPattern(Ref<BitArray> row){
int width = row->getSize();
int rowOffset = 0;
}
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) {
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;
}
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;
}
throw ReaderException("");
}
-
- int Code128Reader::decodeCode(Ref<BitArray> row, int counters[], int countersCount, int rowOffset){
+
+ int Code128Reader::decodeCode(Ref<BitArray> 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;
throw ReaderException("");
}
}
-
- Ref<Result> Code128Reader::decodeRow(int rowNumber, Ref<BitArray> 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<String> resultString(new String(tmpResultString));
-// String resultString(tmpResultString);
-
- if (tmpResultString.length() == 0) {
- delete [] startPatternInfo;
- // Almost surely a false positive
- throw ReaderException("");
+
+ Ref<Result> Code128Reader::decodeRow(int rowNumber, Ref<BitArray> 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<String> 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<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;
+
+ delete [] startPatternInfo;
+ ArrayRef<unsigned char> resultBytes(1);
+ return Ref<Result>(new Result(resultString, resultBytes, resultPoints,
+ BarcodeFormat_CODE_128));
+ } catch (ReaderException const& re) {
+ delete [] startPatternInfo;
+ return Ref<Result>();
}
-
- float left = (float) (startPatternInfo[1] + startPatternInfo[0]) / 2.0f;
- float right = (float) (nextStart + lastStart) / 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);
-
- delete [] startPatternInfo;
- startPatternInfo = NULL;
-
- Ref<Result> 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(){
}
}
* 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");
* 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<Result> Code39Reader::decodeRow(int rowNumber, Ref<BitArray> row){
+ Ref<Result> Code39Reader::decodeRow(int rowNumber, Ref<BitArray> row) {
int* start = NULL;
try {
start = findAsteriskPattern(row);
return res;
} catch (ReaderException const& re) {
delete [] start;
- throw re;
+ return Ref<Result>();
}
}
* 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");
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<BitArray> row, int startRange[], int startRangeLen, std::string& resultString){
+
+ int EAN13Reader::decodeMiddle(Ref<BitArray> 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];
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));
}
throw ReaderException("determineFirstDigit");
}
-
+
BarcodeFormat EAN13Reader::getBarcodeFormat(){
return BarcodeFormat_EAN_13;
}
* 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");
namespace zxing {
namespace oned {
-
+
EAN8Reader::EAN8Reader(){ }
-
- int EAN8Reader::decodeMiddle(Ref<BitArray> row, int startRange[], int startRangeLen, std::string& resultString){
+
+ int EAN8Reader::decodeMiddle(Ref<BitArray> 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;
}
* 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");
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.
*
*/
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
*/
{W, N, N, W, N}, // 8
{N, W, N, W, N} // 9
};
-
-
+
+
ITFReader::ITFReader() : narrowLineWidth(-1) {
}
-
-
- Ref<Result> ITFReader::decodeRow(int rowNumber, Ref<BitArray> row){
- int* startRange = 0;
+
+
+ Ref<Result> ITFReader::decodeRow(int rowNumber, Ref<BitArray> 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<String> resultString(new String(tmpResult));
-
- std::vector< Ref<ResultPoint> > resultPoints(2);
- Ref<OneDResultPoint> resultPoint1(new OneDResultPoint(startRange[1], (float) rowNumber));
- Ref<OneDResultPoint> resultPoint2(new OneDResultPoint(endRange[0], (float) rowNumber));
- resultPoints[0] = resultPoint1;
- resultPoints[1] = resultPoint2;
-
- ArrayRef<unsigned char> resultBytes(1);
-
- Ref<Result> 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<String> resultString(new String(tmpResult));
+
+ std::vector< Ref<ResultPoint> > resultPoints(2);
+ Ref<OneDResultPoint> resultPoint1(new OneDResultPoint(startRange[1], (float) rowNumber));
+ Ref<OneDResultPoint> resultPoint2(new OneDResultPoint(endRange[0], (float) rowNumber));
+ resultPoints[0] = resultPoint1;
+ resultPoints[1] = resultPoint2;
+
+ delete [] startRange;
+ delete [] endRange;
+ ArrayRef<unsigned char> resultBytes(1);
+ return Ref<Result>(new Result(resultString, resultBytes, resultPoints, BarcodeFormat_ITF));
} catch (ReaderException re) {
delete [] startRange;
delete [] endRange;
- throw re;
+ return Ref<Result>();
}
}
-
+
/**
* @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<BitArray> row, int payloadStart, int payloadEnd, std::string& resultString){
+ void ITFReader::decodeMiddle(Ref<BitArray> 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.
for (int i=0; i<counterDigitPairLen; i++) {
counterDigitPair[i] = 0;
}
-
+
int counterBlack[5];
int counterWhite[5];
for (int i=0; i<5; i++) {
counterBlack[i] = 0;
counterWhite[i] = 0;
}
-
+
while (payloadStart < payloadEnd) {
// Get 10 runs of black/white.
recordPattern(row, payloadStart, counterDigitPair, counterDigitPairLen);
counterBlack[k] = counterDigitPair[twoK];
counterWhite[k] = counterDigitPair[twoK + 1];
}
-
+
int bestMatch = decodeDigit(counterBlack, 5);
resultString.append(1, (char) ('0' + bestMatch));
bestMatch = decodeDigit(counterWhite, 5);
resultString.append(1, (char) ('0' + bestMatch));
-
+
for (int i = 0; i < counterDigitPairLen; i++) {
payloadStart += counterDigitPair[i];
}
}
}
-
+
/**
* Identify where the start of the middle / payload section starts.
*
* 'start block'
* @throws ReaderException
*/
- int* ITFReader::decodeStart(Ref<BitArray> row){
+ int* ITFReader::decodeStart(Ref<BitArray> row) {
int endStart = skipWhiteSpace(row);
-/// static int* findGuardPattern(Ref<BitArray> 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.
*
* block'
* @throws ReaderException
*/
-
- int* ITFReader::decodeEnd(Ref<BitArray> row){
+
+ int* ITFReader::decodeEnd(Ref<BitArray> row) {
// For convenience, reverse the row and then
// search from 'the start' for the end block
row->reverse();
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
* @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<BitArray> row, int startPattern){
+ void ITFReader::validateQuietZone(Ref<BitArray> 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;
// throw ReaderException("Unable to find the necessary number of quiet zone pixels");
// }
}
-
+
/**
* Skip all whitespace until we get to the first black line.
*
* @return index of the first black line.
* @throws ReaderException Throws exception if no black lines are found in the row
*/
- int ITFReader::skipWhiteSpace(Ref<BitArray> row){
+ int ITFReader::skipWhiteSpace(Ref<BitArray> row) {
int width = row->getSize();
int endStart = 0;
while (endStart < width) {
}
return endStart;
}
-
+
/**
* @param row row of black/white values to search
* @param rowOffset position to start search
* ints
* @throws ReaderException if pattern is not found
*/
-
- int* ITFReader::findGuardPattern(Ref<BitArray> row, int rowOffset, const int pattern[], int patternLen){
+ int* ITFReader::findGuardPattern(Ref<BitArray> 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;
}
int width = row->getSize();
bool isWhite = false;
-
+
int counterPosition = 0;
int patternStart = rowOffset;
for (int x = rowOffset; x < width; x++) {
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;
}
throw ReaderException("");
}
-
+
/**
* Attempts to decode a sequence of ITF black/white lines into single
* digit.
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<countersLen; ind++){
pattern[ind] = PATTERNS[i][ind];
}
- 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;
throw ReaderException("digit didint found");
}
}
-
-
+
ITFReader::~ITFReader(){
}
}
* MultiFormatOneDReader.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");
readers.push_back(Ref<OneDReader>(new ITFReader()));
}
}
-
- Ref<Result> MultiFormatOneDReader::decodeRow(int rowNumber, Ref<BitArray> row){
+
+ Ref<Result> MultiFormatOneDReader::decodeRow(int rowNumber, Ref<BitArray> 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> result = reader->decodeRow(rowNumber, row);
+ if (!result.empty()) {
+ return result;
}
}
- throw ReaderException("No code detected");
+ return Ref<Result>();
}
}
}
* 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");
namespace zxing {
namespace oned {
-
+
MultiFormatUPCEANReader::MultiFormatUPCEANReader(DecodeHints hints) : readers() {
if (hints.containsFormat(BarcodeFormat_EAN_13)) {
readers.push_back(Ref<OneDReader>(new EAN13Reader()));
}
}
- Ref<Result> MultiFormatUPCEANReader::decodeRow(int rowNumber, Ref<BitArray> row){
+ Ref<Result> MultiFormatUPCEANReader::decodeRow(int rowNumber, Ref<BitArray> row) {
// Compute this location once and reuse it on multiple implementations
int size = readers.size();
for (int i = 0; i < size; i++) {
Ref<OneDReader> reader = readers[i];
- Ref<Result> result;
- try {
- result = reader->decodeRow(rowNumber, row);//decodeRow(rowNumber, row, startGuardPattern);
- } catch (ReaderException re) {
- continue;
+ Ref<Result> 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".
const std::string& text = (result->getText())->getText();
if (text[0] == '0') {
Ref<String> resultString(new String(text.substr(1)));
- Ref<Result> res(new Result(resultString, result->getRawBytes(), result->getResultPoints(), BarcodeFormat_UPC_A));
+ Ref<Result> res(new Result(resultString, result->getRawBytes(),
+ result->getResultPoints(), BarcodeFormat_UPC_A));
return res;
}
}
return result;
}
- throw ReaderException("No EAN code detected");
+ return Ref<Result>();
}
}
}
* 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");
namespace zxing {
namespace oned {
using namespace std;
-
+
OneDReader::OneDReader() {
}
-
- Ref<Result> OneDReader::decode(Ref<BinaryBitmap> image, DecodeHints hints) {
+ Ref<Result> OneDReader::decode(Ref<BinaryBitmap> image, DecodeHints hints) {
try {
return doDecode(image, hints);
- }catch (ReaderException re) {
+ } catch (ReaderException re) {
if (hints.getTryHarder() && image->isRotateSupported()) {
-
Ref<BinaryBitmap> rotatedImage(image->rotateCounterClockwise());
Ref<Result> result(doDecode(rotatedImage, hints));
/*
}
}
}
-
- Ref<Result> OneDReader::doDecode(Ref<BinaryBitmap> image, DecodeHints hints){
+
+ Ref<Result> OneDReader::doDecode(Ref<BinaryBitmap> image, DecodeHints hints) {
int width = image->getWidth();
int height = image->getHeight();
Ref<BitArray> row(new BitArray(width));
} 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?
// 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> 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<Ref<ResultPoint> > 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<ResultPoint> pointZero(new OneDResultPoint(width - points[0]->getX() - 1, points[0]->getY()));
- points[0] = pointZero;
- Ref<ResultPoint> pointOne(new OneDResultPoint(width - points[1]->getX() - 1, points[1]->getY()));
- points[1] = pointOne;
+ // Look for a barcode
+ Ref<Result> 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<Ref<ResultPoint> > 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<ResultPoint> 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<ResultPoint> 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;
// 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;
}
return totalVariance / total;
}
-
+
void OneDReader::recordPattern(Ref<BitArray> row, int start, int counters[], int countersCount){
int numCounters = countersCount;//sizeof(counters) / sizeof(int);
for (int i = 0; i < numCounters; i++) {
throw ReaderException("recordPattern");
}
}
-
+
OneDReader::~OneDReader() {
}
}
class OneDReader : public Reader {
private:
static const int INTEGER_MATH_SHIFT = 8;
-
+
Ref<Result> doDecode(Ref<BinaryBitmap> image, DecodeHints hints);
public:
static const int PATTERN_MATCH_RESULT_SCALE_FACTOR = 1 << INTEGER_MATH_SHIFT;
-
+
OneDReader();
virtual Ref<Result> decode(Ref<BinaryBitmap> 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<Result>();
virtual Ref<Result> decodeRow(int rowNumber, Ref<BitArray> 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<BitArray> row, int start, int counters[], int countersCount);
virtual ~OneDReader();
};
* 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");
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_;
}
* 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");
namespace oned {
UPCAReader::UPCAReader() : ean13Reader() {
}
-
- Ref<Result> UPCAReader::decodeRow(int rowNumber, Ref<BitArray> row){
- return maybeReturnResult(ean13Reader.decodeRow(rowNumber, row));
+
+ Ref<Result> UPCAReader::decodeRow(int rowNumber, Ref<BitArray> row) {
+ return maybeReturnResult(ean13Reader.decodeRow(rowNumber, row));
}
- Ref<Result> UPCAReader::decodeRow(int rowNumber, Ref<BitArray> row, int startGuardRange[]){
+
+ Ref<Result> UPCAReader::decodeRow(int rowNumber, Ref<BitArray> row, int startGuardRange[]) {
return maybeReturnResult(ean13Reader.decodeRow(rowNumber, row, startGuardRange));
}
- Ref<Result> UPCAReader::decode(Ref<BinaryBitmap> image, DecodeHints hints){
+
+ Ref<Result> UPCAReader::decode(Ref<BinaryBitmap> image, DecodeHints hints) {
return maybeReturnResult(ean13Reader.decode(image, hints));
}
-
- int UPCAReader::decodeMiddle(Ref<BitArray> row, int startRange[], int startRangeLen, std::string& resultString){
+
+ int UPCAReader::decodeMiddle(Ref<BitArray> row, int startRange[], int startRangeLen,
+ std::string& resultString) {
return ean13Reader.decodeMiddle(row, startRange, startRangeLen, resultString);
}
-
- Ref<Result> UPCAReader::maybeReturnResult(Ref<Result> result){
+
+ Ref<Result> UPCAReader::maybeReturnResult(Ref<Result> result) {
+ if (result.empty()) {
+ return result;
+ }
const std::string& text = (result->getText())->getText();
if (text[0] == '0') {
Ref<String> resultString(new String(text.substr(1)));
- Ref<Result> res(new Result(resultString, result->getRawBytes(), result->getResultPoints(), BarcodeFormat_UPC_A));
+ Ref<Result> res(new Result(resultString, result->getRawBytes(), result->getResultPoints(),
+ BarcodeFormat_UPC_A));
return res;
- } else {
- throw ReaderException("Not UPC-A barcode.");
}
+ return Ref<Result>();
}
-
BarcodeFormat UPCAReader::getBarcodeFormat(){
return BarcodeFormat_UPC_A;
}
* 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");
#include "UPCEANReader.h"
#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.
*/
{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.
*/
{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<Result> UPCEANReader::decodeRow(int rowNumber, Ref<BitArray> row) {
int* start = NULL;
try {
return result;
} catch (ReaderException const& re) {
delete [] start;
- throw re;
+ return Ref<Result>();
}
}
-
- Ref<Result> UPCEANReader::decodeRow(int rowNumber, Ref<BitArray> row, int startGuardRange[]){
+
+ 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);
-
+ 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)) {
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;
delete [] endRange;
throw re;
}
-
}
-
- int* UPCEANReader::findStartGuardPattern(Ref<BitArray> row){
+
+ 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));
+ 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.
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* 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);
}
rowOffset++;
}
-
+
int counterPosition = 0;
int patternStart = rowOffset;
for (int x = rowOffset; x < width; x++) {
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;
}
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::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){
+
+// 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:
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;
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;
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.
* @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';
}
return sum % 10 == 0;
}
- UPCEANReader::~UPCEANReader(){
+
+ UPCEANReader::~UPCEANReader() {
}
}
}
* 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");
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)
{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<BitArray> row, int startRange[], int startRangeLen, std::string& resultString){
+
+ UPCEReader::UPCEReader() {
+ }
+
+ int UPCEReader::decodeMiddle(Ref<BitArray> 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];
lgPatternFound |= 1 << (5 - x);
}
}
-
+
determineNumSysAndCheckDigit(resultString, lgPatternFound);
-
+
return rowOffset;
}
-
- int* UPCEReader::decodeEnd(Ref<BitArray> row, int endStart){
- return findGuardPattern(row, endStart, true, MIDDLE_END_PATTERN, sizeof(MIDDLE_END_PATTERN)/sizeof(int));
+
+ int* UPCEReader::decodeEnd(Ref<BitArray> 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]) {
}
throw ReaderException("determineNumSysAndCheckDigit exception");
}
-
+
/**
* Expands a UPC-E value back into its full, equivalent UPC-A code value.
*
result.append(1, upce[7]);
return result;
}
-
-
- BarcodeFormat UPCEReader::getBarcodeFormat(){
+
+
+ BarcodeFormat UPCEReader::getBarcodeFormat() {
return BarcodeFormat_UPC_E;
}
}