mirror of
https://github.com/zxing/zxing.git
synced 2025-03-05 20:48:51 -08:00
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: https://zxing.googlecode.com/svn/trunk@1527 59b500cc-1b3d-0410-9834-0bbf25fbcc57
This commit is contained in:
parent
073a3033fc
commit
56ad5f5554
|
@ -193,6 +193,10 @@ public:
|
||||||
return x == 0 ? object_ != 0 : true;
|
return x == 0 ? object_ != 0 : true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool empty() const {
|
||||||
|
return object_ == 0;
|
||||||
|
}
|
||||||
|
|
||||||
template<class Y>
|
template<class Y>
|
||||||
friend std::ostream& operator<<(std::ostream &out, Ref<Y>& ref);
|
friend std::ostream& operator<<(std::ostream &out, Ref<Y>& ref);
|
||||||
};
|
};
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
* Code128Reader.cpp
|
* Code128Reader.cpp
|
||||||
* ZXing
|
* ZXing
|
||||||
*
|
*
|
||||||
* Created by Lukasz Warchol on 10-01-15.
|
|
||||||
* Copyright 2010 ZXing authors All rights reserved.
|
* Copyright 2010 ZXing authors All rights reserved.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
@ -28,7 +27,7 @@
|
||||||
|
|
||||||
namespace zxing {
|
namespace zxing {
|
||||||
namespace oned {
|
namespace oned {
|
||||||
|
|
||||||
const int CODE_PATTERNS_LENGTH = 107;
|
const int CODE_PATTERNS_LENGTH = 107;
|
||||||
const int countersLength = 6;
|
const int countersLength = 6;
|
||||||
static const int CODE_PATTERNS[CODE_PATTERNS_LENGTH][countersLength] = {
|
static const int CODE_PATTERNS[CODE_PATTERNS_LENGTH][countersLength] = {
|
||||||
|
@ -140,11 +139,11 @@ namespace zxing {
|
||||||
{2, 1, 1, 2, 3, 2}, /* 105 */
|
{2, 1, 1, 2, 3, 2}, /* 105 */
|
||||||
{2, 3, 3, 1, 1, 1}
|
{2, 3, 3, 1, 1, 1}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
Code128Reader::Code128Reader(){
|
Code128Reader::Code128Reader(){
|
||||||
}
|
}
|
||||||
|
|
||||||
int* Code128Reader::findStartPattern(Ref<BitArray> row){
|
int* Code128Reader::findStartPattern(Ref<BitArray> row){
|
||||||
int width = row->getSize();
|
int width = row->getSize();
|
||||||
int rowOffset = 0;
|
int rowOffset = 0;
|
||||||
|
@ -154,13 +153,13 @@ namespace zxing {
|
||||||
}
|
}
|
||||||
rowOffset++;
|
rowOffset++;
|
||||||
}
|
}
|
||||||
|
|
||||||
int counterPosition = 0;
|
int counterPosition = 0;
|
||||||
int counters[countersLength] = {0,0,0,0,0,0};
|
int counters[countersLength] = {0,0,0,0,0,0};
|
||||||
int patternStart = rowOffset;
|
int patternStart = rowOffset;
|
||||||
bool isWhite = false;
|
bool isWhite = false;
|
||||||
int patternLength = sizeof(counters) / sizeof(int);
|
int patternLength = sizeof(counters) / sizeof(int);
|
||||||
|
|
||||||
for (int i = rowOffset; i < width; i++) {
|
for (int i = rowOffset; i < width; i++) {
|
||||||
bool pixel = row->get(i);
|
bool pixel = row->get(i);
|
||||||
if (pixel ^ isWhite) {
|
if (pixel ^ isWhite) {
|
||||||
|
@ -170,7 +169,8 @@ namespace zxing {
|
||||||
unsigned int bestVariance = MAX_AVG_VARIANCE;
|
unsigned int bestVariance = MAX_AVG_VARIANCE;
|
||||||
int bestMatch = -1;
|
int bestMatch = -1;
|
||||||
for (int startCode = CODE_START_A; startCode <= CODE_START_C; startCode++) {
|
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) {
|
if (variance < bestVariance) {
|
||||||
bestVariance = variance;
|
bestVariance = variance;
|
||||||
bestMatch = startCode;
|
bestMatch = startCode;
|
||||||
|
@ -178,7 +178,8 @@ namespace zxing {
|
||||||
}
|
}
|
||||||
if (bestMatch >= 0) {
|
if (bestMatch >= 0) {
|
||||||
// Look for whitespace before start pattern, >= 50% of width of start pattern
|
// 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];
|
int* resultValue = new int[3];
|
||||||
resultValue[0] = patternStart;
|
resultValue[0] = patternStart;
|
||||||
resultValue[1] = i;
|
resultValue[1] = i;
|
||||||
|
@ -202,19 +203,21 @@ namespace zxing {
|
||||||
}
|
}
|
||||||
throw ReaderException("");
|
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);
|
recordPattern(row, rowOffset, counters, countersCount);
|
||||||
unsigned int bestVariance = MAX_AVG_VARIANCE; // worst variance we'll accept
|
unsigned int bestVariance = MAX_AVG_VARIANCE; // worst variance we'll accept
|
||||||
int bestMatch = -1;
|
int bestMatch = -1;
|
||||||
for (int d = 0; d < CODE_PATTERNS_LENGTH; d++) {
|
for (int d = 0; d < CODE_PATTERNS_LENGTH; d++) {
|
||||||
int pattern[countersLength];
|
int pattern[countersLength];
|
||||||
|
|
||||||
for(int ind = 0; ind< countersLength; ind++){
|
for(int ind = 0; ind< countersLength; ind++){
|
||||||
pattern[ind] = CODE_PATTERNS[d][ind];
|
pattern[ind] = CODE_PATTERNS[d][ind];
|
||||||
}
|
}
|
||||||
// memcpy(pattern, CODE_PATTERNS[d], countersLength);
|
// 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) {
|
if (variance < bestVariance) {
|
||||||
bestVariance = variance;
|
bestVariance = variance;
|
||||||
bestMatch = d;
|
bestMatch = d;
|
||||||
|
@ -227,265 +230,258 @@ namespace zxing {
|
||||||
throw ReaderException("");
|
throw ReaderException("");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ref<Result> Code128Reader::decodeRow(int rowNumber, Ref<BitArray> row){
|
Ref<Result> Code128Reader::decodeRow(int rowNumber, Ref<BitArray> row) {
|
||||||
|
int* startPatternInfo = NULL;
|
||||||
int* startPatternInfo = findStartPattern(row);
|
try {
|
||||||
int startCode = startPatternInfo[2];
|
startPatternInfo = findStartPattern(row);
|
||||||
int codeSet;
|
int startCode = startPatternInfo[2];
|
||||||
switch (startCode) {
|
int codeSet;
|
||||||
case CODE_START_A:
|
switch (startCode) {
|
||||||
codeSet = CODE_CODE_A;
|
case CODE_START_A:
|
||||||
break;
|
codeSet = CODE_CODE_A;
|
||||||
case CODE_START_B:
|
break;
|
||||||
codeSet = CODE_CODE_B;
|
case CODE_START_B:
|
||||||
break;
|
codeSet = CODE_CODE_B;
|
||||||
case CODE_START_C:
|
break;
|
||||||
codeSet = CODE_CODE_C;
|
case CODE_START_C:
|
||||||
break;
|
codeSet = CODE_CODE_C;
|
||||||
default:
|
break;
|
||||||
delete [] startPatternInfo;
|
default:
|
||||||
throw ReaderException("");
|
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>();
|
||||||
}
|
}
|
||||||
|
|
||||||
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("");
|
|
||||||
}
|
|
||||||
|
|
||||||
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){
|
void Code128Reader::append(char* s, char c){
|
||||||
int len = strlen(s);
|
int len = strlen(s);
|
||||||
s[len] = c;
|
s[len] = c;
|
||||||
s[len + 1] = '\0';
|
s[len + 1] = '\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
Code128Reader::~Code128Reader(){
|
Code128Reader::~Code128Reader(){
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
* Code39Reader.cpp
|
* Code39Reader.cpp
|
||||||
* ZXing
|
* ZXing
|
||||||
*
|
*
|
||||||
* Created by Lukasz Warchol on 10-01-26.
|
|
||||||
* Copyright 2010 ZXing authors All rights reserved.
|
* Copyright 2010 ZXing authors All rights reserved.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* 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.
|
* digit, not data, and verify that the checksum passes.
|
||||||
*/
|
*/
|
||||||
Code39Reader::Code39Reader(bool usingCheckDigit_) :
|
Code39Reader::Code39Reader(bool usingCheckDigit_) :
|
||||||
alphabet_string(ALPHABET_STRING),
|
alphabet_string(ALPHABET_STRING),
|
||||||
usingCheckDigit(usingCheckDigit_),
|
usingCheckDigit(usingCheckDigit_),
|
||||||
extendedMode(false) {
|
extendedMode(false) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Code39Reader::Code39Reader(bool usingCheckDigit_, bool extendedMode_) :
|
Code39Reader::Code39Reader(bool usingCheckDigit_, bool extendedMode_) :
|
||||||
alphabet_string(ALPHABET_STRING),
|
alphabet_string(ALPHABET_STRING),
|
||||||
usingCheckDigit(usingCheckDigit_),
|
usingCheckDigit(usingCheckDigit_),
|
||||||
extendedMode(extendedMode_) {
|
extendedMode(extendedMode_) {
|
||||||
}
|
}
|
||||||
|
|
||||||
Ref<Result> Code39Reader::decodeRow(int rowNumber, Ref<BitArray> row){
|
Ref<Result> Code39Reader::decodeRow(int rowNumber, Ref<BitArray> row) {
|
||||||
int* start = NULL;
|
int* start = NULL;
|
||||||
try {
|
try {
|
||||||
start = findAsteriskPattern(row);
|
start = findAsteriskPattern(row);
|
||||||
|
@ -175,7 +174,7 @@ namespace oned {
|
||||||
return res;
|
return res;
|
||||||
} catch (ReaderException const& re) {
|
} catch (ReaderException const& re) {
|
||||||
delete [] start;
|
delete [] start;
|
||||||
throw re;
|
return Ref<Result>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
* EAN13Reader.cpp
|
* EAN13Reader.cpp
|
||||||
* ZXing
|
* ZXing
|
||||||
*
|
*
|
||||||
* Created by Lukasz Warchol on 10-01-22.
|
|
||||||
* Copyright 2010 ZXing authors All rights reserved.
|
* Copyright 2010 ZXing authors All rights reserved.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
@ -23,24 +22,25 @@
|
||||||
|
|
||||||
namespace zxing {
|
namespace zxing {
|
||||||
namespace oned {
|
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() { }
|
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;
|
const int countersLen = 4;
|
||||||
int counters[countersLen] = { 0, 0, 0, 0 };
|
int counters[countersLen] = { 0, 0, 0, 0 };
|
||||||
|
|
||||||
|
|
||||||
int end = row->getSize();
|
int end = row->getSize();
|
||||||
int rowOffset = startRange[1];
|
int rowOffset = startRange[1];
|
||||||
|
|
||||||
int lgPatternFound = 0;
|
int lgPatternFound = 0;
|
||||||
|
|
||||||
for (int x = 0; x < 6 && rowOffset < end; x++) {
|
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));
|
resultString.append(1, (char) ('0' + bestMatch % 10));
|
||||||
for (int i = 0; i < countersLen; i++) {
|
for (int i = 0; i < countersLen; i++) {
|
||||||
rowOffset += counters[i];
|
rowOffset += counters[i];
|
||||||
|
@ -49,31 +49,33 @@ namespace zxing {
|
||||||
lgPatternFound |= 1 << (5 - x);
|
lgPatternFound |= 1 << (5 - x);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
determineFirstDigit(resultString, lgPatternFound);
|
determineFirstDigit(resultString, lgPatternFound);
|
||||||
|
|
||||||
int* middleRange = 0;
|
int* middleRange = 0;
|
||||||
try {
|
try {
|
||||||
middleRange = findGuardPattern(row, rowOffset, true, (int*)getMIDDLE_PATTERN(), getMIDDLE_PATTERN_LEN());
|
middleRange = findGuardPattern(row, rowOffset, true, (int*)getMIDDLE_PATTERN(),
|
||||||
rowOffset = middleRange[1];
|
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);
|
for (int x = 0; x < 6 && rowOffset < end; x++) {
|
||||||
resultString.append(1, (char) ('0' + bestMatch));
|
int bestMatch = decodeDigit(row, counters, countersLen, rowOffset,
|
||||||
for (int i = 0; i < countersLen; i++) {
|
UPC_EAN_PATTERNS_L_PATTERNS);
|
||||||
rowOffset += counters[i];
|
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;
|
||||||
delete [] middleRange;
|
return rowOffset;
|
||||||
throw re;
|
} 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++) {
|
for (int d = 0; d < 10; d++) {
|
||||||
if (lgPatternFound == FIRST_DIGIT_ENCODINGS[d]) {
|
if (lgPatternFound == FIRST_DIGIT_ENCODINGS[d]) {
|
||||||
resultString.insert(0, 1, (char) ('0' + d));
|
resultString.insert(0, 1, (char) ('0' + d));
|
||||||
|
@ -82,7 +84,7 @@ namespace zxing {
|
||||||
}
|
}
|
||||||
throw ReaderException("determineFirstDigit");
|
throw ReaderException("determineFirstDigit");
|
||||||
}
|
}
|
||||||
|
|
||||||
BarcodeFormat EAN13Reader::getBarcodeFormat(){
|
BarcodeFormat EAN13Reader::getBarcodeFormat(){
|
||||||
return BarcodeFormat_EAN_13;
|
return BarcodeFormat_EAN_13;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
* EAN8Reader.cpp
|
* EAN8Reader.cpp
|
||||||
* ZXing
|
* ZXing
|
||||||
*
|
*
|
||||||
* Created by Lukasz Warchol on 10-01-25.
|
|
||||||
* Copyright 2010 ZXing authors All rights reserved.
|
* Copyright 2010 ZXing authors All rights reserved.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
@ -23,45 +22,49 @@
|
||||||
|
|
||||||
namespace zxing {
|
namespace zxing {
|
||||||
namespace oned {
|
namespace oned {
|
||||||
|
|
||||||
EAN8Reader::EAN8Reader(){ }
|
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;
|
const int countersLen = 4;
|
||||||
int counters[countersLen] = { 0, 0, 0, 0 };
|
int counters[countersLen] = { 0, 0, 0, 0 };
|
||||||
|
|
||||||
int end = row->getSize();
|
int end = row->getSize();
|
||||||
int rowOffset = startRange[1];
|
int rowOffset = startRange[1];
|
||||||
|
|
||||||
for (int x = 0; x < 4 && rowOffset < end; x++) {
|
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));
|
resultString.append(1, (char) ('0' + bestMatch));
|
||||||
for (int i = 0; i < countersLen; i++) {
|
for (int i = 0; i < countersLen; i++) {
|
||||||
rowOffset += counters[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;
|
int* middleRange = 0;
|
||||||
return rowOffset;
|
try {
|
||||||
} catch (ReaderException const& re) {
|
middleRange = findGuardPattern(row, rowOffset, true, (int*)getMIDDLE_PATTERN(),
|
||||||
delete [] middleRange;
|
getMIDDLE_PATTERN_LEN());
|
||||||
throw re;
|
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(){
|
BarcodeFormat EAN8Reader::getBarcodeFormat(){
|
||||||
return BarcodeFormat_EAN_8;
|
return BarcodeFormat_EAN_8;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
* ITFReader.cpp
|
* ITFReader.cpp
|
||||||
* ZXing
|
* ZXing
|
||||||
*
|
*
|
||||||
* Created by Lukasz Warchol on 10-01-26.
|
|
||||||
* Copyright 2010 ZXing authors All rights reserved.
|
* Copyright 2010 ZXing authors All rights reserved.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
@ -26,12 +25,12 @@
|
||||||
|
|
||||||
namespace zxing {
|
namespace zxing {
|
||||||
namespace oned {
|
namespace oned {
|
||||||
|
|
||||||
static const int W = 3; // Pixel width of a wide line
|
static const int W = 3; // Pixel width of a wide line
|
||||||
static const int N = 1; // Pixed width of a narrow line
|
static const int N = 1; // Pixed width of a narrow line
|
||||||
|
|
||||||
const int DEFAULT_ALLOWED_LENGTHS[4] = { 6, 10, 14, 44 };
|
const int DEFAULT_ALLOWED_LENGTHS[4] = { 6, 10, 14, 44 };
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Start/end guard pattern.
|
* Start/end guard pattern.
|
||||||
*
|
*
|
||||||
|
@ -40,10 +39,10 @@ namespace zxing {
|
||||||
*/
|
*/
|
||||||
static const int START_PATTERN_LEN = 4;
|
static const int START_PATTERN_LEN = 4;
|
||||||
static const int START_PATTERN[START_PATTERN_LEN] = {N, N, N, N};
|
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_LEN = 3;
|
||||||
static const int END_PATTERN_REVERSED[END_PATTERN_REVERSED_LEN] = {N, N, W};
|
static const int END_PATTERN_REVERSED[END_PATTERN_REVERSED_LEN] = {N, N, W};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Patterns of Wide / Narrow lines to indicate each digit
|
* Patterns of Wide / Narrow lines to indicate each digit
|
||||||
*/
|
*/
|
||||||
|
@ -60,62 +59,61 @@ namespace zxing {
|
||||||
{W, N, N, W, N}, // 8
|
{W, N, N, W, N}, // 8
|
||||||
{N, W, N, W, N} // 9
|
{N, W, N, W, N} // 9
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
ITFReader::ITFReader() : narrowLineWidth(-1) {
|
ITFReader::ITFReader() : narrowLineWidth(-1) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Ref<Result> ITFReader::decodeRow(int rowNumber, Ref<BitArray> row){
|
Ref<Result> ITFReader::decodeRow(int rowNumber, Ref<BitArray> row) {
|
||||||
int* startRange = 0;
|
int* startRange = 0;
|
||||||
int* endRange = 0;
|
int* endRange = 0;
|
||||||
try {
|
try {
|
||||||
// Find out where the Middle section (payload) starts & ends
|
// Find out where the Middle section (payload) starts & ends
|
||||||
startRange = decodeStart(row);
|
startRange = decodeStart(row);
|
||||||
endRange = decodeEnd(row);
|
endRange = decodeEnd(row);
|
||||||
|
|
||||||
std::string tmpResult;
|
std::string tmpResult;
|
||||||
decodeMiddle(row, startRange[1], endRange[0], tmpResult);
|
decodeMiddle(row, startRange[1], endRange[0], tmpResult);
|
||||||
|
|
||||||
// To avoid false positives with 2D barcodes (and other patterns), make
|
// To avoid false positives with 2D barcodes (and other patterns), make
|
||||||
// an assumption that the decoded string must be 6, 10 or 14 digits.
|
// an assumption that the decoded string must be 6, 10 or 14 digits.
|
||||||
int length = tmpResult.length();
|
int length = tmpResult.length();
|
||||||
bool lengthOK = false;
|
bool lengthOK = false;
|
||||||
if (length == 6 || length == 10 || length == 14) {
|
if (length == 6 || length == 10 || length == 14) {
|
||||||
lengthOK = true;
|
lengthOK = true;
|
||||||
}
|
}
|
||||||
if (!lengthOK) {
|
if (!lengthOK) {
|
||||||
throw ReaderException("not enough characters count");
|
throw ReaderException("not enough characters count");
|
||||||
}
|
}
|
||||||
|
|
||||||
Ref<String> resultString(new String(tmpResult));
|
Ref<String> resultString(new String(tmpResult));
|
||||||
|
|
||||||
std::vector< Ref<ResultPoint> > resultPoints(2);
|
std::vector< Ref<ResultPoint> > resultPoints(2);
|
||||||
Ref<OneDResultPoint> resultPoint1(new OneDResultPoint(startRange[1], (float) rowNumber));
|
Ref<OneDResultPoint> resultPoint1(new OneDResultPoint(startRange[1], (float) rowNumber));
|
||||||
Ref<OneDResultPoint> resultPoint2(new OneDResultPoint(endRange[0], (float) rowNumber));
|
Ref<OneDResultPoint> resultPoint2(new OneDResultPoint(endRange[0], (float) rowNumber));
|
||||||
resultPoints[0] = resultPoint1;
|
resultPoints[0] = resultPoint1;
|
||||||
resultPoints[1] = resultPoint2;
|
resultPoints[1] = resultPoint2;
|
||||||
|
|
||||||
ArrayRef<unsigned char> resultBytes(1);
|
delete [] startRange;
|
||||||
|
delete [] endRange;
|
||||||
Ref<Result> res(new Result(resultString, resultBytes, resultPoints, BarcodeFormat_ITF));
|
ArrayRef<unsigned char> resultBytes(1);
|
||||||
delete [] startRange;
|
return Ref<Result>(new Result(resultString, resultBytes, resultPoints, BarcodeFormat_ITF));
|
||||||
delete [] endRange;
|
|
||||||
return res;
|
|
||||||
} catch (ReaderException re) {
|
} catch (ReaderException re) {
|
||||||
delete [] startRange;
|
delete [] startRange;
|
||||||
delete [] endRange;
|
delete [] endRange;
|
||||||
throw re;
|
return Ref<Result>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param row row of black/white values to search
|
* @param row row of black/white values to search
|
||||||
* @param payloadStart offset of start pattern
|
* @param payloadStart offset of start pattern
|
||||||
* @param resultString {@link StringBuffer} to append decoded chars to
|
* @param resultString {@link StringBuffer} to append decoded chars to
|
||||||
* @throws ReaderException if decoding could not complete successfully
|
* @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
|
// Digits are interleaved in pairs - 5 black lines for one digit, and the
|
||||||
// 5
|
// 5
|
||||||
// interleaved white lines for the second digit.
|
// interleaved white lines for the second digit.
|
||||||
|
@ -126,14 +124,14 @@ namespace zxing {
|
||||||
for (int i=0; i<counterDigitPairLen; i++) {
|
for (int i=0; i<counterDigitPairLen; i++) {
|
||||||
counterDigitPair[i] = 0;
|
counterDigitPair[i] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int counterBlack[5];
|
int counterBlack[5];
|
||||||
int counterWhite[5];
|
int counterWhite[5];
|
||||||
for (int i=0; i<5; i++) {
|
for (int i=0; i<5; i++) {
|
||||||
counterBlack[i] = 0;
|
counterBlack[i] = 0;
|
||||||
counterWhite[i] = 0;
|
counterWhite[i] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (payloadStart < payloadEnd) {
|
while (payloadStart < payloadEnd) {
|
||||||
// Get 10 runs of black/white.
|
// Get 10 runs of black/white.
|
||||||
recordPattern(row, payloadStart, counterDigitPair, counterDigitPairLen);
|
recordPattern(row, payloadStart, counterDigitPair, counterDigitPairLen);
|
||||||
|
@ -143,18 +141,18 @@ namespace zxing {
|
||||||
counterBlack[k] = counterDigitPair[twoK];
|
counterBlack[k] = counterDigitPair[twoK];
|
||||||
counterWhite[k] = counterDigitPair[twoK + 1];
|
counterWhite[k] = counterDigitPair[twoK + 1];
|
||||||
}
|
}
|
||||||
|
|
||||||
int bestMatch = decodeDigit(counterBlack, 5);
|
int bestMatch = decodeDigit(counterBlack, 5);
|
||||||
resultString.append(1, (char) ('0' + bestMatch));
|
resultString.append(1, (char) ('0' + bestMatch));
|
||||||
bestMatch = decodeDigit(counterWhite, 5);
|
bestMatch = decodeDigit(counterWhite, 5);
|
||||||
resultString.append(1, (char) ('0' + bestMatch));
|
resultString.append(1, (char) ('0' + bestMatch));
|
||||||
|
|
||||||
for (int i = 0; i < counterDigitPairLen; i++) {
|
for (int i = 0; i < counterDigitPairLen; i++) {
|
||||||
payloadStart += counterDigitPair[i];
|
payloadStart += counterDigitPair[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Identify where the start of the middle / payload section starts.
|
* Identify where the start of the middle / payload section starts.
|
||||||
*
|
*
|
||||||
|
@ -163,27 +161,24 @@ namespace zxing {
|
||||||
* 'start block'
|
* 'start block'
|
||||||
* @throws ReaderException
|
* @throws ReaderException
|
||||||
*/
|
*/
|
||||||
int* ITFReader::decodeStart(Ref<BitArray> row){
|
int* ITFReader::decodeStart(Ref<BitArray> row) {
|
||||||
int endStart = skipWhiteSpace(row);
|
int endStart = skipWhiteSpace(row);
|
||||||
/// static int* findGuardPattern(Ref<BitArray> row, int rowOffset, bool whiteFirst, const int pattern[], int patternLen);
|
|
||||||
int* startPattern = 0;
|
int* startPattern = 0;
|
||||||
try {
|
try {
|
||||||
startPattern = findGuardPattern(row, endStart, START_PATTERN, START_PATTERN_LEN);
|
startPattern = findGuardPattern(row, endStart, START_PATTERN, START_PATTERN_LEN);
|
||||||
|
|
||||||
// Determine the width of a narrow line in pixels. We can do this by
|
// 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
|
// getting the width of the start pattern and dividing by 4 because its
|
||||||
// made up of 4 narrow lines.
|
// made up of 4 narrow lines.
|
||||||
narrowLineWidth = (startPattern[1] - startPattern[0]) >> 2;
|
narrowLineWidth = (startPattern[1] - startPattern[0]) >> 2;
|
||||||
|
validateQuietZone(row, startPattern[0]);
|
||||||
validateQuietZone(row, startPattern[0]);
|
return startPattern;
|
||||||
|
|
||||||
return startPattern;
|
|
||||||
} catch (ReaderException re) {
|
} catch (ReaderException re) {
|
||||||
delete [] startPattern;
|
delete [] startPattern;
|
||||||
throw re;
|
throw re;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Identify where the end of the middle / payload section ends.
|
* Identify where the end of the middle / payload section ends.
|
||||||
*
|
*
|
||||||
|
@ -192,8 +187,8 @@ namespace zxing {
|
||||||
* block'
|
* block'
|
||||||
* @throws ReaderException
|
* @throws ReaderException
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int* ITFReader::decodeEnd(Ref<BitArray> row){
|
int* ITFReader::decodeEnd(Ref<BitArray> row) {
|
||||||
// For convenience, reverse the row and then
|
// For convenience, reverse the row and then
|
||||||
// search from 'the start' for the end block
|
// search from 'the start' for the end block
|
||||||
row->reverse();
|
row->reverse();
|
||||||
|
@ -201,28 +196,28 @@ namespace zxing {
|
||||||
try {
|
try {
|
||||||
int endStart = skipWhiteSpace(row);
|
int endStart = skipWhiteSpace(row);
|
||||||
endPattern = findGuardPattern(row, endStart, END_PATTERN_REVERSED, END_PATTERN_REVERSED_LEN);
|
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
|
// 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.
|
// zone must be at least 10 times the width of a narrow line.
|
||||||
// ref: http://www.barcode-1.net/i25code.html
|
// ref: http://www.barcode-1.net/i25code.html
|
||||||
validateQuietZone(row, endPattern[0]);
|
validateQuietZone(row, endPattern[0]);
|
||||||
|
|
||||||
// Now recalculate the indices of where the 'endblock' starts & stops to
|
// Now recalculate the indices of where the 'endblock' starts & stops to
|
||||||
// accommodate
|
// accommodate
|
||||||
// the reversed nature of the search
|
// the reversed nature of the search
|
||||||
int temp = endPattern[0];
|
int temp = endPattern[0];
|
||||||
endPattern[0] = row->getSize() - endPattern[1];
|
endPattern[0] = row->getSize() - endPattern[1];
|
||||||
endPattern[1] = row->getSize() - temp;
|
endPattern[1] = row->getSize() - temp;
|
||||||
|
|
||||||
row->reverse();
|
row->reverse();
|
||||||
return endPattern;
|
return endPattern;
|
||||||
} catch (ReaderException re) {
|
} catch (ReaderException re) {
|
||||||
delete [] endPattern;
|
delete [] endPattern;
|
||||||
row->reverse();
|
row->reverse();
|
||||||
throw re;
|
throw re;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The start & end patterns must be pre/post fixed by a quiet zone. This
|
* 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
|
* 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.
|
* @param startPattern index into row of the start or end pattern.
|
||||||
* @throws ReaderException if the quiet zone cannot be found, a ReaderException is thrown.
|
* @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
|
//#pragma mark needs some corrections
|
||||||
// int quietCount = narrowLineWidth * 10; // expect to find this many pixels of quiet zone
|
// int quietCount = narrowLineWidth * 10; // expect to find this many pixels of quiet zone
|
||||||
//
|
//
|
||||||
// for (int i = startPattern - 1; quietCount > 0 && i >= 0; i--) {
|
// for (int i = startPattern - 1; quietCount > 0 && i >= 0; i--) {
|
||||||
// if (row->get(i)) {
|
// if (row->get(i)) {
|
||||||
// break;
|
// break;
|
||||||
|
@ -253,7 +248,7 @@ namespace zxing {
|
||||||
// throw ReaderException("Unable to find the necessary number of quiet zone pixels");
|
// throw ReaderException("Unable to find the necessary number of quiet zone pixels");
|
||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Skip all whitespace until we get to the first black line.
|
* Skip all whitespace until we get to the first black line.
|
||||||
*
|
*
|
||||||
|
@ -261,7 +256,7 @@ namespace zxing {
|
||||||
* @return index of the first black line.
|
* @return index of the first black line.
|
||||||
* @throws ReaderException Throws exception if no black lines are found in the row
|
* @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 width = row->getSize();
|
||||||
int endStart = 0;
|
int endStart = 0;
|
||||||
while (endStart < width) {
|
while (endStart < width) {
|
||||||
|
@ -275,7 +270,7 @@ namespace zxing {
|
||||||
}
|
}
|
||||||
return endStart;
|
return endStart;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param row row of black/white values to search
|
* @param row row of black/white values to search
|
||||||
* @param rowOffset position to start search
|
* @param rowOffset position to start search
|
||||||
|
@ -285,8 +280,8 @@ namespace zxing {
|
||||||
* ints
|
* ints
|
||||||
* @throws ReaderException if pattern is not found
|
* @throws ReaderException if pattern is not found
|
||||||
*/
|
*/
|
||||||
|
int* ITFReader::findGuardPattern(Ref<BitArray> row, int rowOffset, const int pattern[],
|
||||||
int* ITFReader::findGuardPattern(Ref<BitArray> row, int rowOffset, const int pattern[], int patternLen){
|
int patternLen) {
|
||||||
// TODO: This is very similar to implementation in UPCEANReader. Consider if they can be
|
// TODO: This is very similar to implementation in UPCEANReader. Consider if they can be
|
||||||
// merged to a single method.
|
// merged to a single method.
|
||||||
int patternLength = patternLen;
|
int patternLength = patternLen;
|
||||||
|
@ -296,7 +291,7 @@ namespace zxing {
|
||||||
}
|
}
|
||||||
int width = row->getSize();
|
int width = row->getSize();
|
||||||
bool isWhite = false;
|
bool isWhite = false;
|
||||||
|
|
||||||
int counterPosition = 0;
|
int counterPosition = 0;
|
||||||
int patternStart = rowOffset;
|
int patternStart = rowOffset;
|
||||||
for (int x = rowOffset; x < width; x++) {
|
for (int x = rowOffset; x < width; x++) {
|
||||||
|
@ -305,7 +300,8 @@ namespace zxing {
|
||||||
counters[counterPosition]++;
|
counters[counterPosition]++;
|
||||||
} else {
|
} else {
|
||||||
if (counterPosition == patternLength - 1) {
|
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];
|
int* resultValue = new int[2];
|
||||||
resultValue[0] = patternStart;
|
resultValue[0] = patternStart;
|
||||||
resultValue[1] = x;
|
resultValue[1] = x;
|
||||||
|
@ -327,7 +323,7 @@ namespace zxing {
|
||||||
}
|
}
|
||||||
throw ReaderException("");
|
throw ReaderException("");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Attempts to decode a sequence of ITF black/white lines into single
|
* Attempts to decode a sequence of ITF black/white lines into single
|
||||||
* digit.
|
* digit.
|
||||||
|
@ -341,11 +337,12 @@ namespace zxing {
|
||||||
int bestMatch = -1;
|
int bestMatch = -1;
|
||||||
int max = PATTERNS_LEN;
|
int max = PATTERNS_LEN;
|
||||||
for (int i = 0; i < max; i++) {
|
for (int i = 0; i < max; i++) {
|
||||||
int pattern[countersLen];
|
int pattern[countersLen];
|
||||||
for(int ind = 0; ind<countersLen; ind++){
|
for(int ind = 0; ind<countersLen; ind++){
|
||||||
pattern[ind] = PATTERNS[i][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) {
|
if (variance < bestVariance) {
|
||||||
bestVariance = variance;
|
bestVariance = variance;
|
||||||
bestMatch = i;
|
bestMatch = i;
|
||||||
|
@ -357,8 +354,7 @@ namespace zxing {
|
||||||
throw ReaderException("digit didint found");
|
throw ReaderException("digit didint found");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
ITFReader::~ITFReader(){
|
ITFReader::~ITFReader(){
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
* MultiFormatOneDReader.cpp
|
* MultiFormatOneDReader.cpp
|
||||||
* ZXing
|
* ZXing
|
||||||
*
|
*
|
||||||
* Created by Lukasz Warchol on 10-01-25.
|
|
||||||
* Copyright 2010 ZXing authors All rights reserved.
|
* Copyright 2010 ZXing authors All rights reserved.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
@ -51,18 +50,17 @@ namespace zxing {
|
||||||
readers.push_back(Ref<OneDReader>(new ITFReader()));
|
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();
|
int size = readers.size();
|
||||||
for (int i = 0; i < size; i++) {
|
for (int i = 0; i < size; i++) {
|
||||||
OneDReader* reader = readers[i];
|
OneDReader* reader = readers[i];
|
||||||
try {
|
Ref<Result> result = reader->decodeRow(rowNumber, row);
|
||||||
return reader->decodeRow(rowNumber, row);
|
if (!result.empty()) {
|
||||||
} catch (ReaderException re) {
|
return result;
|
||||||
// continue
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
throw ReaderException("No code detected");
|
return Ref<Result>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
* MultiFormatUPCEANReader.cpp
|
* MultiFormatUPCEANReader.cpp
|
||||||
* ZXing
|
* ZXing
|
||||||
*
|
*
|
||||||
* Created by Lukasz Warchol on 10-01-25.
|
|
||||||
* Copyright 2010 ZXing authors All rights reserved.
|
* Copyright 2010 ZXing authors All rights reserved.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
@ -30,7 +29,7 @@
|
||||||
|
|
||||||
namespace zxing {
|
namespace zxing {
|
||||||
namespace oned {
|
namespace oned {
|
||||||
|
|
||||||
MultiFormatUPCEANReader::MultiFormatUPCEANReader(DecodeHints hints) : readers() {
|
MultiFormatUPCEANReader::MultiFormatUPCEANReader(DecodeHints hints) : readers() {
|
||||||
if (hints.containsFormat(BarcodeFormat_EAN_13)) {
|
if (hints.containsFormat(BarcodeFormat_EAN_13)) {
|
||||||
readers.push_back(Ref<OneDReader>(new EAN13Reader()));
|
readers.push_back(Ref<OneDReader>(new EAN13Reader()));
|
||||||
|
@ -51,17 +50,16 @@ namespace zxing {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
// Compute this location once and reuse it on multiple implementations
|
||||||
int size = readers.size();
|
int size = readers.size();
|
||||||
for (int i = 0; i < size; i++) {
|
for (int i = 0; i < size; i++) {
|
||||||
Ref<OneDReader> reader = readers[i];
|
Ref<OneDReader> reader = readers[i];
|
||||||
Ref<Result> result;
|
Ref<Result> result = reader->decodeRow(rowNumber, row);
|
||||||
try {
|
if (result.empty()) {
|
||||||
result = reader->decodeRow(rowNumber, row);//decodeRow(rowNumber, row, startGuardPattern);
|
continue;
|
||||||
} catch (ReaderException re) {
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Special case: a 12-digit code encoded in UPC-A is identical to a "0"
|
// 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,
|
// 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".
|
// 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();
|
const std::string& text = (result->getText())->getText();
|
||||||
if (text[0] == '0') {
|
if (text[0] == '0') {
|
||||||
Ref<String> resultString(new String(text.substr(1)));
|
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 res;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
throw ReaderException("No EAN code detected");
|
return Ref<Result>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
* OneDReader.cpp
|
* OneDReader.cpp
|
||||||
* ZXing
|
* ZXing
|
||||||
*
|
*
|
||||||
* Created by Lukasz Warchol on 10-01-15.
|
|
||||||
* Copyright 2010 ZXing authors All rights reserved.
|
* Copyright 2010 ZXing authors All rights reserved.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
@ -27,17 +26,15 @@
|
||||||
namespace zxing {
|
namespace zxing {
|
||||||
namespace oned {
|
namespace oned {
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
OneDReader::OneDReader() {
|
OneDReader::OneDReader() {
|
||||||
}
|
}
|
||||||
|
|
||||||
Ref<Result> OneDReader::decode(Ref<BinaryBitmap> image, DecodeHints hints) {
|
|
||||||
|
|
||||||
|
Ref<Result> OneDReader::decode(Ref<BinaryBitmap> image, DecodeHints hints) {
|
||||||
try {
|
try {
|
||||||
return doDecode(image, hints);
|
return doDecode(image, hints);
|
||||||
}catch (ReaderException re) {
|
} catch (ReaderException re) {
|
||||||
if (hints.getTryHarder() && image->isRotateSupported()) {
|
if (hints.getTryHarder() && image->isRotateSupported()) {
|
||||||
|
|
||||||
Ref<BinaryBitmap> rotatedImage(image->rotateCounterClockwise());
|
Ref<BinaryBitmap> rotatedImage(image->rotateCounterClockwise());
|
||||||
Ref<Result> result(doDecode(rotatedImage, hints));
|
Ref<Result> result(doDecode(rotatedImage, hints));
|
||||||
/*
|
/*
|
||||||
|
@ -63,8 +60,8 @@ namespace zxing {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ref<Result> OneDReader::doDecode(Ref<BinaryBitmap> image, DecodeHints hints){
|
Ref<Result> OneDReader::doDecode(Ref<BinaryBitmap> image, DecodeHints hints) {
|
||||||
int width = image->getWidth();
|
int width = image->getWidth();
|
||||||
int height = image->getHeight();
|
int height = image->getHeight();
|
||||||
Ref<BitArray> row(new BitArray(width));
|
Ref<BitArray> row(new BitArray(width));
|
||||||
|
@ -77,9 +74,8 @@ namespace zxing {
|
||||||
} else {
|
} else {
|
||||||
maxLines = 15; // 15 rows spaced 1/32 apart is roughly the middle half of the image
|
maxLines = 15; // 15 rows spaced 1/32 apart is roughly the middle half of the image
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int x = 0; x < maxLines; x++) {
|
for (int x = 0; x < maxLines; x++) {
|
||||||
|
|
||||||
// Scanning from the middle out. Determine which row we're looking at next:
|
// Scanning from the middle out. Determine which row we're looking at next:
|
||||||
int rowStepsAboveOrBelow = (x + 1) >> 1;
|
int rowStepsAboveOrBelow = (x + 1) >> 1;
|
||||||
bool isAbove = (x & 0x01) == 0; // i.e. is x even?
|
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
|
// Oops, if we run off the top or bottom, stop
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Estimate black point for this row and load it:
|
// Estimate black point for this row and load it:
|
||||||
try {
|
try {
|
||||||
row = image->getBlackRow(rowNumber, row);
|
row = image->getBlackRow(rowNumber, row);
|
||||||
}catch (ReaderException re) {
|
} catch (ReaderException re) {
|
||||||
continue;
|
continue;
|
||||||
}catch (IllegalArgumentException re) {
|
} catch (IllegalArgumentException re) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// While we have the image data in a BitArray, it's fairly cheap to reverse it in place to
|
// While we have the image data in a BitArray, it's fairly cheap to reverse it in place to
|
||||||
// handle decoding upside down barcodes.
|
// handle decoding upside down barcodes.
|
||||||
for (int attempt = 0; attempt < 2; attempt++) {
|
for (int attempt = 0; attempt < 2; attempt++) {
|
||||||
if (attempt == 1) { // trying again?
|
if (attempt == 1) { // trying again?
|
||||||
row->reverse(); // reverse the row and continue
|
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()));
|
// Look for a barcode
|
||||||
points[1] = pointOne;
|
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()));
|
Ref<ResultPoint> pointOne(new OneDResultPoint(width - points[1]->getX() - 1, points[1]->getY()));
|
||||||
}
|
points[1] = pointOne;
|
||||||
}
|
|
||||||
return result;
|
result.reset(new Result(result->getText(),result->getRawBytes(),points,result->getBarcodeFormat()));
|
||||||
} catch (ReaderException re) {
|
}
|
||||||
// continue -- just couldn't decode this row
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
throw ReaderException("doDecode() failed");
|
throw ReaderException("doDecode() failed");
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int OneDReader::patternMatchVariance(int counters[], int countersSize, const int pattern[], int maxIndividualVariance) {
|
unsigned int OneDReader::patternMatchVariance(int counters[], int countersSize, const int pattern[], int maxIndividualVariance) {
|
||||||
int numCounters = countersSize;
|
int numCounters = countersSize;
|
||||||
unsigned int total = 0;
|
unsigned int total = 0;
|
||||||
|
@ -152,7 +145,7 @@ namespace zxing {
|
||||||
// more "significant digits"
|
// more "significant digits"
|
||||||
unsigned int unitBarWidth = (total << INTEGER_MATH_SHIFT) / patternLength;
|
unsigned int unitBarWidth = (total << INTEGER_MATH_SHIFT) / patternLength;
|
||||||
maxIndividualVariance = (maxIndividualVariance * unitBarWidth) >> INTEGER_MATH_SHIFT;
|
maxIndividualVariance = (maxIndividualVariance * unitBarWidth) >> INTEGER_MATH_SHIFT;
|
||||||
|
|
||||||
unsigned int totalVariance = 0;
|
unsigned int totalVariance = 0;
|
||||||
for (int x = 0; x < numCounters; x++) {
|
for (int x = 0; x < numCounters; x++) {
|
||||||
int counter = counters[x] << INTEGER_MATH_SHIFT;
|
int counter = counters[x] << INTEGER_MATH_SHIFT;
|
||||||
|
@ -165,7 +158,7 @@ namespace zxing {
|
||||||
}
|
}
|
||||||
return totalVariance / total;
|
return totalVariance / total;
|
||||||
}
|
}
|
||||||
|
|
||||||
void OneDReader::recordPattern(Ref<BitArray> row, int start, int counters[], int countersCount){
|
void OneDReader::recordPattern(Ref<BitArray> row, int start, int counters[], int countersCount){
|
||||||
int numCounters = countersCount;//sizeof(counters) / sizeof(int);
|
int numCounters = countersCount;//sizeof(counters) / sizeof(int);
|
||||||
for (int i = 0; i < numCounters; i++) {
|
for (int i = 0; i < numCounters; i++) {
|
||||||
|
@ -199,7 +192,7 @@ namespace zxing {
|
||||||
throw ReaderException("recordPattern");
|
throw ReaderException("recordPattern");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
OneDReader::~OneDReader() {
|
OneDReader::~OneDReader() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,16 +27,20 @@ namespace zxing {
|
||||||
class OneDReader : public Reader {
|
class OneDReader : public Reader {
|
||||||
private:
|
private:
|
||||||
static const int INTEGER_MATH_SHIFT = 8;
|
static const int INTEGER_MATH_SHIFT = 8;
|
||||||
|
|
||||||
Ref<Result> doDecode(Ref<BinaryBitmap> image, DecodeHints hints);
|
Ref<Result> doDecode(Ref<BinaryBitmap> image, DecodeHints hints);
|
||||||
public:
|
public:
|
||||||
static const int PATTERN_MATCH_RESULT_SCALE_FACTOR = 1 << INTEGER_MATH_SHIFT;
|
static const int PATTERN_MATCH_RESULT_SCALE_FACTOR = 1 << INTEGER_MATH_SHIFT;
|
||||||
|
|
||||||
OneDReader();
|
OneDReader();
|
||||||
virtual Ref<Result> decode(Ref<BinaryBitmap> image, DecodeHints hints);
|
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;
|
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);
|
static void recordPattern(Ref<BitArray> row, int start, int counters[], int countersCount);
|
||||||
virtual ~OneDReader();
|
virtual ~OneDReader();
|
||||||
};
|
};
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
* OneDResultPoint.cpp
|
* OneDResultPoint.cpp
|
||||||
* ZXing
|
* ZXing
|
||||||
*
|
*
|
||||||
* Created by Lukasz Warchol on 10-01-20.
|
|
||||||
* Copyright 2010 ZXing authors All rights reserved.
|
* Copyright 2010 ZXing authors All rights reserved.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
@ -22,14 +21,14 @@
|
||||||
|
|
||||||
namespace zxing {
|
namespace zxing {
|
||||||
namespace oned {
|
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 {
|
float OneDResultPoint::getX() const {
|
||||||
return posX_;
|
return posX_;
|
||||||
}
|
}
|
||||||
|
|
||||||
float OneDResultPoint::getY() const {
|
float OneDResultPoint::getY() const {
|
||||||
return posY_;
|
return posY_;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
* UPCAReader.cpp
|
* UPCAReader.cpp
|
||||||
* ZXing
|
* ZXing
|
||||||
*
|
*
|
||||||
* Created by Lukasz Warchol on 10-01-25.
|
|
||||||
* Copyright 2010 ZXing authors All rights reserved.
|
* Copyright 2010 ZXing authors All rights reserved.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
@ -25,33 +24,38 @@ namespace zxing {
|
||||||
namespace oned {
|
namespace oned {
|
||||||
UPCAReader::UPCAReader() : ean13Reader() {
|
UPCAReader::UPCAReader() : ean13Reader() {
|
||||||
}
|
}
|
||||||
|
|
||||||
Ref<Result> UPCAReader::decodeRow(int rowNumber, Ref<BitArray> row){
|
Ref<Result> UPCAReader::decodeRow(int rowNumber, Ref<BitArray> row) {
|
||||||
return maybeReturnResult(ean13Reader.decodeRow(rowNumber, 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));
|
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));
|
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);
|
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();
|
const std::string& text = (result->getText())->getText();
|
||||||
if (text[0] == '0') {
|
if (text[0] == '0') {
|
||||||
Ref<String> resultString(new String(text.substr(1)));
|
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 res;
|
||||||
} else {
|
|
||||||
throw ReaderException("Not UPC-A barcode.");
|
|
||||||
}
|
}
|
||||||
|
return Ref<Result>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
BarcodeFormat UPCAReader::getBarcodeFormat(){
|
BarcodeFormat UPCAReader::getBarcodeFormat(){
|
||||||
return BarcodeFormat_UPC_A;
|
return BarcodeFormat_UPC_A;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
* UPCEANReader.cpp
|
* UPCEANReader.cpp
|
||||||
* ZXing
|
* ZXing
|
||||||
*
|
*
|
||||||
* Created by Lukasz Warchol on 10-01-21.
|
|
||||||
* Copyright 2010 ZXing authors All rights reserved.
|
* Copyright 2010 ZXing authors All rights reserved.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
@ -21,20 +20,21 @@
|
||||||
#include "UPCEANReader.h"
|
#include "UPCEANReader.h"
|
||||||
#include <zxing/oned/OneDResultPoint.h>
|
#include <zxing/oned/OneDResultPoint.h>
|
||||||
#include <zxing/ReaderException.h>
|
#include <zxing/ReaderException.h>
|
||||||
|
|
||||||
namespace zxing {
|
namespace zxing {
|
||||||
namespace oned {
|
namespace oned {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Start/end guard pattern.
|
* Start/end guard pattern.
|
||||||
*/
|
*/
|
||||||
static const int START_END_PATTERN[3] = {1, 1, 1};
|
static const int START_END_PATTERN[3] = {1, 1, 1};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Pattern marking the middle of a UPC/EAN pattern, separating the two halves.
|
* 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_LEN = 5;
|
||||||
static const int MIDDLE_PATTERN[MIDDLE_PATTERN_LEN] = {1, 1, 1, 1, 1};
|
static const int MIDDLE_PATTERN[MIDDLE_PATTERN_LEN] = {1, 1, 1, 1, 1};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* "Odd", or "L" patterns used to encode UPC/EAN digits.
|
* "Odd", or "L" patterns used to encode UPC/EAN digits.
|
||||||
*/
|
*/
|
||||||
|
@ -52,7 +52,7 @@ namespace zxing {
|
||||||
{1, 2, 1, 3}, // 8
|
{1, 2, 1, 3}, // 8
|
||||||
{3, 1, 1, 2} // 9
|
{3, 1, 1, 2} // 9
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* As above but also including the "even", or "G" patterns used to encode UPC/EAN digits.
|
* 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
|
{3, 1, 2, 1}, // 18 reversed 8
|
||||||
{2, 1, 1, 3} // 19 reversed 9
|
{2, 1, 1, 3} // 19 reversed 9
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
const int UPCEANReader::getMIDDLE_PATTERN_LEN(){
|
|
||||||
|
const int UPCEANReader::getMIDDLE_PATTERN_LEN() {
|
||||||
return MIDDLE_PATTERN_LEN;
|
return MIDDLE_PATTERN_LEN;
|
||||||
}
|
}
|
||||||
const int* UPCEANReader::getMIDDLE_PATTERN(){
|
|
||||||
|
const int* UPCEANReader::getMIDDLE_PATTERN() {
|
||||||
return MIDDLE_PATTERN;
|
return MIDDLE_PATTERN;
|
||||||
}
|
}
|
||||||
|
|
||||||
UPCEANReader::UPCEANReader(){
|
UPCEANReader::UPCEANReader() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Ref<Result> UPCEANReader::decodeRow(int rowNumber, Ref<BitArray> row) {
|
Ref<Result> UPCEANReader::decodeRow(int rowNumber, Ref<BitArray> row) {
|
||||||
int* start = NULL;
|
int* start = NULL;
|
||||||
try {
|
try {
|
||||||
|
@ -102,22 +103,21 @@ namespace zxing {
|
||||||
return result;
|
return result;
|
||||||
} catch (ReaderException const& re) {
|
} catch (ReaderException const& re) {
|
||||||
delete [] start;
|
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;
|
int* endRange = NULL;
|
||||||
try {
|
try {
|
||||||
std::string tmpResultString;
|
std::string tmpResultString;
|
||||||
std::string& tmpResultStringRef = tmpResultString;
|
std::string& tmpResultStringRef = tmpResultString;
|
||||||
int endStart;
|
int endStart = decodeMiddle(row, startGuardRange, 2 /*reference findGuardPattern*/ ,
|
||||||
endStart = decodeMiddle(row, startGuardRange, 2 /*reference findGuardPattern*/ , tmpResultStringRef);
|
tmpResultStringRef);
|
||||||
|
|
||||||
endRange = decodeEnd(row, endStart);
|
endRange = decodeEnd(row, endStart);
|
||||||
|
|
||||||
// Make sure there is a quiet zone at least as big as the end pattern after the barcode. The
|
// Make sure there is a quiet zone at least as big as the end pattern after the barcode.
|
||||||
// spec might want more whitespace, but in practice this is the maximum we can count on.
|
// The spec might want more whitespace, but in practice this is the maximum we can count on.
|
||||||
size_t end = endRange[1];
|
size_t end = endRange[1];
|
||||||
size_t quietEnd = end + (end - endRange[0]);
|
size_t quietEnd = end + (end - endRange[0]);
|
||||||
if (quietEnd >= row->getSize() || !row->isRange(end, quietEnd, false)) {
|
if (quietEnd >= row->getSize() || !row->isRange(end, quietEnd, false)) {
|
||||||
|
@ -127,20 +127,20 @@ namespace zxing {
|
||||||
if (!checkChecksum(tmpResultString)) {
|
if (!checkChecksum(tmpResultString)) {
|
||||||
throw ReaderException("Checksum fail.");
|
throw ReaderException("Checksum fail.");
|
||||||
}
|
}
|
||||||
|
|
||||||
Ref<String> resultString(new String(tmpResultString));
|
Ref<String> resultString(new String(tmpResultString));
|
||||||
|
|
||||||
float left = (float) (startGuardRange[1] + startGuardRange[0]) / 2.0f;
|
float left = (float) (startGuardRange[1] + startGuardRange[0]) / 2.0f;
|
||||||
float right = (float) (endRange[1] + endRange[0]) / 2.0f;
|
float right = (float) (endRange[1] + endRange[0]) / 2.0f;
|
||||||
|
|
||||||
std::vector< Ref<ResultPoint> > resultPoints(2);
|
std::vector< Ref<ResultPoint> > resultPoints(2);
|
||||||
Ref<OneDResultPoint> resultPoint1(new OneDResultPoint(left, (float) rowNumber));
|
Ref<OneDResultPoint> resultPoint1(new OneDResultPoint(left, (float) rowNumber));
|
||||||
Ref<OneDResultPoint> resultPoint2(new OneDResultPoint(right, (float) rowNumber));
|
Ref<OneDResultPoint> resultPoint2(new OneDResultPoint(right, (float) rowNumber));
|
||||||
resultPoints[0] = resultPoint1;
|
resultPoints[0] = resultPoint1;
|
||||||
resultPoints[1] = resultPoint2;
|
resultPoints[1] = resultPoint2;
|
||||||
|
|
||||||
ArrayRef<unsigned char> resultBytes(1);
|
ArrayRef<unsigned char> resultBytes(1);
|
||||||
|
|
||||||
Ref<Result> res(new Result(resultString, resultBytes, resultPoints, getBarcodeFormat()));
|
Ref<Result> res(new Result(resultString, resultBytes, resultPoints, getBarcodeFormat()));
|
||||||
delete [] endRange;
|
delete [] endRange;
|
||||||
return res;
|
return res;
|
||||||
|
@ -148,19 +148,18 @@ namespace zxing {
|
||||||
delete [] endRange;
|
delete [] endRange;
|
||||||
throw re;
|
throw re;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int* UPCEANReader::findStartGuardPattern(Ref<BitArray> row){
|
int* UPCEANReader::findStartGuardPattern(Ref<BitArray> row) {
|
||||||
bool foundStart = false;
|
bool foundStart = false;
|
||||||
|
|
||||||
int* startRange = NULL;
|
int* startRange = NULL;
|
||||||
int nextStart = 0;
|
int nextStart = 0;
|
||||||
try {
|
try {
|
||||||
while (!foundStart) {
|
while (!foundStart) {
|
||||||
delete [] startRange;
|
delete [] startRange;
|
||||||
startRange = NULL;
|
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];
|
int start = startRange[0];
|
||||||
nextStart = startRange[1];
|
nextStart = startRange[1];
|
||||||
// Make sure there is a quiet zone at least as big as the start pattern before the barcode.
|
// 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;
|
throw re;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(flyashi): Return a pair<int, int> for return value to avoid using the heap.
|
// 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 patternLength = patternLen;
|
||||||
int counters[patternLength];
|
int counters[patternLength];
|
||||||
int countersCount = sizeof(counters) / sizeof(int);
|
int countersCount = sizeof(counters) / sizeof(int);
|
||||||
|
@ -195,7 +195,7 @@ namespace zxing {
|
||||||
}
|
}
|
||||||
rowOffset++;
|
rowOffset++;
|
||||||
}
|
}
|
||||||
|
|
||||||
int counterPosition = 0;
|
int counterPosition = 0;
|
||||||
int patternStart = rowOffset;
|
int patternStart = rowOffset;
|
||||||
for (int x = rowOffset; x < width; x++) {
|
for (int x = rowOffset; x < width; x++) {
|
||||||
|
@ -204,7 +204,8 @@ namespace zxing {
|
||||||
counters[counterPosition]++;
|
counters[counterPosition]++;
|
||||||
} else {
|
} else {
|
||||||
if (counterPosition == patternLength - 1) {
|
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];
|
int* resultValue = new int[2];
|
||||||
resultValue[0] = patternStart;
|
resultValue[0] = patternStart;
|
||||||
resultValue[1] = x;
|
resultValue[1] = x;
|
||||||
|
@ -226,17 +227,19 @@ namespace zxing {
|
||||||
}
|
}
|
||||||
throw ReaderException("findGuardPattern");
|
throw ReaderException("findGuardPattern");
|
||||||
}
|
}
|
||||||
|
|
||||||
int* UPCEANReader::decodeEnd(Ref<BitArray> row, int endStart){
|
int* UPCEANReader::decodeEnd(Ref<BitArray> row, int endStart) {
|
||||||
return findGuardPattern(row, endStart, false, START_END_PATTERN, sizeof(START_END_PATTERN)/sizeof(int));
|
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, 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,
|
||||||
|
UPC_EAN_PATTERNS patternType) {
|
||||||
recordPattern(row, rowOffset, counters, countersLen);
|
recordPattern(row, rowOffset, counters, countersLen);
|
||||||
unsigned int bestVariance = MAX_AVG_VARIANCE; // worst variance we'll accept
|
unsigned int bestVariance = MAX_AVG_VARIANCE; // worst variance we'll accept
|
||||||
int bestMatch = -1;
|
int bestMatch = -1;
|
||||||
|
|
||||||
int max = 0;
|
int max = 0;
|
||||||
switch (patternType) {
|
switch (patternType) {
|
||||||
case UPC_EAN_PATTERNS_L_PATTERNS:
|
case UPC_EAN_PATTERNS_L_PATTERNS:
|
||||||
|
@ -246,8 +249,9 @@ namespace zxing {
|
||||||
for(int j = 0; j< countersLen; j++){
|
for(int j = 0; j< countersLen; j++){
|
||||||
pattern[j] = L_PATTERNS[i][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) {
|
if (variance < bestVariance) {
|
||||||
bestVariance = variance;
|
bestVariance = variance;
|
||||||
bestMatch = i;
|
bestMatch = i;
|
||||||
|
@ -261,8 +265,9 @@ namespace zxing {
|
||||||
for(int j = 0; j< countersLen; j++){
|
for(int j = 0; j< countersLen; j++){
|
||||||
pattern[j] = L_AND_G_PATTERNS[i][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) {
|
if (variance < bestVariance) {
|
||||||
bestVariance = variance;
|
bestVariance = variance;
|
||||||
bestMatch = i;
|
bestMatch = i;
|
||||||
|
@ -278,15 +283,15 @@ namespace zxing {
|
||||||
throw ReaderException("UPCEANReader::decodeDigit: No best mach");
|
throw ReaderException("UPCEANReader::decodeDigit: No best mach");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return {@link #checkStandardUPCEANChecksum(String)}
|
* @return {@link #checkStandardUPCEANChecksum(String)}
|
||||||
*/
|
*/
|
||||||
bool UPCEANReader::checkChecksum(std::string s){
|
bool UPCEANReader::checkChecksum(std::string s) {
|
||||||
return checkStandardUPCEANChecksum(s);
|
return checkStandardUPCEANChecksum(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Computes the UPC/EAN checksum on a string of digits, and reports
|
* Computes the UPC/EAN checksum on a string of digits, and reports
|
||||||
* whether the checksum is correct or not.
|
* 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
|
* @return true iff string of digits passes the UPC/EAN checksum algorithm
|
||||||
* @throws ReaderException if the string does not contain only digits
|
* @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();
|
int length = s.length();
|
||||||
if (length == 0) {
|
if (length == 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
int sum = 0;
|
int sum = 0;
|
||||||
for (int i = length - 2; i >= 0; i -= 2) {
|
for (int i = length - 2; i >= 0; i -= 2) {
|
||||||
int digit = (int) s[i] - (int) '0';
|
int digit = (int) s[i] - (int) '0';
|
||||||
|
@ -319,7 +324,8 @@ namespace zxing {
|
||||||
}
|
}
|
||||||
return sum % 10 == 0;
|
return sum % 10 == 0;
|
||||||
}
|
}
|
||||||
UPCEANReader::~UPCEANReader(){
|
|
||||||
|
UPCEANReader::~UPCEANReader() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
* UPCEReader.cpp
|
* UPCEReader.cpp
|
||||||
* ZXing
|
* ZXing
|
||||||
*
|
*
|
||||||
* Created by Lukasz Warchol on 10-01-26.
|
|
||||||
* Copyright 2010 ZXing authors All rights reserved.
|
* Copyright 2010 ZXing authors All rights reserved.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
@ -23,13 +22,13 @@
|
||||||
|
|
||||||
namespace zxing {
|
namespace zxing {
|
||||||
namespace oned {
|
namespace oned {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The pattern that marks the middle, and end, of a UPC-E pattern.
|
* The pattern that marks the middle, and end, of a UPC-E pattern.
|
||||||
* There is no "second half" to a UPC-E barcode.
|
* There is no "second half" to a UPC-E barcode.
|
||||||
*/
|
*/
|
||||||
static const int MIDDLE_END_PATTERN[6] = {1, 1, 1, 1, 1, 1};
|
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
|
* 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)
|
* 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},
|
{0x38, 0x34, 0x32, 0x31, 0x2C, 0x26, 0x23, 0x2A, 0x29, 0x25},
|
||||||
{0x07, 0x0B, 0x0D, 0x0E, 0x13, 0x19, 0x1C, 0x15, 0x16, 0x1A}
|
{0x07, 0x0B, 0x0D, 0x0E, 0x13, 0x19, 0x1C, 0x15, 0x16, 0x1A}
|
||||||
};
|
};
|
||||||
|
|
||||||
UPCEReader::UPCEReader(){}
|
UPCEReader::UPCEReader() {
|
||||||
|
}
|
||||||
int UPCEReader::decodeMiddle(Ref<BitArray> row, int startRange[], int startRangeLen, std::string& resultString){
|
|
||||||
|
int UPCEReader::decodeMiddle(Ref<BitArray> row, int startRange[], int startRangeLen,
|
||||||
|
std::string& resultString) {
|
||||||
const int countersLen = 4;
|
const int countersLen = 4;
|
||||||
int counters[countersLen] = { 0, 0, 0, 0 };
|
int counters[countersLen] = { 0, 0, 0, 0 };
|
||||||
|
|
||||||
int end = row->getSize();
|
int end = row->getSize();
|
||||||
int rowOffset = startRange[1];
|
int rowOffset = startRange[1];
|
||||||
|
|
||||||
int lgPatternFound = 0;
|
int lgPatternFound = 0;
|
||||||
|
|
||||||
for (int x = 0; x < 6 && rowOffset < end; x++) {
|
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));
|
resultString.append(1, (char) ('0' + bestMatch % 10));
|
||||||
for (int i = 0; i < countersLen; i++) {
|
for (int i = 0; i < countersLen; i++) {
|
||||||
rowOffset += counters[i];
|
rowOffset += counters[i];
|
||||||
|
@ -61,22 +63,23 @@ namespace zxing {
|
||||||
lgPatternFound |= 1 << (5 - x);
|
lgPatternFound |= 1 << (5 - x);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
determineNumSysAndCheckDigit(resultString, lgPatternFound);
|
determineNumSysAndCheckDigit(resultString, lgPatternFound);
|
||||||
|
|
||||||
return rowOffset;
|
return rowOffset;
|
||||||
}
|
}
|
||||||
|
|
||||||
int* UPCEReader::decodeEnd(Ref<BitArray> row, int endStart){
|
int* UPCEReader::decodeEnd(Ref<BitArray> row, int endStart) {
|
||||||
return findGuardPattern(row, endStart, true, MIDDLE_END_PATTERN, sizeof(MIDDLE_END_PATTERN)/sizeof(int));
|
return findGuardPattern(row, endStart, true, MIDDLE_END_PATTERN,
|
||||||
|
sizeof(MIDDLE_END_PATTERN) / sizeof(int));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool UPCEReader::checkChecksum(std::string s){
|
bool UPCEReader::checkChecksum(std::string s){
|
||||||
return UPCEANReader::checkChecksum(convertUPCEtoUPCA(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 numSys = 0; numSys <= 1; numSys++) {
|
||||||
for (int d = 0; d < 10; d++) {
|
for (int d = 0; d < 10; d++) {
|
||||||
if (lgPatternFound == NUMSYS_AND_CHECK_DIGIT_PATTERNS[numSys][d]) {
|
if (lgPatternFound == NUMSYS_AND_CHECK_DIGIT_PATTERNS[numSys][d]) {
|
||||||
|
@ -88,7 +91,7 @@ namespace zxing {
|
||||||
}
|
}
|
||||||
throw ReaderException("determineNumSysAndCheckDigit exception");
|
throw ReaderException("determineNumSysAndCheckDigit exception");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Expands a UPC-E value back into its full, equivalent UPC-A code value.
|
* 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]);
|
result.append(1, upce[7]);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
BarcodeFormat UPCEReader::getBarcodeFormat(){
|
BarcodeFormat UPCEReader::getBarcodeFormat() {
|
||||||
return BarcodeFormat_UPC_E;
|
return BarcodeFormat_UPC_E;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue