C++ port: some memory leak cleanups

Closes Issue 499 and Issue 496.

git-svn-id: https://zxing.googlecode.com/svn/trunk@1510 59b500cc-1b3d-0410-9834-0bbf25fbcc57
This commit is contained in:
flyashi 2010-08-06 18:59:07 +00:00
parent 2de913d220
commit 5a4f5c901d
8 changed files with 903 additions and 895 deletions

View file

@ -27,16 +27,16 @@
#include <zxing/ReaderException.h> #include <zxing/ReaderException.h>
namespace zxing { namespace zxing {
MultiFormatReader::MultiFormatReader() { MultiFormatReader::MultiFormatReader() {
} }
Ref<Result> MultiFormatReader::decode(Ref<BinaryBitmap> image) { Ref<Result> MultiFormatReader::decode(Ref<BinaryBitmap> image) {
setHints(DecodeHints::DEFAULT_HINT); setHints(DecodeHints::DEFAULT_HINT);
return decodeInternal(image); return decodeInternal(image);
} }
Ref<Result> MultiFormatReader::decode(Ref<BinaryBitmap> image, DecodeHints hints) { Ref<Result> MultiFormatReader::decode(Ref<BinaryBitmap> image, DecodeHints hints) {
setHints(hints); setHints(hints);
return decodeInternal(image); return decodeInternal(image);
} }
@ -62,43 +62,41 @@ namespace zxing {
hints.containsFormat(BarcodeFormat_CODE_39) || hints.containsFormat(BarcodeFormat_CODE_39) ||
hints.containsFormat(BarcodeFormat_ITF); hints.containsFormat(BarcodeFormat_ITF);
if (addOneDReader && !tryHarder) { if (addOneDReader && !tryHarder) {
readers_.push_back(new zxing::oned::MultiFormatOneDReader(hints)); readers_.push_back(Ref<Reader>(new zxing::oned::MultiFormatOneDReader(hints)));
} }
if (hints.containsFormat(BarcodeFormat_QR_CODE)) { if (hints.containsFormat(BarcodeFormat_QR_CODE)) {
readers_.push_back(new zxing::qrcode::QRCodeReader()); readers_.push_back(Ref<Reader>(new zxing::qrcode::QRCodeReader()));
} }
if (hints.containsFormat(BarcodeFormat_DATA_MATRIX)) { if (hints.containsFormat(BarcodeFormat_DATA_MATRIX)) {
readers_.push_back(new zxing::datamatrix::DataMatrixReader()); readers_.push_back(Ref<Reader>(new zxing::datamatrix::DataMatrixReader()));
} }
//TODO: add PDF417 here once PDF417 reader is implemented //TODO: add PDF417 here once PDF417 reader is implemented
if (addOneDReader && tryHarder) { if (addOneDReader && tryHarder) {
readers_.push_back(new zxing::oned::MultiFormatOneDReader(hints)); readers_.push_back(Ref<Reader>(new zxing::oned::MultiFormatOneDReader(hints)));
} }
if (readers_.size() == 0) { if (readers_.size() == 0) {
if (!tryHarder) { if (!tryHarder) {
readers_.push_back(new zxing::oned::MultiFormatOneDReader(hints)); readers_.push_back(Ref<Reader>(new zxing::oned::MultiFormatOneDReader(hints)));
} }
readers_.push_back(new zxing::qrcode::QRCodeReader()); readers_.push_back(Ref<Reader>(new zxing::qrcode::QRCodeReader()));
if (tryHarder) { if (tryHarder) {
readers_.push_back(new zxing::oned::MultiFormatOneDReader(hints)); readers_.push_back(Ref<Reader>(new zxing::oned::MultiFormatOneDReader(hints)));
} }
} }
} }
Ref<Result> MultiFormatReader::decodeInternal(Ref<BinaryBitmap> image) { Ref<Result> MultiFormatReader::decodeInternal(Ref<BinaryBitmap> image) {
for (unsigned int i = 0; i < readers_.size(); i++) { for (unsigned int i = 0; i < readers_.size(); i++) {
try { try {
return readers_[i]->decode(image, hints_); return readers_[i]->decode(image, hints_);
} catch (ReaderException re) { } catch (ReaderException re) {
// continue // continue
} }
} }
throw ReaderException("No code detected"); throw ReaderException("No code detected");
} }
MultiFormatReader::~MultiFormatReader(){ MultiFormatReader::~MultiFormatReader() {
for (unsigned int i = 0; i < readers_.size(); i++) {
delete readers_[i]; }
}
}
} }

View file

@ -27,23 +27,23 @@
#include <zxing/DecodeHints.h> #include <zxing/DecodeHints.h>
namespace zxing { namespace zxing {
class MultiFormatReader : public Reader { class MultiFormatReader : public Reader {
private: private:
Ref<Result> decodeInternal(Ref<BinaryBitmap> image); Ref<Result> decodeInternal(Ref<BinaryBitmap> image);
std::vector<Reader*> readers_; std::vector<Ref<Reader> > readers_;
DecodeHints hints_; DecodeHints hints_;
public: public:
MultiFormatReader(); MultiFormatReader();
Ref<Result> decode(Ref<BinaryBitmap> image); Ref<Result> decode(Ref<BinaryBitmap> image);
Ref<Result> decode(Ref<BinaryBitmap> image, DecodeHints hints); Ref<Result> decode(Ref<BinaryBitmap> image, DecodeHints hints);
Ref<Result> decodeWithState(Ref<BinaryBitmap> image); Ref<Result> decodeWithState(Ref<BinaryBitmap> image);
void setHints(DecodeHints hints); void setHints(DecodeHints hints);
~MultiFormatReader(); ~MultiFormatReader();
}; };
} }
#endif #endif

View file

@ -55,35 +55,41 @@ Ref<BitArray> GlobalHistogramBinarizer::getBlackRow(int y, Ref<BitArray> row) {
} }
//TODO(flyashi): cache this instead of allocating and deleting per row //TODO(flyashi): cache this instead of allocating and deleting per row
unsigned char* row_pixels = new unsigned char[width]; unsigned char* row_pixels = NULL;
getLuminanceSource()->getRow(y,row_pixels); try {
for (int x = 0; x < width; x++) { row_pixels = new unsigned char[width];
histogram[row_pixels[x] >> LUMINANCE_SHIFT]++; getLuminanceSource()->getRow(y,row_pixels);
for (int x = 0; x < width; x++) {
histogram[row_pixels[x] >> LUMINANCE_SHIFT]++;
}
int blackPoint = estimate(histogram) << LUMINANCE_SHIFT;
Ref<BitArray> array_ref(new BitArray(width));
BitArray& array = *array_ref;
int left = row_pixels[0];
int center = row_pixels[1];
for (int x = 1; x < width - 1; x++) {
int right = row_pixels[x + 1];
// A simple -1 4 -1 box filter with a weight of 2.
int luminance = ((center << 2) - left - right) >> 1;
if (luminance < blackPoint) {
array.set(x);
}
left = center;
center = right;
}
cached_row_ = array_ref;
cached_row_num_ = y;
delete [] row_pixels;
return array_ref;
} catch (IllegalArgumentException const& iae) {
delete [] row_pixels;
throw iae;
} }
int blackPoint = estimate(histogram) << LUMINANCE_SHIFT;
Ref<BitArray> array_ref(new BitArray(width));
BitArray& array = *array_ref;
int left = row_pixels[0];
int center = row_pixels[1];
for (int x = 1; x < width - 1; x++) {
int right = row_pixels[x + 1];
// A simple -1 4 -1 box filter with a weight of 2.
int luminance = ((center << 2) - left - right) >> 1;
if (luminance < blackPoint) {
array.set(x);
}
left = center;
center = right;
}
cached_row_ = array_ref;
cached_row_num_ = y;
delete [] row_pixels;
return array_ref;
} }
Ref<BitMatrix> GlobalHistogramBinarizer::getBlackMatrix() { Ref<BitMatrix> GlobalHistogramBinarizer::getBlackMatrix() {

View file

@ -75,112 +75,108 @@ namespace oned {
} }
Code39Reader::Code39Reader(bool usingCheckDigit_, bool extendedMode_) :
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 = findAsteriskPattern(row); int* start = NULL;
int nextStart = start[1]; try {
int end = row->getSize(); start = findAsteriskPattern(row);
int nextStart = start[1];
int end = row->getSize();
// Read off white space
while (nextStart < end && !row->get(nextStart)) {
nextStart++;
}
std::string tmpResultString;
int countersLen = 9;
int* counters = new int[countersLen];
for (int i=0; i<countersLen; i++) {
counters[i] = 0;
}
char decodedChar;
int lastStart;
do {
try {
recordPattern(row, nextStart, counters, countersLen);
} catch (ReaderException re) {
delete [] start;
throw re;
}
int pattern = toNarrowWidePattern(counters, countersLen);
if (pattern < 0) {
delete [] start;
throw ReaderException("pattern < 0");
}
decodedChar = patternToChar(pattern);
tmpResultString.append(1, decodedChar);
lastStart = nextStart;
for (int i = 0; i < countersLen; i++) {
nextStart += counters[i];
}
// Read off white space // Read off white space
while (nextStart < end && !row->get(nextStart)) { while (nextStart < end && !row->get(nextStart)) {
nextStart++; nextStart++;
} }
} while (decodedChar != '*');
tmpResultString.erase(tmpResultString.length()-1, 1);// remove asterisk
// Look for whitespace after pattern: std::string tmpResultString;
int lastPatternSize = 0;
for (int i = 0; i < countersLen; i++) {
lastPatternSize += counters[i];
}
// IS begin
delete [] counters;
// IS end
int whiteSpaceAfterEnd = nextStart - lastStart - lastPatternSize;
// If 50% of last pattern size, following last pattern, is not whitespace,
// fail (but if it's whitespace to the very end of the image, that's OK)
if (nextStart != end && whiteSpaceAfterEnd / 2 < lastPatternSize) {
delete [] start;
throw ReaderException("too short end white space");
}
if (usingCheckDigit) { const int countersLen = 9;
int max = tmpResultString.length() - 1; int counters[countersLen];
unsigned int total = 0; for (int i = 0; i < countersLen; i++) {
for (int i = 0; i < max; i++) { counters[i] = 0;
total += alphabet_string.find_first_of(tmpResultString[i], 0);
} }
if (total % 43 != alphabet_string.find_first_of(tmpResultString[max], 0)) { char decodedChar;
int lastStart;
do {
recordPattern(row, nextStart, counters, countersLen);
int pattern = toNarrowWidePattern(counters, countersLen);
if (pattern < 0) {
throw ReaderException("pattern < 0");
}
decodedChar = patternToChar(pattern);
tmpResultString.append(1, decodedChar);
lastStart = nextStart;
for (int i = 0; i < countersLen; i++) {
nextStart += counters[i];
}
// Read off white space
while (nextStart < end && !row->get(nextStart)) {
nextStart++;
}
} while (decodedChar != '*');
tmpResultString.erase(tmpResultString.length()-1, 1);// remove asterisk
// Look for whitespace after pattern:
int lastPatternSize = 0;
for (int i = 0; i < countersLen; i++) {
lastPatternSize += counters[i];
}
int whiteSpaceAfterEnd = nextStart - lastStart - lastPatternSize;
// If 50% of last pattern size, following last pattern, is not whitespace,
// fail (but if it's whitespace to the very end of the image, that's OK)
if (nextStart != end && whiteSpaceAfterEnd / 2 < lastPatternSize) {
throw ReaderException("too short end white space");
}
if (usingCheckDigit) {
int max = tmpResultString.length() - 1;
unsigned int total = 0;
for (int i = 0; i < max; i++) {
total += alphabet_string.find_first_of(tmpResultString[i], 0);
}
if (total % 43 != alphabet_string.find_first_of(tmpResultString[max], 0)) {
throw ReaderException("");
}
tmpResultString.erase(max, 1);
}
Ref<String> resultString(new String(tmpResultString));
if (extendedMode) {
resultString = decodeExtended(tmpResultString);
}
if (tmpResultString.length() == 0) {
// Almost surely a false positive
throw ReaderException(""); throw ReaderException("");
} }
tmpResultString.erase(max, 1);
}
float left = (float) (start[1] + start[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);
Ref<String> resultString(new String(tmpResultString)); Ref<Result> res(new Result(
if (extendedMode) { resultString, resultBytes, resultPoints, BarcodeFormat_CODE_39));
delete resultString;
resultString = decodeExtended(tmpResultString);
}
if (tmpResultString.length() == 0) {
delete [] start; delete [] start;
// Almost surely a false positive return res;
throw ReaderException(""); } catch (ReaderException const& re) {
delete [] start;
throw re;
} }
float left = (float) (start[1] + start[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 [] start;
Ref<Result> res(new Result(
resultString, resultBytes, resultPoints, BarcodeFormat_CODE_39));
return res;
} }
int* Code39Reader::findAsteriskPattern(Ref<BitArray> row){ int* Code39Reader::findAsteriskPattern(Ref<BitArray> row){
@ -194,9 +190,9 @@ namespace oned {
} }
int counterPosition = 0; int counterPosition = 0;
int countersLen = 9; const int countersLen = 9;
int* counters = new int[countersLen]; int counters[countersLen];
for (int i=0; i<countersLen; i++) { for (int i = 0; i < countersLen; i++) {
counters[i] = 0; counters[i] = 0;
} }
int patternStart = rowOffset; int patternStart = rowOffset;
@ -235,9 +231,6 @@ namespace oned {
isWhite = !isWhite; isWhite = !isWhite;
} }
} }
// IS begin
delete [] counters;
// IS end
throw ReaderException(""); throw ReaderException("");
} }

View file

@ -22,62 +22,69 @@
#include <zxing/ReaderException.h> #include <zxing/ReaderException.h>
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];
} }
if (bestMatch >= 10) { if (bestMatch >= 10) {
lgPatternFound |= 1 << (5 - x); lgPatternFound |= 1 << (5 - x);
} }
} }
determineFirstDigit(resultString, lgPatternFound); determineFirstDigit(resultString, lgPatternFound);
int* middleRange = findGuardPattern(row, rowOffset, true, (int*)getMIDDLE_PATTERN(), getMIDDLE_PATTERN_LEN()); int* middleRange = 0;
rowOffset = middleRange[1]; try {
middleRange = findGuardPattern(row, rowOffset, true, (int*)getMIDDLE_PATTERN(), getMIDDLE_PATTERN_LEN());
for (int x = 0; x < 6 && rowOffset < end; x++) { rowOffset = middleRange[1];
int bestMatch = decodeDigit(row, counters, countersLen, rowOffset, UPC_EAN_PATTERNS_L_PATTERNS);
resultString.append(1, (char) ('0' + bestMatch)); for (int x = 0; x < 6 && rowOffset < end; x++) {
for (int i = 0; i < countersLen; i++) { int bestMatch = decodeDigit(row, counters, countersLen, rowOffset, UPC_EAN_PATTERNS_L_PATTERNS);
rowOffset += counters[i]; resultString.append(1, (char) ('0' + bestMatch));
} for (int i = 0; i < countersLen; i++) {
} rowOffset += counters[i];
}
return rowOffset; }
}
delete [] middleRange;
void EAN13Reader::determineFirstDigit(std::string& resultString, int lgPatternFound){ return rowOffset;
for (int d = 0; d < 10; d++) { } catch (ReaderException const& re) {
if (lgPatternFound == FIRST_DIGIT_ENCODINGS[d]) { delete [] middleRange;
resultString.insert(0, 1, (char) ('0' + d)); throw re;
return; }
} }
}
throw ReaderException("determineFirstDigit"); void EAN13Reader::determineFirstDigit(std::string& resultString, int lgPatternFound){
} for (int d = 0; d < 10; d++) {
if (lgPatternFound == FIRST_DIGIT_ENCODINGS[d]) {
BarcodeFormat EAN13Reader::getBarcodeFormat(){ resultString.insert(0, 1, (char) ('0' + d));
return BarcodeFormat_EAN_13; return;
} }
} }
throw ReaderException("determineFirstDigit");
}
BarcodeFormat EAN13Reader::getBarcodeFormat(){
return BarcodeFormat_EAN_13;
}
}
} }

View file

@ -22,41 +22,48 @@
#include <zxing/ReaderException.h> #include <zxing/ReaderException.h>
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 = findGuardPattern(row, rowOffset, true, (int*)getMIDDLE_PATTERN(), getMIDDLE_PATTERN_LEN()); int* middleRange = 0;
rowOffset = middleRange[1]; try {
middleRange = findGuardPattern(row, rowOffset, true, (int*)getMIDDLE_PATTERN(), getMIDDLE_PATTERN_LEN());
for (int x = 0; x < 4 && rowOffset < end; x++) { rowOffset = middleRange[1];
int bestMatch = decodeDigit(row, counters, countersLen, rowOffset, UPC_EAN_PATTERNS_L_PATTERNS);
resultString.append(1, (char) ('0' + bestMatch)); for (int x = 0; x < 4 && rowOffset < end; x++) {
for (int i = 0; i < countersLen; i++) { int bestMatch = decodeDigit(row, counters, countersLen, rowOffset, UPC_EAN_PATTERNS_L_PATTERNS);
rowOffset += counters[i]; resultString.append(1, (char) ('0' + bestMatch));
} for (int i = 0; i < countersLen; i++) {
} rowOffset += counters[i];
}
return rowOffset; }
}
delete [] middleRange;
BarcodeFormat EAN8Reader::getBarcodeFormat(){ return rowOffset;
return BarcodeFormat_EAN_8; } catch (ReaderException const& re) {
} delete [] middleRange;
} throw re;
}
}
BarcodeFormat EAN8Reader::getBarcodeFormat(){
return BarcodeFormat_EAN_8;
}
}
} }

View file

@ -25,340 +25,341 @@
#include <math.h> #include <math.h>
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.
* *
* Note: The end pattern is reversed because the row is reversed before * Note: The end pattern is reversed because the row is reversed before
* searching for the END_PATTERN * searching for the END_PATTERN
*/ */
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
*/ */
static const int PATTERNS_LEN = 10; static const int PATTERNS_LEN = 10;
static const int PATTERNS[PATTERNS_LEN][5] = { static const int PATTERNS[PATTERNS_LEN][5] = {
{N, N, W, W, N}, // 0 {N, N, W, W, N}, // 0
{W, N, N, N, W}, // 1 {W, N, N, N, W}, // 1
{N, W, N, N, W}, // 2 {N, W, N, N, W}, // 2
{W, W, N, N, N}, // 3 {W, W, N, N, N}, // 3
{N, N, W, N, W}, // 4 {N, N, W, N, W}, // 4
{W, N, W, N, N}, // 5 {W, N, W, N, N}, // 5
{N, W, W, N, N}, // 6 {N, W, W, N, N}, // 6
{N, N, N, W, W}, // 7 {N, N, N, W, W}, // 7
{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){
// Find out where the Middle section (payload) starts & ends int* startRange = 0;
int* startRange = decodeStart(row); int* endRange = 0;
int* endRange; try {
try { // Find out where the Middle section (payload) starts & ends
endRange = decodeEnd(row); startRange = decodeStart(row);
} catch (ReaderException re) { endRange = decodeEnd(row);
delete [] startRange;
throw re; std::string tmpResult;
} decodeMiddle(row, startRange[1], endRange[0], tmpResult);
std::string tmpResult; // To avoid false positives with 2D barcodes (and other patterns), make
try { // an assumption that the decoded string must be 6, 10 or 14 digits.
decodeMiddle(row, startRange[1], endRange[0], tmpResult); int length = tmpResult.length();
} catch (zxing::ReaderException re) { bool lengthOK = false;
delete [] startRange; if (length == 6 || length == 10 || length == 14) {
delete [] endRange; lengthOK = true;
throw re; }
} if (!lengthOK) {
throw ReaderException("not enough characters count");
// 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(); Ref<String> resultString(new String(tmpResult));
bool lengthOK = false;
if (length == 6 || length == 10 || length == 14) { std::vector< Ref<ResultPoint> > resultPoints(2);
lengthOK = true; Ref<OneDResultPoint> resultPoint1(new OneDResultPoint(startRange[1], (float) rowNumber));
} Ref<OneDResultPoint> resultPoint2(new OneDResultPoint(endRange[0], (float) rowNumber));
if (!lengthOK) { resultPoints[0] = resultPoint1;
delete [] startRange; resultPoints[1] = resultPoint2;
delete [] endRange;
throw ReaderException("not enough characters count"); ArrayRef<unsigned char> resultBytes(1);
}
Ref<Result> res(new Result(resultString, resultBytes, resultPoints, BarcodeFormat_ITF));
Ref<String> resultString(new String(tmpResult)); delete [] startRange;
delete [] endRange;
std::vector< Ref<ResultPoint> > resultPoints(2); return res;
Ref<OneDResultPoint> resultPoint1(new OneDResultPoint(startRange[1], (float) rowNumber)); } catch (ReaderException re) {
Ref<OneDResultPoint> resultPoint2(new OneDResultPoint(endRange[0], (float) rowNumber)); delete [] startRange;
resultPoints[0] = resultPoint1; delete [] endRange;
resultPoints[1] = resultPoint2; throw re;
}
ArrayRef<unsigned char> resultBytes(1); }
delete [] startRange; /**
delete [] endRange; * @param row row of black/white values to search
* @param payloadStart offset of start pattern
Ref<Result> res(new Result(resultString, resultBytes, resultPoints, BarcodeFormat_ITF)); * @param resultString {@link StringBuffer} to append decoded chars to
return res; * @throws ReaderException if decoding could not complete successfully
} */
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
* @param row row of black/white values to search // 5
* @param payloadStart offset of start pattern // interleaved white lines for the second digit.
* @param resultString {@link StringBuffer} to append decoded chars to // Therefore, need to scan 10 lines and then
* @throws ReaderException if decoding could not complete successfully // split these into two arrays
*/ int counterDigitPairLen = 10;
void ITFReader::decodeMiddle(Ref<BitArray> row, int payloadStart, int payloadEnd, std::string& resultString){ int counterDigitPair[counterDigitPairLen];
// Digits are interleaved in pairs - 5 black lines for one digit, and the for (int i=0; i<counterDigitPairLen; i++) {
// 5 counterDigitPair[i] = 0;
// interleaved white lines for the second digit. }
// Therefore, need to scan 10 lines and then
// split these into two arrays int counterBlack[5];
int counterDigitPairLen = 10; int counterWhite[5];
int counterDigitPair[counterDigitPairLen]; for (int i=0; i<5; i++) {
for (int i=0; i<counterDigitPairLen; i++) { counterBlack[i] = 0;
counterDigitPair[i] = 0; counterWhite[i] = 0;
} }
int counterBlack[5]; while (payloadStart < payloadEnd) {
int counterWhite[5]; // Get 10 runs of black/white.
for (int i=0; i<5; i++) { recordPattern(row, payloadStart, counterDigitPair, counterDigitPairLen);
counterBlack[i] = 0; // Split them into each array
counterWhite[i] = 0; for (int k = 0; k < 5; k++) {
} int twoK = k << 1;
counterBlack[k] = counterDigitPair[twoK];
while (payloadStart < payloadEnd) { counterWhite[k] = counterDigitPair[twoK + 1];
// Get 10 runs of black/white. }
recordPattern(row, payloadStart, counterDigitPair, counterDigitPairLen);
// Split them into each array int bestMatch = decodeDigit(counterBlack, 5);
for (int k = 0; k < 5; k++) { resultString.append(1, (char) ('0' + bestMatch));
int twoK = k << 1; bestMatch = decodeDigit(counterWhite, 5);
counterBlack[k] = counterDigitPair[twoK]; resultString.append(1, (char) ('0' + bestMatch));
counterWhite[k] = counterDigitPair[twoK + 1];
} for (int i = 0; i < counterDigitPairLen; i++) {
payloadStart += counterDigitPair[i];
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++) { * Identify where the start of the middle / payload section starts.
payloadStart += counterDigitPair[i]; *
} * @param row row of black/white values to search
} * @return Array, containing index of start of 'start block' and end of
} * 'start block'
* @throws ReaderException
/** */
* Identify where the start of the middle / payload section starts. int* ITFReader::decodeStart(Ref<BitArray> row){
* int endStart = skipWhiteSpace(row);
* @param row row of black/white values to search /// static int* findGuardPattern(Ref<BitArray> row, int rowOffset, bool whiteFirst, const int pattern[], int patternLen);
* @return Array, containing index of start of 'start block' and end of int* startPattern = 0;
* 'start block' try {
* @throws ReaderException startPattern = findGuardPattern(row, endStart, START_PATTERN, START_PATTERN_LEN);
*/
int* ITFReader::decodeStart(Ref<BitArray> row){ // Determine the width of a narrow line in pixels. We can do this by
int endStart = skipWhiteSpace(row); // getting the width of the start pattern and dividing by 4 because its
/// static int* findGuardPattern(Ref<BitArray> row, int rowOffset, bool whiteFirst, const int pattern[], int patternLen); // made up of 4 narrow lines.
int* startPattern = findGuardPattern(row, endStart, START_PATTERN, START_PATTERN_LEN); narrowLineWidth = (startPattern[1] - startPattern[0]) >> 2;
// Determine the width of a narrow line in pixels. We can do this by validateQuietZone(row, startPattern[0]);
// getting the width of the start pattern and dividing by 4 because its
// made up of 4 narrow lines. return startPattern;
narrowLineWidth = (startPattern[1] - startPattern[0]) >> 2; } catch (ReaderException re) {
delete [] startPattern;
validateQuietZone(row, startPattern[0]); throw re;
}
return startPattern; }
}
/**
/** * Identify where the end of the middle / payload section ends.
* Identify where the end of the middle / payload section ends. *
* * @param row row of black/white values to search
* @param row row of black/white values to search * @return Array, containing index of start of 'end block' and end of 'end
* @return Array, containing index of start of 'end block' and end of 'end * 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(); int* endPattern = 0;
try { try {
int endStart = skipWhiteSpace(row); int endStart = skipWhiteSpace(row);
int* 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) {
row->reverse(); delete [] endPattern;
throw re; 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 * The start & end patterns must be pre/post fixed by a quiet zone. This
* we either get to the start of the barcode or match the necessary number of * zone must be at least 10 times the width of a narrow line. Scan back until
* quiet zone pixels. * we either get to the start of the barcode or match the necessary number of
* * quiet zone pixels.
* Note: Its assumed the row is reversed when using this method to find *
* quiet zone after the end pattern. * Note: Its assumed the row is reversed when using this method to find
* * quiet zone after the end pattern.
* ref: http://www.barcode-1.net/i25code.html *
* * ref: http://www.barcode-1.net/i25code.html
* @param row bit array representing the scanned barcode. *
* @param startPattern index into row of the start or end pattern. * @param row bit array representing the scanned barcode.
* @throws ReaderException if the quiet zone cannot be found, a ReaderException is thrown. * @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 //#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;
// } // }
// quietCount--; // quietCount--;
// } // }
// if (quietCount != 0) { // if (quietCount != 0) {
// // Unable to find the necessary number of quiet zone pixels. // // Unable to find the necessary number of quiet zone pixels.
// 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.
* *
* @param row row of black/white values to search * @param row row of black/white values to search
* @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) {
if (row->get(endStart)) { if (row->get(endStart)) {
break; break;
} }
endStart++; endStart++;
} }
if (endStart == width) { if (endStart == width) {
throw ReaderException(""); throw ReaderException("");
} }
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
* @param pattern pattern of counts of number of black and white pixels that are * @param pattern pattern of counts of number of black and white pixels that are
* being searched for as a pattern * being searched for as a pattern
* @return start/end horizontal offset of guard pattern, as an array of two * @return start/end horizontal offset of guard pattern, as an array of two
* 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 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 // 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;
int counters[patternLength]; int counters[patternLength];
for (int i=0; i<patternLength; i++) { for (int i=0; i<patternLength; i++) {
counters[i] = 0; counters[i] = 0;
} }
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++) {
bool pixel = row->get(x); bool pixel = row->get(x);
if (pixel ^ isWhite) { if (pixel ^ isWhite) {
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;
return resultValue; return resultValue;
} }
patternStart += counters[0] + counters[1]; patternStart += counters[0] + counters[1];
for (int y = 2; y < patternLength; y++) { for (int y = 2; y < patternLength; y++) {
counters[y - 2] = counters[y]; counters[y - 2] = counters[y];
} }
counters[patternLength - 2] = 0; counters[patternLength - 2] = 0;
counters[patternLength - 1] = 0; counters[patternLength - 1] = 0;
counterPosition--; counterPosition--;
} else { } else {
counterPosition++; counterPosition++;
} }
counters[counterPosition] = 1; counters[counterPosition] = 1;
isWhite = !isWhite; isWhite = !isWhite;
} }
} }
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.
* *
* @param counters the counts of runs of observed black/white/black/... values * @param counters the counts of runs of observed black/white/black/... values
* @return The decoded digit * @return The decoded digit
* @throws ReaderException if digit cannot be decoded * @throws ReaderException if digit cannot be decoded
*/ */
int ITFReader::decodeDigit(int counters[], int countersLen){ int ITFReader::decodeDigit(int counters[], int 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 = 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;
} }
} }
if (bestMatch >= 0) { if (bestMatch >= 0) {
return bestMatch; return bestMatch;
} else { } else {
throw ReaderException("digit didint found"); throw ReaderException("digit didint found");
} }
} }
ITFReader::~ITFReader(){ ITFReader::~ITFReader(){
} }
} }
} }

View file

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