mirror of
https://github.com/zxing/zxing.git
synced 2025-01-13 20:27:34 -08:00
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:
parent
2de913d220
commit
5a4f5c901d
|
@ -27,16 +27,16 @@
|
|||
#include <zxing/ReaderException.h>
|
||||
|
||||
namespace zxing {
|
||||
MultiFormatReader::MultiFormatReader() {
|
||||
MultiFormatReader::MultiFormatReader() {
|
||||
|
||||
}
|
||||
|
||||
Ref<Result> MultiFormatReader::decode(Ref<BinaryBitmap> image) {
|
||||
setHints(DecodeHints::DEFAULT_HINT);
|
||||
return decodeInternal(image);
|
||||
}
|
||||
}
|
||||
|
||||
Ref<Result> MultiFormatReader::decode(Ref<BinaryBitmap> image) {
|
||||
setHints(DecodeHints::DEFAULT_HINT);
|
||||
return decodeInternal(image);
|
||||
}
|
||||
|
||||
Ref<Result> MultiFormatReader::decode(Ref<BinaryBitmap> image, DecodeHints hints) {
|
||||
Ref<Result> MultiFormatReader::decode(Ref<BinaryBitmap> image, DecodeHints hints) {
|
||||
setHints(hints);
|
||||
return decodeInternal(image);
|
||||
}
|
||||
|
@ -62,43 +62,41 @@ namespace zxing {
|
|||
hints.containsFormat(BarcodeFormat_CODE_39) ||
|
||||
hints.containsFormat(BarcodeFormat_ITF);
|
||||
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)) {
|
||||
readers_.push_back(new zxing::qrcode::QRCodeReader());
|
||||
readers_.push_back(Ref<Reader>(new zxing::qrcode::QRCodeReader()));
|
||||
}
|
||||
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
|
||||
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 (!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) {
|
||||
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) {
|
||||
for (unsigned int i = 0; i < readers_.size(); i++) {
|
||||
try {
|
||||
return readers_[i]->decode(image, hints_);
|
||||
} catch (ReaderException re) {
|
||||
// continue
|
||||
}
|
||||
}
|
||||
throw ReaderException("No code detected");
|
||||
}
|
||||
|
||||
MultiFormatReader::~MultiFormatReader(){
|
||||
for (unsigned int i = 0; i < readers_.size(); i++) {
|
||||
delete readers_[i];
|
||||
}
|
||||
}
|
||||
Ref<Result> MultiFormatReader::decodeInternal(Ref<BinaryBitmap> image) {
|
||||
for (unsigned int i = 0; i < readers_.size(); i++) {
|
||||
try {
|
||||
return readers_[i]->decode(image, hints_);
|
||||
} catch (ReaderException re) {
|
||||
// continue
|
||||
}
|
||||
}
|
||||
throw ReaderException("No code detected");
|
||||
}
|
||||
|
||||
MultiFormatReader::~MultiFormatReader() {
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,23 +27,23 @@
|
|||
#include <zxing/DecodeHints.h>
|
||||
|
||||
namespace zxing {
|
||||
class MultiFormatReader : public Reader {
|
||||
|
||||
private:
|
||||
Ref<Result> decodeInternal(Ref<BinaryBitmap> image);
|
||||
|
||||
std::vector<Reader*> readers_;
|
||||
DecodeHints hints_;
|
||||
class MultiFormatReader : public Reader {
|
||||
|
||||
private:
|
||||
Ref<Result> decodeInternal(Ref<BinaryBitmap> image);
|
||||
|
||||
std::vector<Ref<Reader> > readers_;
|
||||
DecodeHints hints_;
|
||||
|
||||
public:
|
||||
MultiFormatReader();
|
||||
|
||||
Ref<Result> decode(Ref<BinaryBitmap> image);
|
||||
Ref<Result> decode(Ref<BinaryBitmap> image, DecodeHints hints);
|
||||
public:
|
||||
MultiFormatReader();
|
||||
|
||||
Ref<Result> decode(Ref<BinaryBitmap> image);
|
||||
Ref<Result> decode(Ref<BinaryBitmap> image, DecodeHints hints);
|
||||
Ref<Result> decodeWithState(Ref<BinaryBitmap> image);
|
||||
void setHints(DecodeHints hints);
|
||||
~MultiFormatReader();
|
||||
};
|
||||
~MultiFormatReader();
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -55,35 +55,41 @@ Ref<BitArray> GlobalHistogramBinarizer::getBlackRow(int y, Ref<BitArray> row) {
|
|||
}
|
||||
|
||||
//TODO(flyashi): cache this instead of allocating and deleting per row
|
||||
unsigned char* row_pixels = new unsigned char[width];
|
||||
getLuminanceSource()->getRow(y,row_pixels);
|
||||
for (int x = 0; x < width; x++) {
|
||||
histogram[row_pixels[x] >> LUMINANCE_SHIFT]++;
|
||||
unsigned char* row_pixels = NULL;
|
||||
try {
|
||||
row_pixels = new unsigned char[width];
|
||||
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() {
|
||||
|
|
|
@ -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){
|
||||
int* start = findAsteriskPattern(row);
|
||||
int nextStart = start[1];
|
||||
int end = row->getSize();
|
||||
int* start = NULL;
|
||||
try {
|
||||
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
|
||||
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];
|
||||
}
|
||||
// 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");
|
||||
}
|
||||
std::string tmpResultString;
|
||||
|
||||
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);
|
||||
const int countersLen = 9;
|
||||
int counters[countersLen];
|
||||
for (int i = 0; i < countersLen; i++) {
|
||||
counters[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("");
|
||||
}
|
||||
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));
|
||||
if (extendedMode) {
|
||||
delete resultString;
|
||||
resultString = decodeExtended(tmpResultString);
|
||||
}
|
||||
Ref<Result> res(new Result(
|
||||
resultString, resultBytes, resultPoints, BarcodeFormat_CODE_39));
|
||||
|
||||
if (tmpResultString.length() == 0) {
|
||||
delete [] start;
|
||||
// Almost surely a false positive
|
||||
throw ReaderException("");
|
||||
return res;
|
||||
} 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){
|
||||
|
@ -194,9 +190,9 @@ namespace oned {
|
|||
}
|
||||
|
||||
int counterPosition = 0;
|
||||
int countersLen = 9;
|
||||
int* counters = new int[countersLen];
|
||||
for (int i=0; i<countersLen; i++) {
|
||||
const int countersLen = 9;
|
||||
int counters[countersLen];
|
||||
for (int i = 0; i < countersLen; i++) {
|
||||
counters[i] = 0;
|
||||
}
|
||||
int patternStart = rowOffset;
|
||||
|
@ -235,9 +231,6 @@ namespace oned {
|
|||
isWhite = !isWhite;
|
||||
}
|
||||
}
|
||||
// IS begin
|
||||
delete [] counters;
|
||||
// IS end
|
||||
throw ReaderException("");
|
||||
}
|
||||
|
||||
|
|
|
@ -22,62 +22,69 @@
|
|||
#include <zxing/ReaderException.h>
|
||||
|
||||
namespace zxing {
|
||||
namespace oned {
|
||||
|
||||
static const int FIRST_DIGIT_ENCODINGS[10] = {0x00, 0x0B, 0x0D, 0xE, 0x13, 0x19, 0x1C, 0x15, 0x16, 0x1A};
|
||||
|
||||
|
||||
EAN13Reader::EAN13Reader() { }
|
||||
|
||||
int EAN13Reader::decodeMiddle(Ref<BitArray> row, int startRange[], int startRangeLen, std::string& resultString){
|
||||
const int countersLen = 4;
|
||||
int counters[countersLen] = { 0, 0, 0, 0 };
|
||||
|
||||
|
||||
int end = row->getSize();
|
||||
int rowOffset = startRange[1];
|
||||
|
||||
int lgPatternFound = 0;
|
||||
|
||||
for (int x = 0; x < 6 && rowOffset < end; x++) {
|
||||
int bestMatch = decodeDigit(row, counters, countersLen, rowOffset, UPC_EAN_PATTERNS_L_AND_G_PATTERNS);
|
||||
resultString.append(1, (char) ('0' + bestMatch % 10));
|
||||
for (int i = 0; i < countersLen; i++) {
|
||||
rowOffset += counters[i];
|
||||
}
|
||||
if (bestMatch >= 10) {
|
||||
lgPatternFound |= 1 << (5 - x);
|
||||
}
|
||||
}
|
||||
|
||||
determineFirstDigit(resultString, lgPatternFound);
|
||||
|
||||
int* middleRange = findGuardPattern(row, rowOffset, true, (int*)getMIDDLE_PATTERN(), getMIDDLE_PATTERN_LEN());
|
||||
rowOffset = middleRange[1];
|
||||
|
||||
for (int x = 0; x < 6 && rowOffset < end; x++) {
|
||||
int bestMatch = decodeDigit(row, counters, countersLen, rowOffset, UPC_EAN_PATTERNS_L_PATTERNS);
|
||||
resultString.append(1, (char) ('0' + bestMatch));
|
||||
for (int i = 0; i < countersLen; i++) {
|
||||
rowOffset += counters[i];
|
||||
}
|
||||
}
|
||||
|
||||
return rowOffset;
|
||||
}
|
||||
|
||||
void EAN13Reader::determineFirstDigit(std::string& resultString, int lgPatternFound){
|
||||
for (int d = 0; d < 10; d++) {
|
||||
if (lgPatternFound == FIRST_DIGIT_ENCODINGS[d]) {
|
||||
resultString.insert(0, 1, (char) ('0' + d));
|
||||
return;
|
||||
}
|
||||
}
|
||||
throw ReaderException("determineFirstDigit");
|
||||
}
|
||||
|
||||
BarcodeFormat EAN13Reader::getBarcodeFormat(){
|
||||
return BarcodeFormat_EAN_13;
|
||||
}
|
||||
}
|
||||
namespace oned {
|
||||
|
||||
static const int FIRST_DIGIT_ENCODINGS[10] = {0x00, 0x0B, 0x0D, 0xE, 0x13, 0x19, 0x1C, 0x15, 0x16, 0x1A};
|
||||
|
||||
|
||||
EAN13Reader::EAN13Reader() { }
|
||||
|
||||
int EAN13Reader::decodeMiddle(Ref<BitArray> row, int startRange[], int startRangeLen, std::string& resultString){
|
||||
const int countersLen = 4;
|
||||
int counters[countersLen] = { 0, 0, 0, 0 };
|
||||
|
||||
|
||||
int end = row->getSize();
|
||||
int rowOffset = startRange[1];
|
||||
|
||||
int lgPatternFound = 0;
|
||||
|
||||
for (int x = 0; x < 6 && rowOffset < end; x++) {
|
||||
int bestMatch = decodeDigit(row, counters, countersLen, rowOffset, UPC_EAN_PATTERNS_L_AND_G_PATTERNS);
|
||||
resultString.append(1, (char) ('0' + bestMatch % 10));
|
||||
for (int i = 0; i < countersLen; i++) {
|
||||
rowOffset += counters[i];
|
||||
}
|
||||
if (bestMatch >= 10) {
|
||||
lgPatternFound |= 1 << (5 - x);
|
||||
}
|
||||
}
|
||||
|
||||
determineFirstDigit(resultString, lgPatternFound);
|
||||
|
||||
int* middleRange = 0;
|
||||
try {
|
||||
middleRange = findGuardPattern(row, rowOffset, true, (int*)getMIDDLE_PATTERN(), getMIDDLE_PATTERN_LEN());
|
||||
rowOffset = middleRange[1];
|
||||
|
||||
for (int x = 0; x < 6 && rowOffset < end; x++) {
|
||||
int bestMatch = decodeDigit(row, counters, countersLen, rowOffset, UPC_EAN_PATTERNS_L_PATTERNS);
|
||||
resultString.append(1, (char) ('0' + bestMatch));
|
||||
for (int i = 0; i < countersLen; i++) {
|
||||
rowOffset += counters[i];
|
||||
}
|
||||
}
|
||||
|
||||
delete [] middleRange;
|
||||
return rowOffset;
|
||||
} catch (ReaderException const& re) {
|
||||
delete [] middleRange;
|
||||
throw re;
|
||||
}
|
||||
}
|
||||
|
||||
void EAN13Reader::determineFirstDigit(std::string& resultString, int lgPatternFound){
|
||||
for (int d = 0; d < 10; d++) {
|
||||
if (lgPatternFound == FIRST_DIGIT_ENCODINGS[d]) {
|
||||
resultString.insert(0, 1, (char) ('0' + d));
|
||||
return;
|
||||
}
|
||||
}
|
||||
throw ReaderException("determineFirstDigit");
|
||||
}
|
||||
|
||||
BarcodeFormat EAN13Reader::getBarcodeFormat(){
|
||||
return BarcodeFormat_EAN_13;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,41 +22,48 @@
|
|||
#include <zxing/ReaderException.h>
|
||||
|
||||
namespace zxing {
|
||||
namespace oned {
|
||||
|
||||
EAN8Reader::EAN8Reader(){ }
|
||||
|
||||
int EAN8Reader::decodeMiddle(Ref<BitArray> row, int startRange[], int startRangeLen, std::string& resultString){
|
||||
const int countersLen = 4;
|
||||
int counters[countersLen] = { 0, 0, 0, 0 };
|
||||
|
||||
int end = row->getSize();
|
||||
int rowOffset = startRange[1];
|
||||
|
||||
for (int x = 0; x < 4 && rowOffset < end; x++) {
|
||||
int bestMatch = decodeDigit(row, counters, countersLen, rowOffset, UPC_EAN_PATTERNS_L_PATTERNS);
|
||||
resultString.append(1, (char) ('0' + bestMatch));
|
||||
for (int i = 0; i < countersLen; i++) {
|
||||
rowOffset += counters[i];
|
||||
}
|
||||
}
|
||||
|
||||
int* 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];
|
||||
}
|
||||
}
|
||||
|
||||
return rowOffset;
|
||||
}
|
||||
|
||||
BarcodeFormat EAN8Reader::getBarcodeFormat(){
|
||||
return BarcodeFormat_EAN_8;
|
||||
}
|
||||
}
|
||||
namespace oned {
|
||||
|
||||
EAN8Reader::EAN8Reader(){ }
|
||||
|
||||
int EAN8Reader::decodeMiddle(Ref<BitArray> row, int startRange[], int startRangeLen, std::string& resultString){
|
||||
const int countersLen = 4;
|
||||
int counters[countersLen] = { 0, 0, 0, 0 };
|
||||
|
||||
int end = row->getSize();
|
||||
int rowOffset = startRange[1];
|
||||
|
||||
for (int x = 0; x < 4 && rowOffset < end; x++) {
|
||||
int bestMatch = decodeDigit(row, counters, countersLen, rowOffset, UPC_EAN_PATTERNS_L_PATTERNS);
|
||||
resultString.append(1, (char) ('0' + bestMatch));
|
||||
for (int i = 0; i < countersLen; i++) {
|
||||
rowOffset += counters[i];
|
||||
}
|
||||
}
|
||||
|
||||
int* middleRange = 0;
|
||||
try {
|
||||
middleRange = findGuardPattern(row, rowOffset, true, (int*)getMIDDLE_PATTERN(), getMIDDLE_PATTERN_LEN());
|
||||
rowOffset = middleRange[1];
|
||||
|
||||
for (int x = 0; x < 4 && rowOffset < end; x++) {
|
||||
int bestMatch = decodeDigit(row, counters, countersLen, rowOffset, UPC_EAN_PATTERNS_L_PATTERNS);
|
||||
resultString.append(1, (char) ('0' + bestMatch));
|
||||
for (int i = 0; i < countersLen; i++) {
|
||||
rowOffset += counters[i];
|
||||
}
|
||||
}
|
||||
|
||||
delete [] middleRange;
|
||||
return rowOffset;
|
||||
} catch (ReaderException const& re) {
|
||||
delete [] middleRange;
|
||||
throw re;
|
||||
}
|
||||
}
|
||||
|
||||
BarcodeFormat EAN8Reader::getBarcodeFormat(){
|
||||
return BarcodeFormat_EAN_8;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,340 +25,341 @@
|
|||
#include <math.h>
|
||||
|
||||
namespace zxing {
|
||||
namespace oned {
|
||||
|
||||
static const int W = 3; // Pixel width of a wide line
|
||||
static const int N = 1; // Pixed width of a narrow line
|
||||
|
||||
const int DEFAULT_ALLOWED_LENGTHS[4] = { 6, 10, 14, 44 };
|
||||
|
||||
/**
|
||||
* Start/end guard pattern.
|
||||
*
|
||||
* Note: The end pattern is reversed because the row is reversed before
|
||||
* searching for the END_PATTERN
|
||||
*/
|
||||
static const int START_PATTERN_LEN = 4;
|
||||
static const int START_PATTERN[START_PATTERN_LEN] = {N, N, N, N};
|
||||
|
||||
static const int END_PATTERN_REVERSED_LEN = 3;
|
||||
static const int END_PATTERN_REVERSED[END_PATTERN_REVERSED_LEN] = {N, N, W};
|
||||
|
||||
/**
|
||||
* Patterns of Wide / Narrow lines to indicate each digit
|
||||
*/
|
||||
static const int PATTERNS_LEN = 10;
|
||||
static const int PATTERNS[PATTERNS_LEN][5] = {
|
||||
{N, N, W, W, N}, // 0
|
||||
{W, N, N, N, W}, // 1
|
||||
{N, W, N, N, W}, // 2
|
||||
{W, W, N, N, N}, // 3
|
||||
{N, N, W, N, W}, // 4
|
||||
{W, N, W, N, N}, // 5
|
||||
{N, W, W, N, N}, // 6
|
||||
{N, N, N, W, W}, // 7
|
||||
{W, N, N, W, N}, // 8
|
||||
{N, W, N, W, N} // 9
|
||||
};
|
||||
|
||||
|
||||
ITFReader::ITFReader() : narrowLineWidth(-1) {
|
||||
}
|
||||
|
||||
|
||||
Ref<Result> ITFReader::decodeRow(int rowNumber, Ref<BitArray> row){
|
||||
// Find out where the Middle section (payload) starts & ends
|
||||
int* startRange = decodeStart(row);
|
||||
int* endRange;
|
||||
try {
|
||||
endRange = decodeEnd(row);
|
||||
} catch (ReaderException re) {
|
||||
delete [] startRange;
|
||||
throw re;
|
||||
}
|
||||
|
||||
std::string tmpResult;
|
||||
try {
|
||||
decodeMiddle(row, startRange[1], endRange[0], tmpResult);
|
||||
} catch (zxing::ReaderException re) {
|
||||
delete [] startRange;
|
||||
delete [] endRange;
|
||||
throw re;
|
||||
}
|
||||
|
||||
// To avoid false positives with 2D barcodes (and other patterns), make
|
||||
// an assumption that the decoded string must be 6, 10 or 14 digits.
|
||||
int length = tmpResult.length();
|
||||
bool lengthOK = false;
|
||||
if (length == 6 || length == 10 || length == 14) {
|
||||
lengthOK = true;
|
||||
}
|
||||
if (!lengthOK) {
|
||||
delete [] startRange;
|
||||
delete [] endRange;
|
||||
throw ReaderException("not enough characters count");
|
||||
}
|
||||
|
||||
Ref<String> resultString(new String(tmpResult));
|
||||
|
||||
std::vector< Ref<ResultPoint> > resultPoints(2);
|
||||
Ref<OneDResultPoint> resultPoint1(new OneDResultPoint(startRange[1], (float) rowNumber));
|
||||
Ref<OneDResultPoint> resultPoint2(new OneDResultPoint(endRange[0], (float) rowNumber));
|
||||
resultPoints[0] = resultPoint1;
|
||||
resultPoints[1] = resultPoint2;
|
||||
|
||||
ArrayRef<unsigned char> resultBytes(1);
|
||||
|
||||
delete [] startRange;
|
||||
delete [] endRange;
|
||||
|
||||
Ref<Result> res(new Result(resultString, resultBytes, resultPoints, BarcodeFormat_ITF));
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param row row of black/white values to search
|
||||
* @param payloadStart offset of start pattern
|
||||
* @param resultString {@link StringBuffer} to append decoded chars to
|
||||
* @throws ReaderException if decoding could not complete successfully
|
||||
*/
|
||||
void ITFReader::decodeMiddle(Ref<BitArray> row, int payloadStart, int payloadEnd, std::string& resultString){
|
||||
// Digits are interleaved in pairs - 5 black lines for one digit, and the
|
||||
// 5
|
||||
// interleaved white lines for the second digit.
|
||||
// Therefore, need to scan 10 lines and then
|
||||
// split these into two arrays
|
||||
int counterDigitPairLen = 10;
|
||||
int counterDigitPair[counterDigitPairLen];
|
||||
for (int i=0; i<counterDigitPairLen; i++) {
|
||||
counterDigitPair[i] = 0;
|
||||
}
|
||||
|
||||
int counterBlack[5];
|
||||
int counterWhite[5];
|
||||
for (int i=0; i<5; i++) {
|
||||
counterBlack[i] = 0;
|
||||
counterWhite[i] = 0;
|
||||
}
|
||||
|
||||
while (payloadStart < payloadEnd) {
|
||||
// Get 10 runs of black/white.
|
||||
recordPattern(row, payloadStart, counterDigitPair, counterDigitPairLen);
|
||||
// Split them into each array
|
||||
for (int k = 0; k < 5; k++) {
|
||||
int twoK = k << 1;
|
||||
counterBlack[k] = counterDigitPair[twoK];
|
||||
counterWhite[k] = counterDigitPair[twoK + 1];
|
||||
}
|
||||
|
||||
int bestMatch = decodeDigit(counterBlack, 5);
|
||||
resultString.append(1, (char) ('0' + bestMatch));
|
||||
bestMatch = decodeDigit(counterWhite, 5);
|
||||
resultString.append(1, (char) ('0' + bestMatch));
|
||||
|
||||
for (int i = 0; i < counterDigitPairLen; i++) {
|
||||
payloadStart += counterDigitPair[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Identify where the start of the middle / payload section starts.
|
||||
*
|
||||
* @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
|
||||
*/
|
||||
int* ITFReader::decodeStart(Ref<BitArray> row){
|
||||
int endStart = skipWhiteSpace(row);
|
||||
/// static int* findGuardPattern(Ref<BitArray> row, int rowOffset, bool whiteFirst, const int pattern[], int patternLen);
|
||||
int* startPattern = findGuardPattern(row, endStart, START_PATTERN, START_PATTERN_LEN);
|
||||
|
||||
// Determine the width of a narrow line in pixels. We can do this by
|
||||
// getting the width of the start pattern and dividing by 4 because its
|
||||
// made up of 4 narrow lines.
|
||||
narrowLineWidth = (startPattern[1] - startPattern[0]) >> 2;
|
||||
|
||||
validateQuietZone(row, startPattern[0]);
|
||||
|
||||
return startPattern;
|
||||
}
|
||||
|
||||
/**
|
||||
* Identify where the end of the middle / payload section ends.
|
||||
*
|
||||
* @param row row of black/white values to search
|
||||
* @return Array, containing index of start of 'end block' and end of 'end
|
||||
* block'
|
||||
* @throws ReaderException
|
||||
*/
|
||||
|
||||
int* ITFReader::decodeEnd(Ref<BitArray> row){
|
||||
// For convenience, reverse the row and then
|
||||
// search from 'the start' for the end block
|
||||
row->reverse();
|
||||
try {
|
||||
int endStart = skipWhiteSpace(row);
|
||||
int* endPattern = findGuardPattern(row, endStart, END_PATTERN_REVERSED, END_PATTERN_REVERSED_LEN);
|
||||
|
||||
// The start & end patterns must be pre/post fixed by a quiet zone. This
|
||||
// zone must be at least 10 times the width of a narrow line.
|
||||
// ref: http://www.barcode-1.net/i25code.html
|
||||
validateQuietZone(row, endPattern[0]);
|
||||
|
||||
// Now recalculate the indices of where the 'endblock' starts & stops to
|
||||
// accommodate
|
||||
// the reversed nature of the search
|
||||
int temp = endPattern[0];
|
||||
endPattern[0] = row->getSize() - endPattern[1];
|
||||
endPattern[1] = row->getSize() - temp;
|
||||
|
||||
row->reverse();
|
||||
return endPattern;
|
||||
} catch (ReaderException re) {
|
||||
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
|
||||
* 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.
|
||||
*
|
||||
* 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.
|
||||
* @throws ReaderException if the quiet zone cannot be found, a ReaderException is thrown.
|
||||
*/
|
||||
void ITFReader::validateQuietZone(Ref<BitArray> row, int startPattern){
|
||||
namespace oned {
|
||||
|
||||
static const int W = 3; // Pixel width of a wide line
|
||||
static const int N = 1; // Pixed width of a narrow line
|
||||
|
||||
const int DEFAULT_ALLOWED_LENGTHS[4] = { 6, 10, 14, 44 };
|
||||
|
||||
/**
|
||||
* Start/end guard pattern.
|
||||
*
|
||||
* Note: The end pattern is reversed because the row is reversed before
|
||||
* searching for the END_PATTERN
|
||||
*/
|
||||
static const int START_PATTERN_LEN = 4;
|
||||
static const int START_PATTERN[START_PATTERN_LEN] = {N, N, N, N};
|
||||
|
||||
static const int END_PATTERN_REVERSED_LEN = 3;
|
||||
static const int END_PATTERN_REVERSED[END_PATTERN_REVERSED_LEN] = {N, N, W};
|
||||
|
||||
/**
|
||||
* Patterns of Wide / Narrow lines to indicate each digit
|
||||
*/
|
||||
static const int PATTERNS_LEN = 10;
|
||||
static const int PATTERNS[PATTERNS_LEN][5] = {
|
||||
{N, N, W, W, N}, // 0
|
||||
{W, N, N, N, W}, // 1
|
||||
{N, W, N, N, W}, // 2
|
||||
{W, W, N, N, N}, // 3
|
||||
{N, N, W, N, W}, // 4
|
||||
{W, N, W, N, N}, // 5
|
||||
{N, W, W, N, N}, // 6
|
||||
{N, N, N, W, W}, // 7
|
||||
{W, N, N, W, N}, // 8
|
||||
{N, W, N, W, N} // 9
|
||||
};
|
||||
|
||||
|
||||
ITFReader::ITFReader() : narrowLineWidth(-1) {
|
||||
}
|
||||
|
||||
|
||||
Ref<Result> ITFReader::decodeRow(int rowNumber, Ref<BitArray> row){
|
||||
int* startRange = 0;
|
||||
int* endRange = 0;
|
||||
try {
|
||||
// Find out where the Middle section (payload) starts & ends
|
||||
startRange = decodeStart(row);
|
||||
endRange = decodeEnd(row);
|
||||
|
||||
std::string tmpResult;
|
||||
decodeMiddle(row, startRange[1], endRange[0], tmpResult);
|
||||
|
||||
// To avoid false positives with 2D barcodes (and other patterns), make
|
||||
// an assumption that the decoded string must be 6, 10 or 14 digits.
|
||||
int length = tmpResult.length();
|
||||
bool lengthOK = false;
|
||||
if (length == 6 || length == 10 || length == 14) {
|
||||
lengthOK = true;
|
||||
}
|
||||
if (!lengthOK) {
|
||||
throw ReaderException("not enough characters count");
|
||||
}
|
||||
|
||||
Ref<String> resultString(new String(tmpResult));
|
||||
|
||||
std::vector< Ref<ResultPoint> > resultPoints(2);
|
||||
Ref<OneDResultPoint> resultPoint1(new OneDResultPoint(startRange[1], (float) rowNumber));
|
||||
Ref<OneDResultPoint> resultPoint2(new OneDResultPoint(endRange[0], (float) rowNumber));
|
||||
resultPoints[0] = resultPoint1;
|
||||
resultPoints[1] = resultPoint2;
|
||||
|
||||
ArrayRef<unsigned char> resultBytes(1);
|
||||
|
||||
Ref<Result> res(new Result(resultString, resultBytes, resultPoints, BarcodeFormat_ITF));
|
||||
delete [] startRange;
|
||||
delete [] endRange;
|
||||
return res;
|
||||
} catch (ReaderException re) {
|
||||
delete [] startRange;
|
||||
delete [] endRange;
|
||||
throw re;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param row row of black/white values to search
|
||||
* @param payloadStart offset of start pattern
|
||||
* @param resultString {@link StringBuffer} to append decoded chars to
|
||||
* @throws ReaderException if decoding could not complete successfully
|
||||
*/
|
||||
void ITFReader::decodeMiddle(Ref<BitArray> row, int payloadStart, int payloadEnd, std::string& resultString){
|
||||
// Digits are interleaved in pairs - 5 black lines for one digit, and the
|
||||
// 5
|
||||
// interleaved white lines for the second digit.
|
||||
// Therefore, need to scan 10 lines and then
|
||||
// split these into two arrays
|
||||
int counterDigitPairLen = 10;
|
||||
int counterDigitPair[counterDigitPairLen];
|
||||
for (int i=0; i<counterDigitPairLen; i++) {
|
||||
counterDigitPair[i] = 0;
|
||||
}
|
||||
|
||||
int counterBlack[5];
|
||||
int counterWhite[5];
|
||||
for (int i=0; i<5; i++) {
|
||||
counterBlack[i] = 0;
|
||||
counterWhite[i] = 0;
|
||||
}
|
||||
|
||||
while (payloadStart < payloadEnd) {
|
||||
// Get 10 runs of black/white.
|
||||
recordPattern(row, payloadStart, counterDigitPair, counterDigitPairLen);
|
||||
// Split them into each array
|
||||
for (int k = 0; k < 5; k++) {
|
||||
int twoK = k << 1;
|
||||
counterBlack[k] = counterDigitPair[twoK];
|
||||
counterWhite[k] = counterDigitPair[twoK + 1];
|
||||
}
|
||||
|
||||
int bestMatch = decodeDigit(counterBlack, 5);
|
||||
resultString.append(1, (char) ('0' + bestMatch));
|
||||
bestMatch = decodeDigit(counterWhite, 5);
|
||||
resultString.append(1, (char) ('0' + bestMatch));
|
||||
|
||||
for (int i = 0; i < counterDigitPairLen; i++) {
|
||||
payloadStart += counterDigitPair[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Identify where the start of the middle / payload section starts.
|
||||
*
|
||||
* @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
|
||||
*/
|
||||
int* ITFReader::decodeStart(Ref<BitArray> row){
|
||||
int endStart = skipWhiteSpace(row);
|
||||
/// static int* findGuardPattern(Ref<BitArray> row, int rowOffset, bool whiteFirst, const int pattern[], int patternLen);
|
||||
int* startPattern = 0;
|
||||
try {
|
||||
startPattern = findGuardPattern(row, endStart, START_PATTERN, START_PATTERN_LEN);
|
||||
|
||||
// Determine the width of a narrow line in pixels. We can do this by
|
||||
// getting the width of the start pattern and dividing by 4 because its
|
||||
// made up of 4 narrow lines.
|
||||
narrowLineWidth = (startPattern[1] - startPattern[0]) >> 2;
|
||||
|
||||
validateQuietZone(row, startPattern[0]);
|
||||
|
||||
return startPattern;
|
||||
} catch (ReaderException re) {
|
||||
delete [] startPattern;
|
||||
throw re;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Identify where the end of the middle / payload section ends.
|
||||
*
|
||||
* @param row row of black/white values to search
|
||||
* @return Array, containing index of start of 'end block' and end of 'end
|
||||
* block'
|
||||
* @throws ReaderException
|
||||
*/
|
||||
|
||||
int* ITFReader::decodeEnd(Ref<BitArray> row){
|
||||
// For convenience, reverse the row and then
|
||||
// search from 'the start' for the end block
|
||||
row->reverse();
|
||||
int* endPattern = 0;
|
||||
try {
|
||||
int endStart = skipWhiteSpace(row);
|
||||
endPattern = findGuardPattern(row, endStart, END_PATTERN_REVERSED, END_PATTERN_REVERSED_LEN);
|
||||
|
||||
// The start & end patterns must be pre/post fixed by a quiet zone. This
|
||||
// zone must be at least 10 times the width of a narrow line.
|
||||
// ref: http://www.barcode-1.net/i25code.html
|
||||
validateQuietZone(row, endPattern[0]);
|
||||
|
||||
// Now recalculate the indices of where the 'endblock' starts & stops to
|
||||
// accommodate
|
||||
// the reversed nature of the search
|
||||
int temp = endPattern[0];
|
||||
endPattern[0] = row->getSize() - endPattern[1];
|
||||
endPattern[1] = row->getSize() - temp;
|
||||
|
||||
row->reverse();
|
||||
return endPattern;
|
||||
} catch (ReaderException re) {
|
||||
delete [] endPattern;
|
||||
row->reverse();
|
||||
throw re;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The start & end patterns must be pre/post fixed by a quiet zone. This
|
||||
* zone must be at least 10 times the width of a narrow line. Scan back until
|
||||
* 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.
|
||||
*
|
||||
* 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.
|
||||
* @throws ReaderException if the quiet zone cannot be found, a ReaderException is thrown.
|
||||
*/
|
||||
void ITFReader::validateQuietZone(Ref<BitArray> row, int startPattern){
|
||||
//#pragma mark needs some corrections
|
||||
// int quietCount = narrowLineWidth * 10; // expect to find this many pixels of quiet zone
|
||||
//
|
||||
// for (int i = startPattern - 1; quietCount > 0 && i >= 0; i--) {
|
||||
// if (row->get(i)) {
|
||||
// break;
|
||||
// }
|
||||
// quietCount--;
|
||||
// }
|
||||
// if (quietCount != 0) {
|
||||
// // 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.
|
||||
*
|
||||
* @param row row of black/white values to search
|
||||
* @return index of the first black line.
|
||||
* @throws ReaderException Throws exception if no black lines are found in the row
|
||||
*/
|
||||
int ITFReader::skipWhiteSpace(Ref<BitArray> row){
|
||||
int width = row->getSize();
|
||||
int endStart = 0;
|
||||
while (endStart < width) {
|
||||
if (row->get(endStart)) {
|
||||
break;
|
||||
}
|
||||
endStart++;
|
||||
}
|
||||
if (endStart == width) {
|
||||
throw ReaderException("");
|
||||
}
|
||||
return endStart;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param row row of black/white values to search
|
||||
* @param rowOffset position to start search
|
||||
* @param pattern pattern of counts of number of black and white pixels that are
|
||||
* being searched for as a pattern
|
||||
* @return start/end horizontal offset of guard pattern, as an array of two
|
||||
* ints
|
||||
* @throws ReaderException if pattern is not found
|
||||
*/
|
||||
|
||||
int* ITFReader::findGuardPattern(Ref<BitArray> row, int rowOffset, const int pattern[], int patternLen){
|
||||
// TODO: This is very similar to implementation in UPCEANReader. Consider if they can be
|
||||
// merged to a single method.
|
||||
int patternLength = patternLen;
|
||||
int counters[patternLength];
|
||||
for (int i=0; i<patternLength; i++) {
|
||||
counters[i] = 0;
|
||||
}
|
||||
int width = row->getSize();
|
||||
bool isWhite = false;
|
||||
|
||||
int counterPosition = 0;
|
||||
int patternStart = rowOffset;
|
||||
for (int x = rowOffset; x < width; x++) {
|
||||
bool pixel = row->get(x);
|
||||
if (pixel ^ isWhite) {
|
||||
counters[counterPosition]++;
|
||||
} else {
|
||||
if (counterPosition == patternLength - 1) {
|
||||
if (patternMatchVariance(counters, patternLength, pattern, MAX_INDIVIDUAL_VARIANCE) < MAX_AVG_VARIANCE) {
|
||||
int* resultValue = new int[2];
|
||||
resultValue[0] = patternStart;
|
||||
resultValue[1] = x;
|
||||
return resultValue;
|
||||
}
|
||||
patternStart += counters[0] + counters[1];
|
||||
for (int y = 2; y < patternLength; y++) {
|
||||
counters[y - 2] = counters[y];
|
||||
}
|
||||
counters[patternLength - 2] = 0;
|
||||
counters[patternLength - 1] = 0;
|
||||
counterPosition--;
|
||||
} else {
|
||||
counterPosition++;
|
||||
}
|
||||
counters[counterPosition] = 1;
|
||||
isWhite = !isWhite;
|
||||
}
|
||||
}
|
||||
throw ReaderException("");
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to decode a sequence of ITF black/white lines into single
|
||||
* digit.
|
||||
*
|
||||
* @param counters the counts of runs of observed black/white/black/... values
|
||||
* @return The decoded digit
|
||||
* @throws ReaderException if digit cannot be decoded
|
||||
*/
|
||||
int ITFReader::decodeDigit(int counters[], int countersLen){
|
||||
unsigned int bestVariance = MAX_AVG_VARIANCE; // worst variance we'll accept
|
||||
int bestMatch = -1;
|
||||
int max = PATTERNS_LEN;
|
||||
for (int i = 0; i < max; i++) {
|
||||
int pattern[countersLen];
|
||||
for(int ind = 0; ind<countersLen; ind++){
|
||||
pattern[ind] = PATTERNS[i][ind];
|
||||
}
|
||||
unsigned int variance = patternMatchVariance(counters, countersLen, pattern, MAX_INDIVIDUAL_VARIANCE);
|
||||
if (variance < bestVariance) {
|
||||
bestVariance = variance;
|
||||
bestMatch = i;
|
||||
}
|
||||
}
|
||||
if (bestMatch >= 0) {
|
||||
return bestMatch;
|
||||
} else {
|
||||
throw ReaderException("digit didint found");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ITFReader::~ITFReader(){
|
||||
}
|
||||
}
|
||||
// int quietCount = narrowLineWidth * 10; // expect to find this many pixels of quiet zone
|
||||
//
|
||||
// for (int i = startPattern - 1; quietCount > 0 && i >= 0; i--) {
|
||||
// if (row->get(i)) {
|
||||
// break;
|
||||
// }
|
||||
// quietCount--;
|
||||
// }
|
||||
// if (quietCount != 0) {
|
||||
// // 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.
|
||||
*
|
||||
* @param row row of black/white values to search
|
||||
* @return index of the first black line.
|
||||
* @throws ReaderException Throws exception if no black lines are found in the row
|
||||
*/
|
||||
int ITFReader::skipWhiteSpace(Ref<BitArray> row){
|
||||
int width = row->getSize();
|
||||
int endStart = 0;
|
||||
while (endStart < width) {
|
||||
if (row->get(endStart)) {
|
||||
break;
|
||||
}
|
||||
endStart++;
|
||||
}
|
||||
if (endStart == width) {
|
||||
throw ReaderException("");
|
||||
}
|
||||
return endStart;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param row row of black/white values to search
|
||||
* @param rowOffset position to start search
|
||||
* @param pattern pattern of counts of number of black and white pixels that are
|
||||
* being searched for as a pattern
|
||||
* @return start/end horizontal offset of guard pattern, as an array of two
|
||||
* ints
|
||||
* @throws ReaderException if pattern is not found
|
||||
*/
|
||||
|
||||
int* ITFReader::findGuardPattern(Ref<BitArray> row, int rowOffset, const int pattern[], int patternLen){
|
||||
// TODO: This is very similar to implementation in UPCEANReader. Consider if they can be
|
||||
// merged to a single method.
|
||||
int patternLength = patternLen;
|
||||
int counters[patternLength];
|
||||
for (int i=0; i<patternLength; i++) {
|
||||
counters[i] = 0;
|
||||
}
|
||||
int width = row->getSize();
|
||||
bool isWhite = false;
|
||||
|
||||
int counterPosition = 0;
|
||||
int patternStart = rowOffset;
|
||||
for (int x = rowOffset; x < width; x++) {
|
||||
bool pixel = row->get(x);
|
||||
if (pixel ^ isWhite) {
|
||||
counters[counterPosition]++;
|
||||
} else {
|
||||
if (counterPosition == patternLength - 1) {
|
||||
if (patternMatchVariance(counters, patternLength, pattern, MAX_INDIVIDUAL_VARIANCE) < MAX_AVG_VARIANCE) {
|
||||
int* resultValue = new int[2];
|
||||
resultValue[0] = patternStart;
|
||||
resultValue[1] = x;
|
||||
return resultValue;
|
||||
}
|
||||
patternStart += counters[0] + counters[1];
|
||||
for (int y = 2; y < patternLength; y++) {
|
||||
counters[y - 2] = counters[y];
|
||||
}
|
||||
counters[patternLength - 2] = 0;
|
||||
counters[patternLength - 1] = 0;
|
||||
counterPosition--;
|
||||
} else {
|
||||
counterPosition++;
|
||||
}
|
||||
counters[counterPosition] = 1;
|
||||
isWhite = !isWhite;
|
||||
}
|
||||
}
|
||||
throw ReaderException("");
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to decode a sequence of ITF black/white lines into single
|
||||
* digit.
|
||||
*
|
||||
* @param counters the counts of runs of observed black/white/black/... values
|
||||
* @return The decoded digit
|
||||
* @throws ReaderException if digit cannot be decoded
|
||||
*/
|
||||
int ITFReader::decodeDigit(int counters[], int countersLen){
|
||||
unsigned int bestVariance = MAX_AVG_VARIANCE; // worst variance we'll accept
|
||||
int bestMatch = -1;
|
||||
int max = PATTERNS_LEN;
|
||||
for (int i = 0; i < max; i++) {
|
||||
int pattern[countersLen];
|
||||
for(int ind = 0; ind<countersLen; ind++){
|
||||
pattern[ind] = PATTERNS[i][ind];
|
||||
}
|
||||
unsigned int variance = patternMatchVariance(counters, countersLen, pattern, MAX_INDIVIDUAL_VARIANCE);
|
||||
if (variance < bestVariance) {
|
||||
bestVariance = variance;
|
||||
bestMatch = i;
|
||||
}
|
||||
}
|
||||
if (bestMatch >= 0) {
|
||||
return bestMatch;
|
||||
} else {
|
||||
throw ReaderException("digit didint found");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ITFReader::~ITFReader(){
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,308 +22,304 @@
|
|||
#include <zxing/oned/OneDResultPoint.h>
|
||||
#include <zxing/ReaderException.h>
|
||||
namespace zxing {
|
||||
namespace oned {
|
||||
|
||||
/**
|
||||
* Start/end guard pattern.
|
||||
*/
|
||||
static const int START_END_PATTERN[3] = {1, 1, 1};
|
||||
|
||||
/**
|
||||
* Pattern marking the middle of a UPC/EAN pattern, separating the two halves.
|
||||
*/
|
||||
static const int MIDDLE_PATTERN_LEN = 5;
|
||||
static const int MIDDLE_PATTERN[MIDDLE_PATTERN_LEN] = {1, 1, 1, 1, 1};
|
||||
|
||||
/**
|
||||
* "Odd", or "L" patterns used to encode UPC/EAN digits.
|
||||
*/
|
||||
const int L_PATTERNS_LEN = 10;
|
||||
const int L_PATTERNS_SUB_LEN = 4;
|
||||
const int L_PATTERNS[10][4] = {
|
||||
{3, 2, 1, 1}, // 0
|
||||
{2, 2, 2, 1}, // 1
|
||||
{2, 1, 2, 2}, // 2
|
||||
{1, 4, 1, 1}, // 3
|
||||
{1, 1, 3, 2}, // 4
|
||||
{1, 2, 3, 1}, // 5
|
||||
{1, 1, 1, 4}, // 6
|
||||
{1, 3, 1, 2}, // 7
|
||||
{1, 2, 1, 3}, // 8
|
||||
{3, 1, 1, 2} // 9
|
||||
};
|
||||
|
||||
/**
|
||||
* As above but also including the "even", or "G" patterns used to encode UPC/EAN digits.
|
||||
*/
|
||||
const int L_AND_G_PATTERNS_LEN = 20;
|
||||
const int L_AND_G_PATTERNS_SUB_LEN = 4;
|
||||
const int L_AND_G_PATTERNS[L_AND_G_PATTERNS_LEN][L_AND_G_PATTERNS_SUB_LEN] = {
|
||||
{3, 2, 1, 1}, // 0
|
||||
{2, 2, 2, 1}, // 1
|
||||
{2, 1, 2, 2}, // 2
|
||||
{1, 4, 1, 1}, // 3
|
||||
{1, 1, 3, 2}, // 4
|
||||
{1, 2, 3, 1}, // 5
|
||||
{1, 1, 1, 4}, // 6
|
||||
{1, 3, 1, 2}, // 7
|
||||
{1, 2, 1, 3}, // 8
|
||||
{3, 1, 1, 2}, // 9
|
||||
{1, 1, 2, 3}, // 10 reversed 0
|
||||
{1, 2, 2, 2}, // 11 reversed 1
|
||||
{2, 2, 1, 2}, // 12 reversed 2
|
||||
{1, 1, 4, 1}, // 13 reversed 3
|
||||
{2, 3, 1, 1}, // 14 reversed 4
|
||||
{1, 3, 2, 1}, // 15 reversed 5
|
||||
{4, 1, 1, 1}, // 16 reversed 6
|
||||
{2, 1, 3, 1}, // 17 reversed 7
|
||||
{3, 1, 2, 1}, // 18 reversed 8
|
||||
{2, 1, 1, 3} // 19 reversed 9
|
||||
};
|
||||
|
||||
namespace oned {
|
||||
|
||||
/**
|
||||
* Start/end guard pattern.
|
||||
*/
|
||||
static const int START_END_PATTERN[3] = {1, 1, 1};
|
||||
|
||||
/**
|
||||
* Pattern marking the middle of a UPC/EAN pattern, separating the two halves.
|
||||
*/
|
||||
static const int MIDDLE_PATTERN_LEN = 5;
|
||||
static const int MIDDLE_PATTERN[MIDDLE_PATTERN_LEN] = {1, 1, 1, 1, 1};
|
||||
|
||||
/**
|
||||
* "Odd", or "L" patterns used to encode UPC/EAN digits.
|
||||
*/
|
||||
const int L_PATTERNS_LEN = 10;
|
||||
const int L_PATTERNS_SUB_LEN = 4;
|
||||
const int L_PATTERNS[10][4] = {
|
||||
{3, 2, 1, 1}, // 0
|
||||
{2, 2, 2, 1}, // 1
|
||||
{2, 1, 2, 2}, // 2
|
||||
{1, 4, 1, 1}, // 3
|
||||
{1, 1, 3, 2}, // 4
|
||||
{1, 2, 3, 1}, // 5
|
||||
{1, 1, 1, 4}, // 6
|
||||
{1, 3, 1, 2}, // 7
|
||||
{1, 2, 1, 3}, // 8
|
||||
{3, 1, 1, 2} // 9
|
||||
};
|
||||
|
||||
/**
|
||||
* As above but also including the "even", or "G" patterns used to encode UPC/EAN digits.
|
||||
*/
|
||||
const int L_AND_G_PATTERNS_LEN = 20;
|
||||
const int L_AND_G_PATTERNS_SUB_LEN = 4;
|
||||
const int L_AND_G_PATTERNS[L_AND_G_PATTERNS_LEN][L_AND_G_PATTERNS_SUB_LEN] = {
|
||||
{3, 2, 1, 1}, // 0
|
||||
{2, 2, 2, 1}, // 1
|
||||
{2, 1, 2, 2}, // 2
|
||||
{1, 4, 1, 1}, // 3
|
||||
{1, 1, 3, 2}, // 4
|
||||
{1, 2, 3, 1}, // 5
|
||||
{1, 1, 1, 4}, // 6
|
||||
{1, 3, 1, 2}, // 7
|
||||
{1, 2, 1, 3}, // 8
|
||||
{3, 1, 1, 2}, // 9
|
||||
{1, 1, 2, 3}, // 10 reversed 0
|
||||
{1, 2, 2, 2}, // 11 reversed 1
|
||||
{2, 2, 1, 2}, // 12 reversed 2
|
||||
{1, 1, 4, 1}, // 13 reversed 3
|
||||
{2, 3, 1, 1}, // 14 reversed 4
|
||||
{1, 3, 2, 1}, // 15 reversed 5
|
||||
{4, 1, 1, 1}, // 16 reversed 6
|
||||
{2, 1, 3, 1}, // 17 reversed 7
|
||||
{3, 1, 2, 1}, // 18 reversed 8
|
||||
{2, 1, 1, 3} // 19 reversed 9
|
||||
};
|
||||
|
||||
|
||||
const int UPCEANReader::getMIDDLE_PATTERN_LEN(){
|
||||
return MIDDLE_PATTERN_LEN;
|
||||
}
|
||||
const int* UPCEANReader::getMIDDLE_PATTERN(){
|
||||
return MIDDLE_PATTERN;
|
||||
}
|
||||
|
||||
UPCEANReader::UPCEANReader(){
|
||||
}
|
||||
|
||||
|
||||
Ref<Result> UPCEANReader::decodeRow(int rowNumber, Ref<BitArray> row){
|
||||
return decodeRow(rowNumber, row, findStartGuardPattern(row));
|
||||
}
|
||||
Ref<Result> UPCEANReader::decodeRow(int rowNumber, Ref<BitArray> row, int startGuardRange[]){
|
||||
|
||||
std::string tmpResultString;
|
||||
std::string& tmpResultStringRef = tmpResultString;
|
||||
int endStart;
|
||||
const int UPCEANReader::getMIDDLE_PATTERN_LEN(){
|
||||
return MIDDLE_PATTERN_LEN;
|
||||
}
|
||||
const int* UPCEANReader::getMIDDLE_PATTERN(){
|
||||
return MIDDLE_PATTERN;
|
||||
}
|
||||
|
||||
UPCEANReader::UPCEANReader(){
|
||||
}
|
||||
|
||||
|
||||
Ref<Result> UPCEANReader::decodeRow(int rowNumber, Ref<BitArray> row) {
|
||||
int* start = NULL;
|
||||
try {
|
||||
endStart = decodeMiddle(row, startGuardRange, 2 /*reference findGuardPattern*/ , tmpResultStringRef);
|
||||
} catch (ReaderException re) {
|
||||
if (startGuardRange!=NULL) {
|
||||
delete [] startGuardRange;
|
||||
startGuardRange = NULL;
|
||||
}
|
||||
start = findStartGuardPattern(row);
|
||||
Ref<Result> result = decodeRow(rowNumber, row, start);
|
||||
delete [] start;
|
||||
return result;
|
||||
} catch (ReaderException const& re) {
|
||||
delete [] start;
|
||||
throw re;
|
||||
}
|
||||
|
||||
int* endRange = decodeEnd(row, endStart);
|
||||
|
||||
// Make sure there is a quiet zone at least as big as the end pattern after the barcode. The
|
||||
// spec might want more whitespace, but in practice this is the maximum we can count on.
|
||||
size_t end = endRange[1];
|
||||
size_t quietEnd = end + (end - endRange[0]);
|
||||
if (quietEnd >= row->getSize() || !row->isRange(end, quietEnd, false)) {
|
||||
throw ReaderException("Quiet zone asserrt fail.");
|
||||
}
|
||||
|
||||
Ref<Result> UPCEANReader::decodeRow(int rowNumber, Ref<BitArray> row, int startGuardRange[]){
|
||||
int* endRange = NULL;
|
||||
try {
|
||||
std::string tmpResultString;
|
||||
std::string& tmpResultStringRef = tmpResultString;
|
||||
int endStart;
|
||||
endStart = decodeMiddle(row, startGuardRange, 2 /*reference findGuardPattern*/ , tmpResultStringRef);
|
||||
|
||||
endRange = decodeEnd(row, endStart);
|
||||
|
||||
// Make sure there is a quiet zone at least as big as the end pattern after the barcode. The
|
||||
// spec might want more whitespace, but in practice this is the maximum we can count on.
|
||||
size_t end = endRange[1];
|
||||
size_t quietEnd = end + (end - endRange[0]);
|
||||
if (quietEnd >= row->getSize() || !row->isRange(end, quietEnd, false)) {
|
||||
throw ReaderException("Quiet zone asserrt fail.");
|
||||
}
|
||||
|
||||
if (!checkChecksum(tmpResultString)) {
|
||||
throw ReaderException("Checksum fail.");
|
||||
}
|
||||
|
||||
Ref<String> resultString(new String(tmpResultString));
|
||||
|
||||
float left = (float) (startGuardRange[1] + startGuardRange[0]) / 2.0f;
|
||||
float right = (float) (endRange[1] + endRange[0]) / 2.0f;
|
||||
|
||||
std::vector< Ref<ResultPoint> > resultPoints(2);
|
||||
Ref<OneDResultPoint> resultPoint1(new OneDResultPoint(left, (float) rowNumber));
|
||||
Ref<OneDResultPoint> resultPoint2(new OneDResultPoint(right, (float) rowNumber));
|
||||
resultPoints[0] = resultPoint1;
|
||||
resultPoints[1] = resultPoint2;
|
||||
|
||||
ArrayRef<unsigned char> resultBytes(1);
|
||||
|
||||
Ref<Result> res(new Result(resultString, resultBytes, resultPoints, getBarcodeFormat()));
|
||||
delete [] endRange;
|
||||
return res;
|
||||
} catch (ReaderException const& re) {
|
||||
delete [] endRange;
|
||||
throw re;
|
||||
}
|
||||
|
||||
if (!checkChecksum(tmpResultString)) {
|
||||
if (startGuardRange!=NULL) {
|
||||
delete [] startGuardRange;
|
||||
startGuardRange = NULL;
|
||||
}
|
||||
if (endRange!=NULL) {
|
||||
delete [] endRange;
|
||||
endRange = NULL;
|
||||
}
|
||||
throw ReaderException("Checksum fail.");
|
||||
}
|
||||
|
||||
Ref<String> resultString(new String(tmpResultString));
|
||||
|
||||
float left = (float) (startGuardRange[1] + startGuardRange[0]) / 2.0f;
|
||||
float right = (float) (endRange[1] + endRange[0]) / 2.0f;
|
||||
|
||||
std::vector< Ref<ResultPoint> > resultPoints(2);
|
||||
Ref<OneDResultPoint> resultPoint1(new OneDResultPoint(left, (float) rowNumber));
|
||||
Ref<OneDResultPoint> resultPoint2(new OneDResultPoint(right, (float) rowNumber));
|
||||
resultPoints[0] = resultPoint1;
|
||||
resultPoints[1] = resultPoint2;
|
||||
|
||||
ArrayRef<unsigned char> resultBytes(1);
|
||||
|
||||
if (startGuardRange!=NULL) {
|
||||
delete [] startGuardRange;
|
||||
startGuardRange = NULL;
|
||||
}
|
||||
if (endRange!=NULL) {
|
||||
delete [] endRange;
|
||||
endRange = NULL;
|
||||
}
|
||||
|
||||
Ref<Result> res(new Result(resultString, resultBytes, resultPoints, getBarcodeFormat()));
|
||||
return res;
|
||||
}
|
||||
|
||||
int* UPCEANReader::findStartGuardPattern(Ref<BitArray> row){
|
||||
bool foundStart = false;
|
||||
|
||||
int* startRange = NULL;
|
||||
int nextStart = 0;
|
||||
while (!foundStart) {
|
||||
startRange = findGuardPattern(row, nextStart, false, START_END_PATTERN, sizeof(START_END_PATTERN)/sizeof(int));
|
||||
int start = startRange[0];
|
||||
nextStart = startRange[1];
|
||||
// Make sure there is a quiet zone at least as big as the start pattern before the barcode.
|
||||
// If this check would run off the left edge of the image, do not accept this barcode,
|
||||
// as it is very likely to be a false positive.
|
||||
int quietStart = start - (nextStart - start);
|
||||
if (quietStart >= 0) {
|
||||
foundStart = row->isRange(quietStart, start, false);
|
||||
}
|
||||
if (!foundStart) {
|
||||
delete [] startRange;
|
||||
}
|
||||
}
|
||||
return startRange;
|
||||
}
|
||||
|
||||
int* UPCEANReader::findGuardPattern(Ref<BitArray> row, int rowOffset, bool whiteFirst, const int pattern[], int patternLen){
|
||||
int patternLength = patternLen;
|
||||
|
||||
int counters[patternLength];
|
||||
int countersCount = sizeof(counters)/sizeof(int);
|
||||
for (int i=0; i<countersCount ; i++) {
|
||||
counters[i]=0;
|
||||
}
|
||||
int width = row->getSize();
|
||||
bool isWhite = false;
|
||||
while (rowOffset < width) {
|
||||
isWhite = !row->get(rowOffset);
|
||||
if (whiteFirst == isWhite) {
|
||||
break;
|
||||
}
|
||||
rowOffset++;
|
||||
}
|
||||
|
||||
int counterPosition = 0;
|
||||
int patternStart = rowOffset;
|
||||
for (int x = rowOffset; x < width; x++) {
|
||||
bool pixel = row->get(x);
|
||||
if (pixel ^ isWhite) {
|
||||
counters[counterPosition]++;
|
||||
} else {
|
||||
if (counterPosition == patternLength - 1) {
|
||||
if (patternMatchVariance(counters, countersCount, pattern, MAX_INDIVIDUAL_VARIANCE) < MAX_AVG_VARIANCE) {
|
||||
int* resultValue = new int[2];
|
||||
resultValue[0] = patternStart;
|
||||
resultValue[1] = x;
|
||||
return resultValue;
|
||||
}
|
||||
patternStart += counters[0] + counters[1];
|
||||
for (int y = 2; y < patternLength; y++) {
|
||||
counters[y - 2] = counters[y];
|
||||
}
|
||||
counters[patternLength - 2] = 0;
|
||||
counters[patternLength - 1] = 0;
|
||||
counterPosition--;
|
||||
} else {
|
||||
counterPosition++;
|
||||
}
|
||||
counters[counterPosition] = 1;
|
||||
isWhite = !isWhite;
|
||||
}
|
||||
}
|
||||
throw ReaderException("findGuardPattern");
|
||||
}
|
||||
|
||||
int* UPCEANReader::decodeEnd(Ref<BitArray> row, int endStart){
|
||||
return findGuardPattern(row, endStart, false, START_END_PATTERN, sizeof(START_END_PATTERN)/sizeof(int));
|
||||
}
|
||||
|
||||
// int UPCEANReader::decodeDigit(Ref<BitArray> row, int counters[], int countersLen, int rowOffset, int** patterns/*[][]*/, int paterns1Len, int paterns2Len)
|
||||
int UPCEANReader::decodeDigit(Ref<BitArray> row, int counters[], int countersLen, int rowOffset, UPC_EAN_PATTERNS patternType){
|
||||
recordPattern(row, rowOffset, counters, countersLen);
|
||||
unsigned int bestVariance = MAX_AVG_VARIANCE; // worst variance we'll accept
|
||||
int bestMatch = -1;
|
||||
|
||||
int max = 0;
|
||||
switch (patternType) {
|
||||
case UPC_EAN_PATTERNS_L_PATTERNS:
|
||||
max = L_PATTERNS_LEN;
|
||||
for (int i = 0; i < max; i++) {
|
||||
int pattern[countersLen];
|
||||
for(int j = 0; j< countersLen; j++){
|
||||
pattern[j] = L_PATTERNS[i][j];
|
||||
}
|
||||
|
||||
unsigned int variance = patternMatchVariance(counters, countersLen, pattern, MAX_INDIVIDUAL_VARIANCE);
|
||||
if (variance < bestVariance) {
|
||||
bestVariance = variance;
|
||||
bestMatch = i;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case UPC_EAN_PATTERNS_L_AND_G_PATTERNS:
|
||||
max = L_AND_G_PATTERNS_LEN;
|
||||
for (int i = 0; i < max; i++) {
|
||||
int pattern[countersLen];
|
||||
for(int j = 0; j< countersLen; j++){
|
||||
pattern[j] = L_AND_G_PATTERNS[i][j];
|
||||
}
|
||||
|
||||
unsigned int variance = patternMatchVariance(counters, countersLen, pattern, MAX_INDIVIDUAL_VARIANCE);
|
||||
if (variance < bestVariance) {
|
||||
bestVariance = variance;
|
||||
bestMatch = i;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (bestMatch >= 0) {
|
||||
return bestMatch;
|
||||
} else {
|
||||
throw ReaderException("UPCEANReader::decodeDigit: No best mach");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return {@link #checkStandardUPCEANChecksum(String)}
|
||||
*/
|
||||
bool UPCEANReader::checkChecksum(std::string s){
|
||||
return checkStandardUPCEANChecksum(s);
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the UPC/EAN checksum on a string of digits, and reports
|
||||
* whether the checksum is correct or not.
|
||||
*
|
||||
* @param s string of digits to check
|
||||
* @return true iff string of digits passes the UPC/EAN checksum algorithm
|
||||
* @throws ReaderException if the string does not contain only digits
|
||||
*/
|
||||
bool UPCEANReader::checkStandardUPCEANChecksum(std::string s){
|
||||
int length = s.length();
|
||||
if (length == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int sum = 0;
|
||||
for (int i = length - 2; i >= 0; i -= 2) {
|
||||
int digit = (int) s[i] - (int) '0';
|
||||
if (digit < 0 || digit > 9) {
|
||||
throw ReaderException("checkStandardUPCEANChecksum");
|
||||
}
|
||||
sum += digit;
|
||||
}
|
||||
sum *= 3;
|
||||
for (int i = length - 1; i >= 0; i -= 2) {
|
||||
int digit = (int) s[i] - (int) '0';
|
||||
if (digit < 0 || digit > 9) {
|
||||
throw ReaderException("checkStandardUPCEANChecksum");
|
||||
}
|
||||
sum += digit;
|
||||
}
|
||||
return sum % 10 == 0;
|
||||
}
|
||||
UPCEANReader::~UPCEANReader(){
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int* UPCEANReader::findStartGuardPattern(Ref<BitArray> row){
|
||||
bool foundStart = false;
|
||||
|
||||
int* startRange = NULL;
|
||||
int nextStart = 0;
|
||||
try {
|
||||
while (!foundStart) {
|
||||
delete [] startRange;
|
||||
startRange = NULL;
|
||||
startRange = findGuardPattern(row, nextStart, false, START_END_PATTERN, sizeof(START_END_PATTERN)/sizeof(int));
|
||||
int start = startRange[0];
|
||||
nextStart = startRange[1];
|
||||
// Make sure there is a quiet zone at least as big as the start pattern before the barcode.
|
||||
// If this check would run off the left edge of the image, do not accept this barcode,
|
||||
// as it is very likely to be a false positive.
|
||||
int quietStart = start - (nextStart - start);
|
||||
if (quietStart >= 0) {
|
||||
foundStart = row->isRange(quietStart, start, false);
|
||||
}
|
||||
}
|
||||
return startRange;
|
||||
} catch (ReaderException const& re) {
|
||||
delete [] startRange;
|
||||
throw re;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(flyashi): Return a pair<int, int> for return value to avoid using the heap.
|
||||
int* UPCEANReader::findGuardPattern(Ref<BitArray> row, int rowOffset, bool whiteFirst, const int pattern[], int patternLen){
|
||||
int patternLength = patternLen;
|
||||
int counters[patternLength];
|
||||
int countersCount = sizeof(counters) / sizeof(int);
|
||||
for (int i = 0; i < countersCount; i++) {
|
||||
counters[i] = 0;
|
||||
}
|
||||
int width = row->getSize();
|
||||
bool isWhite = false;
|
||||
while (rowOffset < width) {
|
||||
isWhite = !row->get(rowOffset);
|
||||
if (whiteFirst == isWhite) {
|
||||
break;
|
||||
}
|
||||
rowOffset++;
|
||||
}
|
||||
|
||||
int counterPosition = 0;
|
||||
int patternStart = rowOffset;
|
||||
for (int x = rowOffset; x < width; x++) {
|
||||
bool pixel = row->get(x);
|
||||
if (pixel ^ isWhite) {
|
||||
counters[counterPosition]++;
|
||||
} else {
|
||||
if (counterPosition == patternLength - 1) {
|
||||
if (patternMatchVariance(counters, countersCount, pattern, MAX_INDIVIDUAL_VARIANCE) < MAX_AVG_VARIANCE) {
|
||||
int* resultValue = new int[2];
|
||||
resultValue[0] = patternStart;
|
||||
resultValue[1] = x;
|
||||
return resultValue;
|
||||
}
|
||||
patternStart += counters[0] + counters[1];
|
||||
for (int y = 2; y < patternLength; y++) {
|
||||
counters[y - 2] = counters[y];
|
||||
}
|
||||
counters[patternLength - 2] = 0;
|
||||
counters[patternLength - 1] = 0;
|
||||
counterPosition--;
|
||||
} else {
|
||||
counterPosition++;
|
||||
}
|
||||
counters[counterPosition] = 1;
|
||||
isWhite = !isWhite;
|
||||
}
|
||||
}
|
||||
throw ReaderException("findGuardPattern");
|
||||
}
|
||||
|
||||
int* UPCEANReader::decodeEnd(Ref<BitArray> row, int endStart){
|
||||
return findGuardPattern(row, endStart, false, START_END_PATTERN, sizeof(START_END_PATTERN)/sizeof(int));
|
||||
}
|
||||
|
||||
// int UPCEANReader::decodeDigit(Ref<BitArray> row, int counters[], int countersLen, int rowOffset, int** patterns/*[][]*/, int paterns1Len, int paterns2Len)
|
||||
int UPCEANReader::decodeDigit(Ref<BitArray> row, int counters[], int countersLen, int rowOffset, UPC_EAN_PATTERNS patternType){
|
||||
recordPattern(row, rowOffset, counters, countersLen);
|
||||
unsigned int bestVariance = MAX_AVG_VARIANCE; // worst variance we'll accept
|
||||
int bestMatch = -1;
|
||||
|
||||
int max = 0;
|
||||
switch (patternType) {
|
||||
case UPC_EAN_PATTERNS_L_PATTERNS:
|
||||
max = L_PATTERNS_LEN;
|
||||
for (int i = 0; i < max; i++) {
|
||||
int pattern[countersLen];
|
||||
for(int j = 0; j< countersLen; j++){
|
||||
pattern[j] = L_PATTERNS[i][j];
|
||||
}
|
||||
|
||||
unsigned int variance = patternMatchVariance(counters, countersLen, pattern, MAX_INDIVIDUAL_VARIANCE);
|
||||
if (variance < bestVariance) {
|
||||
bestVariance = variance;
|
||||
bestMatch = i;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case UPC_EAN_PATTERNS_L_AND_G_PATTERNS:
|
||||
max = L_AND_G_PATTERNS_LEN;
|
||||
for (int i = 0; i < max; i++) {
|
||||
int pattern[countersLen];
|
||||
for(int j = 0; j< countersLen; j++){
|
||||
pattern[j] = L_AND_G_PATTERNS[i][j];
|
||||
}
|
||||
|
||||
unsigned int variance = patternMatchVariance(counters, countersLen, pattern, MAX_INDIVIDUAL_VARIANCE);
|
||||
if (variance < bestVariance) {
|
||||
bestVariance = variance;
|
||||
bestMatch = i;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (bestMatch >= 0) {
|
||||
return bestMatch;
|
||||
} else {
|
||||
throw ReaderException("UPCEANReader::decodeDigit: No best mach");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return {@link #checkStandardUPCEANChecksum(String)}
|
||||
*/
|
||||
bool UPCEANReader::checkChecksum(std::string s){
|
||||
return checkStandardUPCEANChecksum(s);
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the UPC/EAN checksum on a string of digits, and reports
|
||||
* whether the checksum is correct or not.
|
||||
*
|
||||
* @param s string of digits to check
|
||||
* @return true iff string of digits passes the UPC/EAN checksum algorithm
|
||||
* @throws ReaderException if the string does not contain only digits
|
||||
*/
|
||||
bool UPCEANReader::checkStandardUPCEANChecksum(std::string s){
|
||||
int length = s.length();
|
||||
if (length == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int sum = 0;
|
||||
for (int i = length - 2; i >= 0; i -= 2) {
|
||||
int digit = (int) s[i] - (int) '0';
|
||||
if (digit < 0 || digit > 9) {
|
||||
throw ReaderException("checkStandardUPCEANChecksum");
|
||||
}
|
||||
sum += digit;
|
||||
}
|
||||
sum *= 3;
|
||||
for (int i = length - 1; i >= 0; i -= 2) {
|
||||
int digit = (int) s[i] - (int) '0';
|
||||
if (digit < 0 || digit > 9) {
|
||||
throw ReaderException("checkStandardUPCEANChecksum");
|
||||
}
|
||||
sum += digit;
|
||||
}
|
||||
return sum % 10 == 0;
|
||||
}
|
||||
UPCEANReader::~UPCEANReader(){
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue