mirror of
https://github.com/zxing/zxing.git
synced 2025-03-05 20:48:51 -08:00
Updated with the latest version of the library. Uses MultiFormatReader instead of QRCodeReader. DataMatrixReader is still not supported.
git-svn-id: https://zxing.googlecode.com/svn/trunk@1481 59b500cc-1b3d-0410-9834-0bbf25fbcc57
This commit is contained in:
parent
5a36cea5af
commit
31b5627fee
|
@ -29,7 +29,8 @@
|
|||
****************************************************************************/
|
||||
|
||||
#include "QQrDecoder.h"
|
||||
#include <zxing/qrcode/QRCodeReader.h>
|
||||
//#include <zxing/qrcode/QRCodeReader.h>
|
||||
#include <zxing/MultiFormatReader.h>
|
||||
|
||||
#include <zxing/common/GlobalHistogramBinarizer.h>
|
||||
#include <zxing/Binarizer.h>
|
||||
|
@ -41,7 +42,7 @@
|
|||
#include <QPixmap>
|
||||
|
||||
using namespace zxing;
|
||||
using namespace zxing::qrcode;
|
||||
//using namespace zxing::qrcode;
|
||||
|
||||
QQrDecoder::QQrDecoder(QWidget *parent): QMainWindow(parent)
|
||||
{
|
||||
|
@ -67,7 +68,7 @@ void QQrDecoder::findAndDecode()
|
|||
|
||||
void QQrDecoder::decodeImage(QImage originalImage)
|
||||
{
|
||||
QRCodeReader decoder;
|
||||
MultiFormatReader decoder;
|
||||
|
||||
image.setImage(originalImage);
|
||||
|
||||
|
|
|
@ -61,7 +61,6 @@ HEADERS += CameraImageWrapper.h \
|
|||
zxing/qrcode/detector/FinderPatternFinder.h \
|
||||
zxing/qrcode/detector/FinderPatternInfo.h \
|
||||
zxing/qrcode/detector/QREdgeDetector.h \
|
||||
QQrDecoder.loc \
|
||||
QQrDecoder.h
|
||||
SOURCES += CameraImageWrapper.cpp \
|
||||
zxing/BarcodeFormat.cpp \
|
||||
|
@ -121,8 +120,6 @@ SOURCES += CameraImageWrapper.cpp \
|
|||
zxing/qrcode/detector/FinderPatternFinder.cpp \
|
||||
zxing/qrcode/detector/FinderPatternInfo.cpp \
|
||||
zxing/qrcode/detector/QREdgeDetector.cpp \
|
||||
QQrDecoder.rss \
|
||||
QQrDecoder_reg.rss \
|
||||
main.cpp \
|
||||
QQrDecoder.cpp
|
||||
FORMS += QQrDecoder.ui
|
||||
|
|
Binary file not shown.
|
@ -23,15 +23,17 @@
|
|||
|
||||
namespace zxing {
|
||||
|
||||
Binarizer::Binarizer(Ref<LuminanceSource> source) : source_(source), array_(NULL), matrix_(NULL) {
|
||||
Binarizer::Binarizer(Ref<LuminanceSource> source) : source_(source), array_(NULL), matrix_(NULL), cached_y_(-1) {
|
||||
}
|
||||
|
||||
Binarizer::~Binarizer() {
|
||||
}
|
||||
|
||||
Ref<BitArray> Binarizer::getBlackRow(int y, Ref<BitArray> row){
|
||||
if (array_ == NULL)
|
||||
if (array_ == NULL && cached_y_ != y) {
|
||||
array_ = estimateBlackRow(y, row);
|
||||
cached_y_ = y;
|
||||
}
|
||||
return array_;
|
||||
}
|
||||
|
||||
|
|
|
@ -28,24 +28,25 @@
|
|||
#include <zxing/common/Counted.h>
|
||||
|
||||
namespace zxing {
|
||||
|
||||
class Binarizer : public Counted {
|
||||
private:
|
||||
Ref<LuminanceSource> source_;
|
||||
Ref<BitMatrix> matrix_;
|
||||
Ref<BitArray> array_;
|
||||
|
||||
public:
|
||||
Binarizer(Ref<LuminanceSource> source);
|
||||
virtual ~Binarizer();
|
||||
|
||||
virtual Ref<BitArray> estimateBlackRow(int y, Ref<BitArray> row)=0;
|
||||
Ref<BitArray> getBlackRow(int y, Ref<BitArray> row);
|
||||
|
||||
virtual Ref<BitMatrix> estimateBlackMatrix() = 0;
|
||||
Ref<BitMatrix> getBlackMatrix();
|
||||
Ref<LuminanceSource> getSource();
|
||||
};
|
||||
|
||||
|
||||
class Binarizer : public Counted {
|
||||
private:
|
||||
Ref<LuminanceSource> source_;
|
||||
Ref<BitArray> array_;
|
||||
Ref<BitMatrix> matrix_;
|
||||
int cached_y_;
|
||||
|
||||
public:
|
||||
Binarizer(Ref<LuminanceSource> source);
|
||||
virtual ~Binarizer();
|
||||
|
||||
virtual Ref<BitArray> estimateBlackRow(int y, Ref<BitArray> row)=0;
|
||||
Ref<BitArray> getBlackRow(int y, Ref<BitArray> row);
|
||||
|
||||
virtual Ref<BitMatrix> estimateBlackMatrix() = 0;
|
||||
Ref<BitMatrix> getBlackMatrix();
|
||||
Ref<LuminanceSource> getSource();
|
||||
};
|
||||
|
||||
}
|
||||
#endif /* BINARIZER_H_ */
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
|
||||
namespace zxing {
|
||||
|
||||
BinaryBitmap::BinaryBitmap(Ref<Binarizer> binarizer) : bits_(NULL), array_bits_(NULL), binarizer_(binarizer) {
|
||||
BinaryBitmap::BinaryBitmap(Ref<Binarizer> binarizer) : bits_(NULL), array_bits_(NULL), binarizer_(binarizer), cached_y_(-1) {
|
||||
|
||||
}
|
||||
|
||||
|
@ -31,8 +31,9 @@ namespace zxing {
|
|||
}
|
||||
|
||||
Ref<BitArray> BinaryBitmap::getBlackRow(int y, Ref<BitArray> row) {
|
||||
if (array_bits_ == NULL) {
|
||||
if (array_bits_ == NULL && cached_y_ != y) {
|
||||
array_bits_ = binarizer_->getBlackRow(y, row);
|
||||
cached_y_ = y;
|
||||
}
|
||||
return array_bits_;
|
||||
}
|
||||
|
|
|
@ -33,6 +33,7 @@ namespace zxing {
|
|||
Ref<BitMatrix> bits_;
|
||||
Ref<BitArray> array_bits_;
|
||||
Ref<Binarizer> binarizer_;
|
||||
int cached_y_;
|
||||
|
||||
public:
|
||||
BinaryBitmap(Ref<Binarizer> binarizer);
|
||||
|
|
|
@ -28,7 +28,7 @@ LuminanceSource::LuminanceSource() {
|
|||
LuminanceSource::~LuminanceSource() {
|
||||
}
|
||||
|
||||
unsigned char* LuminanceSource::copyMatrix() const {
|
||||
unsigned char* LuminanceSource::copyMatrix() {
|
||||
int width = getWidth();
|
||||
int height = getHeight();
|
||||
unsigned char* matrix = new unsigned char[width*height];
|
||||
|
|
|
@ -34,7 +34,7 @@ public:
|
|||
virtual int getHeight() const = 0;
|
||||
|
||||
virtual unsigned char getPixel(int x, int y) const = 0;
|
||||
virtual unsigned char* copyMatrix() const;
|
||||
virtual unsigned char* copyMatrix();
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "MultiFormatReader.h"
|
||||
#include <zxing/MultiFormatReader.h>
|
||||
#include <zxing/qrcode/QRCodeReader.h>
|
||||
//#include <zxing/datamatrix/DataMatrixReader.h>
|
||||
#include <zxing/oned/MultiFormatUPCEANReader.h>
|
||||
|
@ -27,23 +27,27 @@
|
|||
#include <zxing/ReaderException.h>
|
||||
|
||||
namespace zxing {
|
||||
MultiFormatReader::MultiFormatReader() : readers() {
|
||||
readers.push_back(Ref<Reader>(new zxing::qrcode::QRCodeReader()));
|
||||
//readers.push_back(Ref<Reader>(new zxing::datamatrix::DataMatrixReader()));
|
||||
readers.push_back(Ref<Reader>(new zxing::oned::MultiFormatUPCEANReader()));
|
||||
readers.push_back(Ref<Reader>(new zxing::oned::MultiFormatOneDReader()));
|
||||
MultiFormatReader::MultiFormatReader() {
|
||||
readers.push_back(new zxing::qrcode::QRCodeReader());
|
||||
//readers.push_back(new zxing::datamatrix::DataMatrixReader());
|
||||
readers.push_back(new zxing::oned::MultiFormatUPCEANReader());
|
||||
readers.push_back(new zxing::oned::MultiFormatOneDReader());
|
||||
}
|
||||
|
||||
Ref<Result> MultiFormatReader::decode(Ref<BinaryBitmap> image){
|
||||
int size = readers.size();
|
||||
for (int i = 0; i < size; i++) {
|
||||
Ref<Reader> reader = readers[i];
|
||||
for (unsigned int i = 0; i < readers.size(); i++) {
|
||||
try {
|
||||
return reader->decode(image);
|
||||
return readers[i]->decode(image);
|
||||
} catch (ReaderException re) {
|
||||
// continue
|
||||
}
|
||||
}
|
||||
throw ReaderException("No code detected");
|
||||
}
|
||||
|
||||
MultiFormatReader::~MultiFormatReader(){
|
||||
for (unsigned int i = 0; i < readers.size(); i++) {
|
||||
delete readers[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
* ZXing
|
||||
*
|
||||
* Created by Lukasz Warchol on 10-01-26.
|
||||
* Modified by Luiz Silva on 09/02/2010.
|
||||
* Copyright 2010 ZXing authors All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
|
@ -27,11 +28,12 @@ namespace zxing {
|
|||
class MultiFormatReader : public Reader {
|
||||
|
||||
private:
|
||||
std::vector<Ref<Reader> >readers;
|
||||
std::vector<Reader*>readers;
|
||||
public:
|
||||
MultiFormatReader();
|
||||
|
||||
Ref<Result> decode(Ref<BinaryBitmap> image);
|
||||
|
||||
~MultiFormatReader();
|
||||
};
|
||||
}
|
||||
|
|
|
@ -107,10 +107,12 @@ vector<unsigned int>& BitArray::getBitArray() {
|
|||
return bits_;
|
||||
}
|
||||
void BitArray::reverse() {
|
||||
unsigned int allBits = numeric_limits<unsigned int>::max();
|
||||
size_t max = bits_.size();
|
||||
for (size_t i = 0; i < max; i++) {
|
||||
bits_[i] = bits_[i] ^ allBits;
|
||||
std::vector<unsigned int> newBits(bits_.size(),(const unsigned int) 0);
|
||||
for (size_t i = 0; i < size_; i++) {
|
||||
if (get(size_ - i - 1)) {
|
||||
newBits[i >> logBits_] |= 1<< (i & bitsMask_);
|
||||
}
|
||||
}
|
||||
bits_ = newBits;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,154 +24,160 @@
|
|||
#include <zxing/common/IllegalArgumentException.h>
|
||||
|
||||
namespace zxing {
|
||||
using namespace std;
|
||||
|
||||
const int LUMINANCE_BITS = 5;
|
||||
const int LUMINANCE_SHIFT = 8 - LUMINANCE_BITS;
|
||||
const int LUMINANCE_BUCKETS = 1 << LUMINANCE_BITS;
|
||||
|
||||
GlobalHistogramBinarizer::GlobalHistogramBinarizer(Ref<LuminanceSource> source) :
|
||||
Binarizer(source) {
|
||||
|
||||
}
|
||||
|
||||
GlobalHistogramBinarizer::~GlobalHistogramBinarizer() {
|
||||
}
|
||||
|
||||
|
||||
Ref<BitArray> GlobalHistogramBinarizer::estimateBlackRow(int y, Ref<BitArray> row){
|
||||
vector<int> histogram(LUMINANCE_BUCKETS, 0);
|
||||
LuminanceSource& source = *getSource();
|
||||
int width = source.getWidth();
|
||||
if (row == NULL || row->getSize() < width) {
|
||||
row = new BitArray(width);
|
||||
} else {
|
||||
row->clear();
|
||||
}
|
||||
|
||||
for (int x = 0; x < width; x++) {
|
||||
unsigned char pixel = source.getPixel(x, y);
|
||||
histogram[pixel >> LUMINANCE_SHIFT]++;
|
||||
}
|
||||
int blackPoint = estimate(histogram) << LUMINANCE_SHIFT;
|
||||
|
||||
|
||||
Ref<BitArray> array_ref(new BitArray(width));
|
||||
BitArray& array = *array_ref;
|
||||
|
||||
int left = source.getPixel(0, y);
|
||||
int center = source.getPixel(1, y);
|
||||
for (int x = 1; x < width - 1; x++) {
|
||||
int right = source.getPixel(x+1, y);
|
||||
// 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;
|
||||
}
|
||||
|
||||
return array_ref;
|
||||
}
|
||||
|
||||
Ref<BitMatrix> GlobalHistogramBinarizer::estimateBlackMatrix() {
|
||||
// Faster than working with the reference
|
||||
LuminanceSource& source = *getSource();
|
||||
int width = source.getWidth();
|
||||
int height = source.getHeight();
|
||||
vector<int> histogram(LUMINANCE_BUCKETS, 0);
|
||||
|
||||
|
||||
// Quickly calculates the histogram by sampling four rows from the image. This proved to be
|
||||
// more robust on the blackbox tests than sampling a diagonal as we used to do.
|
||||
for (int y = 1; y < 5; y++) {
|
||||
int row = height * y / 5;
|
||||
int right = (width << 2) / 5;
|
||||
int sdf;
|
||||
for (int x = width / 5; x < right; x++) {
|
||||
unsigned char pixel = source.getPixel(x, row);
|
||||
histogram[pixel >> LUMINANCE_SHIFT]++;
|
||||
sdf = histogram[pixel >> LUMINANCE_SHIFT];
|
||||
}
|
||||
}
|
||||
|
||||
int blackPoint = estimate(histogram) << LUMINANCE_SHIFT;
|
||||
|
||||
Ref<BitMatrix> matrix_ref(new BitMatrix(width, height));
|
||||
BitMatrix& matrix = *matrix_ref;
|
||||
for (int y = 0; y < height; y++) {
|
||||
for (int x = 0; x < width; x++) {
|
||||
if (source.getPixel(x, y) <= blackPoint)
|
||||
matrix.set(x, y);
|
||||
}
|
||||
}
|
||||
return matrix_ref;
|
||||
}
|
||||
|
||||
int GlobalHistogramBinarizer::estimate(vector<int> &histogram) {
|
||||
int numBuckets = histogram.size();
|
||||
int maxBucketCount = 0;
|
||||
|
||||
|
||||
// Find tallest peak in histogram
|
||||
int firstPeak = 0;
|
||||
int firstPeakSize = 0;
|
||||
for (int i = 0; i < numBuckets; i++) {
|
||||
if (histogram[i] > firstPeakSize) {
|
||||
firstPeak = i;
|
||||
firstPeakSize = histogram[i];
|
||||
}
|
||||
if (histogram[i] > maxBucketCount) {
|
||||
maxBucketCount = histogram[i];
|
||||
}
|
||||
}
|
||||
|
||||
// Find second-tallest peak -- well, another peak that is tall and not
|
||||
// so close to the first one
|
||||
int secondPeak = 0;
|
||||
int secondPeakScore = 0;
|
||||
for (int i = 0; i < numBuckets; i++) {
|
||||
int distanceToBiggest = i - firstPeak;
|
||||
// Encourage more distant second peaks by multiplying by square of distance
|
||||
int score = histogram[i] * distanceToBiggest * distanceToBiggest;
|
||||
if (score > secondPeakScore) {
|
||||
secondPeak = i;
|
||||
secondPeakScore = score;
|
||||
}
|
||||
}
|
||||
|
||||
// Put firstPeak first
|
||||
if (firstPeak > secondPeak) {
|
||||
int temp = firstPeak;
|
||||
firstPeak = secondPeak;
|
||||
secondPeak = temp;
|
||||
}
|
||||
|
||||
// Kind of arbitrary; if the two peaks are very close, then we figure there is so little
|
||||
// dynamic range in the image, that discriminating black and white is too error-prone.
|
||||
// Decoding the image/line is either pointless, or may in some cases lead to a false positive
|
||||
// for 1D formats, which are relatively lenient.
|
||||
// We arbitrarily say "close" is "<= 1/16 of the total histogram buckets apart"
|
||||
if (secondPeak - firstPeak <= numBuckets >> 4) {
|
||||
throw IllegalArgumentException("Too little dynamic range in luminance");
|
||||
}
|
||||
|
||||
// Find a valley between them that is low and closer to the white peak
|
||||
int bestValley = secondPeak - 1;
|
||||
int bestValleyScore = -1;
|
||||
for (int i = secondPeak - 1; i > firstPeak; i--) {
|
||||
int fromFirst = i - firstPeak;
|
||||
// Favor a "valley" that is not too close to either peak -- especially not the black peak --
|
||||
// and that has a low value of course
|
||||
int score = fromFirst * fromFirst * (secondPeak - i) * (maxBucketCount - histogram[i]);
|
||||
if (score > bestValleyScore) {
|
||||
bestValley = i;
|
||||
bestValleyScore = score;
|
||||
}
|
||||
}
|
||||
|
||||
return bestValley;
|
||||
}
|
||||
|
||||
using namespace std;
|
||||
|
||||
const int LUMINANCE_BITS = 5;
|
||||
const int LUMINANCE_SHIFT = 8 - LUMINANCE_BITS;
|
||||
const int LUMINANCE_BUCKETS = 1 << LUMINANCE_BITS;
|
||||
|
||||
GlobalHistogramBinarizer::GlobalHistogramBinarizer(Ref<LuminanceSource> source) :
|
||||
Binarizer(source) {
|
||||
|
||||
}
|
||||
|
||||
GlobalHistogramBinarizer::~GlobalHistogramBinarizer() {
|
||||
}
|
||||
|
||||
|
||||
Ref<BitArray> GlobalHistogramBinarizer::estimateBlackRow(int y,
|
||||
Ref<BitArray> row){
|
||||
vector<int> histogram(LUMINANCE_BUCKETS, 0);
|
||||
LuminanceSource& source = *getSource();
|
||||
int width = source.getWidth();
|
||||
if (row == NULL || static_cast<int>(row->getSize()) < width) {
|
||||
row = new BitArray(width);
|
||||
} else {
|
||||
row->clear();
|
||||
}
|
||||
|
||||
for (int x = 0; x < width; x++) {
|
||||
unsigned char pixel = source.getPixel(x, y);
|
||||
histogram[pixel >> LUMINANCE_SHIFT]++;
|
||||
}
|
||||
int blackPoint = estimate(histogram) << LUMINANCE_SHIFT;
|
||||
|
||||
|
||||
Ref<BitArray> array_ref(new BitArray(width));
|
||||
BitArray& array = *array_ref;
|
||||
|
||||
int left = source.getPixel(0, y);
|
||||
int center = source.getPixel(1, y);
|
||||
for (int x = 1; x < width - 1; x++) {
|
||||
int right = source.getPixel(x+1, y);
|
||||
// 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;
|
||||
}
|
||||
|
||||
return array_ref;
|
||||
}
|
||||
|
||||
Ref<BitMatrix> GlobalHistogramBinarizer::estimateBlackMatrix() {
|
||||
// Faster than working with the reference
|
||||
LuminanceSource& source = *getSource();
|
||||
int width = source.getWidth();
|
||||
int height = source.getHeight();
|
||||
vector<int> histogram(LUMINANCE_BUCKETS, 0);
|
||||
|
||||
|
||||
// Quickly calculates the histogram by sampling four rows from the image.
|
||||
// This proved to be more robust on the blackbox tests than sampling a
|
||||
// diagonal as we used to do.
|
||||
for (int y = 1; y < 5; y++) {
|
||||
int row = height * y / 5;
|
||||
int right = (width << 2) / 5;
|
||||
int sdf;
|
||||
for (int x = width / 5; x < right; x++) {
|
||||
unsigned char pixel = source.getPixel(x, row);
|
||||
histogram[pixel >> LUMINANCE_SHIFT]++;
|
||||
sdf = histogram[pixel >> LUMINANCE_SHIFT];
|
||||
}
|
||||
}
|
||||
|
||||
int blackPoint = estimate(histogram) << LUMINANCE_SHIFT;
|
||||
|
||||
Ref<BitMatrix> matrix_ref(new BitMatrix(width, height));
|
||||
BitMatrix& matrix = *matrix_ref;
|
||||
for (int y = 0; y < height; y++) {
|
||||
for (int x = 0; x < width; x++) {
|
||||
if (source.getPixel(x, y) <= blackPoint)
|
||||
matrix.set(x, y);
|
||||
}
|
||||
}
|
||||
return matrix_ref;
|
||||
}
|
||||
|
||||
int GlobalHistogramBinarizer::estimate(vector<int> &histogram) {
|
||||
int numBuckets = histogram.size();
|
||||
int maxBucketCount = 0;
|
||||
|
||||
|
||||
// Find tallest peak in histogram
|
||||
int firstPeak = 0;
|
||||
int firstPeakSize = 0;
|
||||
for (int i = 0; i < numBuckets; i++) {
|
||||
if (histogram[i] > firstPeakSize) {
|
||||
firstPeak = i;
|
||||
firstPeakSize = histogram[i];
|
||||
}
|
||||
if (histogram[i] > maxBucketCount) {
|
||||
maxBucketCount = histogram[i];
|
||||
}
|
||||
}
|
||||
|
||||
// Find second-tallest peak -- well, another peak that is tall and not
|
||||
// so close to the first one
|
||||
int secondPeak = 0;
|
||||
int secondPeakScore = 0;
|
||||
for (int i = 0; i < numBuckets; i++) {
|
||||
int distanceToBiggest = i - firstPeak;
|
||||
// Encourage more distant second peaks by multiplying by square of distance
|
||||
int score = histogram[i] * distanceToBiggest * distanceToBiggest;
|
||||
if (score > secondPeakScore) {
|
||||
secondPeak = i;
|
||||
secondPeakScore = score;
|
||||
}
|
||||
}
|
||||
|
||||
// Put firstPeak first
|
||||
if (firstPeak > secondPeak) {
|
||||
int temp = firstPeak;
|
||||
firstPeak = secondPeak;
|
||||
secondPeak = temp;
|
||||
}
|
||||
|
||||
// Kind of arbitrary; if the two peaks are very close, then we figure there is
|
||||
// so little dynamic range in the image, that discriminating black and white
|
||||
// is too error-prone.
|
||||
// Decoding the image/line is either pointless, or may in some cases lead to
|
||||
// a false positive for 1D formats, which are relatively lenient.
|
||||
// We arbitrarily say "close" is
|
||||
// "<= 1/16 of the total histogram buckets apart"
|
||||
if (secondPeak - firstPeak <= numBuckets >> 4) {
|
||||
throw IllegalArgumentException("Too little dynamic range in luminance");
|
||||
}
|
||||
|
||||
// Find a valley between them that is low and closer to the white peak
|
||||
int bestValley = secondPeak - 1;
|
||||
int bestValleyScore = -1;
|
||||
for (int i = secondPeak - 1; i > firstPeak; i--) {
|
||||
int fromFirst = i - firstPeak;
|
||||
// Favor a "valley" that is not too close to either peak -- especially not
|
||||
// the black peak -- and that has a low value of course
|
||||
int score = fromFirst * fromFirst * (secondPeak - i) *
|
||||
(maxBucketCount - histogram[i]);
|
||||
if (score > bestValleyScore) {
|
||||
bestValley = i;
|
||||
bestValleyScore = score;
|
||||
}
|
||||
}
|
||||
|
||||
return bestValley;
|
||||
}
|
||||
|
||||
} // namespace zxing
|
||||
|
||||
|
|
|
@ -28,8 +28,8 @@ PerspectiveTransform::PerspectiveTransform(float inA11, float inA21,
|
|||
float inA22, float inA32,
|
||||
float inA13, float inA23,
|
||||
float inA33) :
|
||||
a11(inA11), a21(inA21), a31(inA31), a12(inA12), a22(inA22), a32(inA32),
|
||||
a13(inA13), a23(inA23), a33(inA33) {}
|
||||
a11(inA11), a12(inA12), a13(inA13), a21(inA21), a22(inA22), a23(inA23),
|
||||
a31(inA31), a32(inA32), a33(inA33) {}
|
||||
|
||||
Ref<PerspectiveTransform> PerspectiveTransform::quadrilateralToQuadrilateral(float x0, float y0, float x1, float y1,
|
||||
float x2, float y2, float x3, float y3, float x0p, float y0p, float x1p, float y1p, float x2p, float y2p,
|
||||
|
|
|
@ -109,13 +109,10 @@ int GF256::multiply(int a, int b) {
|
|||
if (a == 0 || b == 0) {
|
||||
return 0;
|
||||
}
|
||||
if (a == 1) {
|
||||
return b;
|
||||
}
|
||||
if (b == 1) {
|
||||
return a;
|
||||
}
|
||||
return exp_[(log_[a] + log_[b]) % 255];
|
||||
int logSum = log_[a] + log_[b];
|
||||
// index is a sped-up alternative to logSum % 255 since sum
|
||||
// is in [0,510]. Thanks to jmsachs for the idea
|
||||
return exp_[(logSum & 0xFF) + (logSum >> 8)];
|
||||
}
|
||||
|
||||
GF256 GF256::QR_CODE_FIELD(0x011D); // x^8 + x^4 + x^3 + x^2 + 1
|
||||
|
|
82
symbian/QQrDecoder/zxing/datamatrix/DataMatrixReader.cpp
Normal file
82
symbian/QQrDecoder/zxing/datamatrix/DataMatrixReader.cpp
Normal file
|
@ -0,0 +1,82 @@
|
|||
/*
|
||||
* DataMatrixReader.cpp
|
||||
* zxing
|
||||
*
|
||||
* Created by Luiz Silva on 09/02/2010.
|
||||
* Copyright 2010 ZXing authors All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <zxing/datamatrix/DataMatrixReader.h>
|
||||
#include <zxing/datamatrix/detector/Detector.h>
|
||||
#include <iostream>
|
||||
|
||||
namespace zxing {
|
||||
namespace datamatrix {
|
||||
|
||||
using namespace std;
|
||||
|
||||
DataMatrixReader::DataMatrixReader() :
|
||||
decoder_() {
|
||||
}
|
||||
|
||||
Ref<Result> DataMatrixReader::decode(Ref<BinaryBitmap> image) {
|
||||
#ifdef DEBUG
|
||||
cout << "decoding image " << image.object_ << ":\n" << flush;
|
||||
#endif
|
||||
|
||||
Detector detector(image->getBlackMatrix());
|
||||
|
||||
|
||||
#ifdef DEBUG
|
||||
cout << "(1) created detector " << &detector << "\n" << flush;
|
||||
#endif
|
||||
|
||||
Ref<DetectorResult> detectorResult(detector.detect());
|
||||
#ifdef DEBUG
|
||||
cout << "(2) detected, have detectorResult " << detectorResult.object_ << "\n" << flush;
|
||||
#endif
|
||||
|
||||
std::vector<Ref<ResultPoint> > points(detectorResult->getPoints());
|
||||
|
||||
|
||||
#ifdef DEBUG
|
||||
cout << "(3) extracted points " << &points << "\n" << flush;
|
||||
cout << "found " << points.size() << " points:\n";
|
||||
for (size_t i = 0; i < points.size(); i++) {
|
||||
cout << " " << points[i]->getX() << "," << points[i]->getY() << "\n";
|
||||
}
|
||||
cout << "bits:\n";
|
||||
cout << *(detectorResult->getBits()) << "\n";
|
||||
#endif
|
||||
|
||||
Ref<DecoderResult> decoderResult(decoder_.decode(detectorResult->getBits()));
|
||||
#ifdef DEBUG
|
||||
cout << "(4) decoded, have decoderResult " << decoderResult.object_ << "\n" << flush;
|
||||
#endif
|
||||
|
||||
Ref<Result> result(
|
||||
new Result(decoderResult->getText(), decoderResult->getRawBytes(), points, BarcodeFormat_DATA_MATRIX));
|
||||
#ifdef DEBUG
|
||||
cout << "(5) created result " << result.object_ << ", returning\n" << flush;
|
||||
#endif
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
DataMatrixReader::~DataMatrixReader() {
|
||||
}
|
||||
|
||||
}
|
||||
}
|
44
symbian/QQrDecoder/zxing/datamatrix/DataMatrixReader.h
Normal file
44
symbian/QQrDecoder/zxing/datamatrix/DataMatrixReader.h
Normal file
|
@ -0,0 +1,44 @@
|
|||
#ifndef __DATA_MATRIX_READER_H__
|
||||
#define __DATA_MATRIX_READER_H__
|
||||
|
||||
/*
|
||||
* DataMatrixReader.h
|
||||
* zxing
|
||||
*
|
||||
* Created by Luiz Silva on 09/02/2010.
|
||||
* Copyright 2010 ZXing authors All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <zxing/Reader.h>
|
||||
#include <zxing/datamatrix/decoder/Decoder.h>
|
||||
|
||||
namespace zxing {
|
||||
namespace datamatrix {
|
||||
|
||||
class DataMatrixReader : public Reader {
|
||||
private:
|
||||
Decoder decoder_;
|
||||
|
||||
public:
|
||||
DataMatrixReader();
|
||||
virtual Ref<Result> decode(Ref<BinaryBitmap> image);
|
||||
virtual ~DataMatrixReader();
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif // __DATA_MATRIX_READER_H__
|
199
symbian/QQrDecoder/zxing/datamatrix/Version.cpp
Normal file
199
symbian/QQrDecoder/zxing/datamatrix/Version.cpp
Normal file
|
@ -0,0 +1,199 @@
|
|||
/*
|
||||
* Version.cpp
|
||||
* zxing
|
||||
*
|
||||
* Created by Luiz Silva on 09/02/2010.
|
||||
* Copyright 2010 ZXing authors All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <zxing/datamatrix/Version.h>
|
||||
#include <limits>
|
||||
#include <iostream>
|
||||
|
||||
namespace zxing {
|
||||
namespace datamatrix {
|
||||
using namespace std;
|
||||
|
||||
ECB::ECB(int count, int dataCodewords) :
|
||||
count_(count), dataCodewords_(dataCodewords) {
|
||||
}
|
||||
|
||||
int ECB::getCount() {
|
||||
return count_;
|
||||
}
|
||||
|
||||
int ECB::getDataCodewords() {
|
||||
return dataCodewords_;
|
||||
}
|
||||
|
||||
ECBlocks::ECBlocks(int ecCodewords, ECB *ecBlocks) :
|
||||
ecCodewords_(ecCodewords), ecBlocks_(1, ecBlocks) {
|
||||
}
|
||||
|
||||
ECBlocks::ECBlocks(int ecCodewords, ECB *ecBlocks1, ECB *ecBlocks2) :
|
||||
ecCodewords_(ecCodewords), ecBlocks_(1, ecBlocks1) {
|
||||
ecBlocks_.push_back(ecBlocks2);
|
||||
}
|
||||
|
||||
int ECBlocks::getECCodewords() {
|
||||
return ecCodewords_;
|
||||
}
|
||||
|
||||
std::vector<ECB*>& ECBlocks::getECBlocks() {
|
||||
return ecBlocks_;
|
||||
}
|
||||
|
||||
ECBlocks::~ECBlocks() {
|
||||
for (size_t i = 0; i < ecBlocks_.size(); i++) {
|
||||
delete ecBlocks_[i];
|
||||
}
|
||||
}
|
||||
|
||||
vector<Ref<Version> > Version::VERSIONS;
|
||||
static int N_VERSIONS = Version::buildVersions();
|
||||
|
||||
Version::Version(int versionNumber, int symbolSizeRows, int symbolSizeColumns, int dataRegionSizeRows,
|
||||
int dataRegionSizeColumns, ECBlocks* ecBlocks) : versionNumber_(versionNumber),
|
||||
symbolSizeRows_(symbolSizeRows), symbolSizeColumns_(symbolSizeColumns),
|
||||
dataRegionSizeRows_(dataRegionSizeRows), dataRegionSizeColumns_(dataRegionSizeColumns),
|
||||
ecBlocks_(ecBlocks), totalCodewords_(0) {
|
||||
// Calculate the total number of codewords
|
||||
int total = 0;
|
||||
int ecCodewords = ecBlocks_->getECCodewords();
|
||||
vector<ECB*> &ecbArray = ecBlocks_->getECBlocks();
|
||||
for (unsigned int i = 0; i < ecbArray.size(); i++) {
|
||||
ECB *ecBlock = ecbArray[i];
|
||||
total += ecBlock->getCount() * (ecBlock->getDataCodewords() + ecCodewords);
|
||||
}
|
||||
totalCodewords_ = total;
|
||||
}
|
||||
|
||||
Version::~Version() {
|
||||
delete ecBlocks_;
|
||||
}
|
||||
|
||||
int Version::getVersionNumber() {
|
||||
return versionNumber_;
|
||||
}
|
||||
|
||||
int Version::getSymbolSizeRows() {
|
||||
return symbolSizeRows_;
|
||||
}
|
||||
|
||||
int Version::getSymbolSizeColumns() {
|
||||
return symbolSizeColumns_;
|
||||
}
|
||||
|
||||
int Version::getDataRegionSizeRows() {
|
||||
return dataRegionSizeRows_;
|
||||
}
|
||||
|
||||
int Version::getDataRegionSizeColumns() {
|
||||
return dataRegionSizeColumns_;
|
||||
}
|
||||
|
||||
int Version::getTotalCodewords() {
|
||||
return totalCodewords_;
|
||||
}
|
||||
|
||||
ECBlocks* Version::getECBlocks() {
|
||||
return ecBlocks_;
|
||||
}
|
||||
|
||||
Ref<Version> Version::getVersionForDimensions(int numRows, int numColumns) {
|
||||
if ((numRows & 0x01) != 0 || (numColumns & 0x01) != 0) {
|
||||
throw ReaderException("Number of rows and columns must be even");
|
||||
}
|
||||
|
||||
// TODO(bbrown): This is doing a linear search through the array of versions.
|
||||
// If we interleave the rectangular versions with the square versions we could
|
||||
// do a binary search.
|
||||
for (int i = 0; i < N_VERSIONS; ++i){
|
||||
Ref<Version> version(VERSIONS[i]);
|
||||
if (version->getSymbolSizeRows() == numRows && version->getSymbolSizeColumns() == numColumns) {
|
||||
return version;
|
||||
}
|
||||
}
|
||||
throw ReaderException("Error version not found");
|
||||
}
|
||||
|
||||
/**
|
||||
* See ISO 16022:2006 5.5.1 Table 7
|
||||
*/
|
||||
int Version::buildVersions() {
|
||||
VERSIONS.push_back(Ref<Version>(new Version(1, 10, 10, 8, 8,
|
||||
new ECBlocks(5, new ECB(1, 3)))));
|
||||
VERSIONS.push_back(Ref<Version>(new Version(2, 12, 12, 10, 10,
|
||||
new ECBlocks(7, new ECB(1, 5)))));
|
||||
VERSIONS.push_back(Ref<Version>(new Version(3, 14, 14, 12, 12,
|
||||
new ECBlocks(10, new ECB(1, 8)))));
|
||||
VERSIONS.push_back(Ref<Version>(new Version(4, 16, 16, 14, 14,
|
||||
new ECBlocks(12, new ECB(1, 12)))));
|
||||
VERSIONS.push_back(Ref<Version>(new Version(5, 18, 18, 16, 16,
|
||||
new ECBlocks(14, new ECB(1, 18)))));
|
||||
VERSIONS.push_back(Ref<Version>(new Version(6, 20, 20, 18, 18,
|
||||
new ECBlocks(18, new ECB(1, 22)))));
|
||||
VERSIONS.push_back(Ref<Version>(new Version(7, 22, 22, 20, 20,
|
||||
new ECBlocks(20, new ECB(1, 30)))));
|
||||
VERSIONS.push_back(Ref<Version>(new Version(8, 24, 24, 22, 22,
|
||||
new ECBlocks(24, new ECB(1, 36)))));
|
||||
VERSIONS.push_back(Ref<Version>(new Version(9, 26, 26, 24, 24,
|
||||
new ECBlocks(28, new ECB(1, 44)))));
|
||||
VERSIONS.push_back(Ref<Version>(new Version(10, 32, 32, 14, 14,
|
||||
new ECBlocks(36, new ECB(1, 62)))));
|
||||
VERSIONS.push_back(Ref<Version>(new Version(11, 36, 36, 16, 16,
|
||||
new ECBlocks(42, new ECB(1, 86)))));
|
||||
VERSIONS.push_back(Ref<Version>(new Version(12, 40, 40, 18, 18,
|
||||
new ECBlocks(48, new ECB(1, 114)))));
|
||||
VERSIONS.push_back(Ref<Version>(new Version(13, 44, 44, 20, 20,
|
||||
new ECBlocks(56, new ECB(1, 144)))));
|
||||
VERSIONS.push_back(Ref<Version>(new Version(14, 48, 48, 22, 22,
|
||||
new ECBlocks(68, new ECB(1, 174)))));
|
||||
VERSIONS.push_back(Ref<Version>(new Version(15, 52, 52, 24, 24,
|
||||
new ECBlocks(42, new ECB(2, 102)))));
|
||||
VERSIONS.push_back(Ref<Version>(new Version(16, 64, 64, 14, 14,
|
||||
new ECBlocks(56, new ECB(2, 140)))));
|
||||
VERSIONS.push_back(Ref<Version>(new Version(17, 72, 72, 16, 16,
|
||||
new ECBlocks(36, new ECB(4, 92)))));
|
||||
VERSIONS.push_back(Ref<Version>(new Version(18, 80, 80, 18, 18,
|
||||
new ECBlocks(48, new ECB(4, 114)))));
|
||||
VERSIONS.push_back(Ref<Version>(new Version(19, 88, 88, 20, 20,
|
||||
new ECBlocks(56, new ECB(4, 144)))));
|
||||
VERSIONS.push_back(Ref<Version>(new Version(20, 96, 96, 22, 22,
|
||||
new ECBlocks(68, new ECB(4, 174)))));
|
||||
VERSIONS.push_back(Ref<Version>(new Version(21, 104, 104, 24, 24,
|
||||
new ECBlocks(56, new ECB(6, 136)))));
|
||||
VERSIONS.push_back(Ref<Version>(new Version(22, 120, 120, 18, 18,
|
||||
new ECBlocks(68, new ECB(6, 175)))));
|
||||
VERSIONS.push_back(Ref<Version>(new Version(23, 132, 132, 20, 20,
|
||||
new ECBlocks(62, new ECB(8, 163)))));
|
||||
VERSIONS.push_back(Ref<Version>(new Version(24, 144, 144, 22, 22,
|
||||
new ECBlocks(62, new ECB(8, 156), new ECB(2, 155)))));
|
||||
VERSIONS.push_back(Ref<Version>(new Version(25, 8, 18, 6, 16,
|
||||
new ECBlocks(7, new ECB(1, 5)))));
|
||||
VERSIONS.push_back(Ref<Version>(new Version(26, 8, 32, 6, 14,
|
||||
new ECBlocks(11, new ECB(1, 10)))));
|
||||
VERSIONS.push_back(Ref<Version>(new Version(27, 12, 26, 10, 24,
|
||||
new ECBlocks(14, new ECB(1, 16)))));
|
||||
VERSIONS.push_back(Ref<Version>(new Version(28, 12, 36, 10, 16,
|
||||
new ECBlocks(18, new ECB(1, 22)))));
|
||||
VERSIONS.push_back(Ref<Version>(new Version(29, 16, 36, 10, 16,
|
||||
new ECBlocks(24, new ECB(1, 32)))));
|
||||
VERSIONS.push_back(Ref<Version>(new Version(30, 16, 48, 14, 22,
|
||||
new ECBlocks(28, new ECB(1, 49)))));
|
||||
return VERSIONS.size();
|
||||
}
|
||||
}
|
||||
}
|
87
symbian/QQrDecoder/zxing/datamatrix/Version.h
Normal file
87
symbian/QQrDecoder/zxing/datamatrix/Version.h
Normal file
|
@ -0,0 +1,87 @@
|
|||
#ifndef __VERSION_H__
|
||||
#define __VERSION_H__
|
||||
|
||||
/*
|
||||
* Version.h
|
||||
* zxing
|
||||
*
|
||||
* Created by Luiz Silva on 09/02/2010.
|
||||
* Copyright 2010 ZXing authors All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <zxing/ReaderException.h>
|
||||
#include <zxing/common/BitMatrix.h>
|
||||
#include <zxing/common/Counted.h>
|
||||
#include <vector>
|
||||
|
||||
namespace zxing {
|
||||
namespace datamatrix {
|
||||
|
||||
class ECB {
|
||||
private:
|
||||
int count_;
|
||||
int dataCodewords_;
|
||||
public:
|
||||
ECB(int count, int dataCodewords);
|
||||
int getCount();
|
||||
int getDataCodewords();
|
||||
};
|
||||
|
||||
class ECBlocks {
|
||||
private:
|
||||
int ecCodewords_;
|
||||
std::vector<ECB*> ecBlocks_;
|
||||
public:
|
||||
ECBlocks(int ecCodewords, ECB *ecBlocks);
|
||||
ECBlocks(int ecCodewords, ECB *ecBlocks1, ECB *ecBlocks2);
|
||||
int getECCodewords();
|
||||
std::vector<ECB*>& getECBlocks();
|
||||
~ECBlocks();
|
||||
};
|
||||
|
||||
class Version : public Counted {
|
||||
private:
|
||||
int versionNumber_;
|
||||
int symbolSizeRows_;
|
||||
int symbolSizeColumns_;
|
||||
int dataRegionSizeRows_;
|
||||
int dataRegionSizeColumns_;
|
||||
ECBlocks* ecBlocks_;
|
||||
int totalCodewords_;
|
||||
Version(int versionNumber, int symbolSizeRows, int symbolSizeColumns, int dataRegionSizeRows,
|
||||
int dataRegionSizeColumns, ECBlocks *ecBlocks);
|
||||
|
||||
public:
|
||||
static std::vector<Ref<Version> > VERSIONS;
|
||||
|
||||
~Version();
|
||||
int getVersionNumber();
|
||||
int getSymbolSizeRows();
|
||||
int getSymbolSizeColumns();
|
||||
int getDataRegionSizeRows();
|
||||
int getDataRegionSizeColumns();
|
||||
int getTotalCodewords();
|
||||
ECBlocks* getECBlocks();
|
||||
static int buildVersions();
|
||||
Ref<Version> getVersionForDimensions(int numRows, int numColumns);
|
||||
|
||||
private:
|
||||
Version(const Version&);
|
||||
Version & operator=(const Version&);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif // __VERSION_H__
|
364
symbian/QQrDecoder/zxing/datamatrix/decoder/BitMatrixParser.cpp
Normal file
364
symbian/QQrDecoder/zxing/datamatrix/decoder/BitMatrixParser.cpp
Normal file
|
@ -0,0 +1,364 @@
|
|||
/*
|
||||
* BitMatrixParser.cpp
|
||||
* zxing
|
||||
*
|
||||
* Created by Luiz Silva on 09/02/2010.
|
||||
* Copyright 2010 ZXing authors All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <zxing/datamatrix/decoder/BitMatrixParser.h>
|
||||
#include <zxing/common/IllegalArgumentException.h>
|
||||
|
||||
namespace zxing {
|
||||
namespace datamatrix {
|
||||
|
||||
int BitMatrixParser::copyBit(size_t x, size_t y, int versionBits) {
|
||||
return bitMatrix_->get(x, y) ? (versionBits << 1) | 0x1 : versionBits << 1;
|
||||
}
|
||||
|
||||
BitMatrixParser::BitMatrixParser(Ref<BitMatrix> bitMatrix) : bitMatrix_(NULL),
|
||||
parsedVersion_(NULL),
|
||||
readBitMatrix_(NULL) {
|
||||
size_t dimension = bitMatrix->getDimension();
|
||||
if (dimension < 10 || dimension > 144 || (dimension & 0x01) != 0)
|
||||
throw ReaderException("Dimension must be even, > 10 < 144");
|
||||
|
||||
parsedVersion_ = readVersion(bitMatrix);
|
||||
bitMatrix_ = extractDataRegion(bitMatrix);
|
||||
// TODO(bbrown): Make this work for rectangular symbols
|
||||
readBitMatrix_ = new BitMatrix(bitMatrix_->getDimension());
|
||||
}
|
||||
|
||||
Ref<Version> BitMatrixParser::readVersion(Ref<BitMatrix> bitMatrix) {
|
||||
if (parsedVersion_ != 0) {
|
||||
return parsedVersion_;
|
||||
}
|
||||
|
||||
// TODO(bbrown): make this work for rectangular dimensions as well.
|
||||
int numRows = bitMatrix->getDimension();
|
||||
int numColumns = numRows;
|
||||
|
||||
Ref<Version> version = parsedVersion_->getVersionForDimensions(numRows, numColumns);
|
||||
if (version != 0) {
|
||||
return version;
|
||||
}
|
||||
throw ReaderException("Couldn't decode version");
|
||||
}
|
||||
|
||||
ArrayRef<unsigned char> BitMatrixParser::readCodewords() {
|
||||
ArrayRef<unsigned char> result(parsedVersion_->getTotalCodewords());
|
||||
int resultOffset = 0;
|
||||
int row = 4;
|
||||
int column = 0;
|
||||
|
||||
// TODO(bbrown): Data Matrix can be rectangular, assuming square for now
|
||||
int numRows = bitMatrix_->getDimension();
|
||||
int numColumns = numRows;
|
||||
|
||||
bool corner1Read = false;
|
||||
bool corner2Read = false;
|
||||
bool corner3Read = false;
|
||||
bool corner4Read = false;
|
||||
|
||||
// Read all of the codewords
|
||||
do {
|
||||
// Check the four corner cases
|
||||
if ((row == numRows) && (column == 0) && !corner1Read) {
|
||||
result[resultOffset++] = (unsigned char) readCorner1(numRows, numColumns);
|
||||
row -= 2;
|
||||
column +=2;
|
||||
corner1Read = true;
|
||||
} else if ((row == numRows-2) && (column == 0) && ((numColumns & 0x03) != 0) && !corner2Read) {
|
||||
result[resultOffset++] = (unsigned char) readCorner2(numRows, numColumns);
|
||||
row -= 2;
|
||||
column +=2;
|
||||
corner2Read = true;
|
||||
} else if ((row == numRows+4) && (column == 2) && ((numColumns & 0x07) == 0) && !corner3Read) {
|
||||
result[resultOffset++] = (unsigned char) readCorner3(numRows, numColumns);
|
||||
row -= 2;
|
||||
column +=2;
|
||||
corner3Read = true;
|
||||
} else if ((row == numRows-2) && (column == 0) && ((numColumns & 0x07) == 4) && !corner4Read) {
|
||||
result[resultOffset++] = (unsigned char) readCorner4(numRows, numColumns);
|
||||
row -= 2;
|
||||
column +=2;
|
||||
corner4Read = true;
|
||||
} else {
|
||||
// Sweep upward diagonally to the right
|
||||
do {
|
||||
if ((row < numRows) && (column >= 0) && !readBitMatrix_->get(column, row)) {
|
||||
result[resultOffset++] = (unsigned char) readUtah(row, column, numRows, numColumns);
|
||||
}
|
||||
row -= 2;
|
||||
column +=2;
|
||||
} while ((row >= 0) && (column < numColumns));
|
||||
row += 1;
|
||||
column +=3;
|
||||
|
||||
// Sweep downward diagonally to the left
|
||||
do {
|
||||
if ((row >= 0) && (column < numColumns) && !readBitMatrix_->get(column, row)) {
|
||||
result[resultOffset++] = (unsigned char) readUtah(row, column, numRows, numColumns);
|
||||
}
|
||||
row += 2;
|
||||
column -=2;
|
||||
} while ((row < numRows) && (column >= 0));
|
||||
row += 3;
|
||||
column +=1;
|
||||
}
|
||||
} while ((row < numRows) || (column < numColumns));
|
||||
|
||||
if (resultOffset != parsedVersion_->getTotalCodewords()) {
|
||||
throw ReaderException("Did not read all codewords");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool BitMatrixParser::readModule(int row, int column, int numRows, int numColumns) {
|
||||
// Adjust the row and column indices based on boundary wrapping
|
||||
if (row < 0) {
|
||||
row += numRows;
|
||||
column += 4 - ((numRows + 4) & 0x07);
|
||||
}
|
||||
if (column < 0) {
|
||||
column += numColumns;
|
||||
row += 4 - ((numColumns + 4) & 0x07);
|
||||
}
|
||||
readBitMatrix_->set(column, row);
|
||||
return bitMatrix_->get(column, row);
|
||||
}
|
||||
|
||||
int BitMatrixParser::readUtah(int row, int column, int numRows, int numColumns) {
|
||||
int currentByte = 0;
|
||||
if (readModule(row - 2, column - 2, numRows, numColumns)) {
|
||||
currentByte |= 1;
|
||||
}
|
||||
currentByte <<= 1;
|
||||
if (readModule(row - 2, column - 1, numRows, numColumns)) {
|
||||
currentByte |= 1;
|
||||
}
|
||||
currentByte <<= 1;
|
||||
if (readModule(row - 1, column - 2, numRows, numColumns)) {
|
||||
currentByte |= 1;
|
||||
}
|
||||
currentByte <<= 1;
|
||||
if (readModule(row - 1, column - 1, numRows, numColumns)) {
|
||||
currentByte |= 1;
|
||||
}
|
||||
currentByte <<= 1;
|
||||
if (readModule(row - 1, column, numRows, numColumns)) {
|
||||
currentByte |= 1;
|
||||
}
|
||||
currentByte <<= 1;
|
||||
if (readModule(row, column - 2, numRows, numColumns)) {
|
||||
currentByte |= 1;
|
||||
}
|
||||
currentByte <<= 1;
|
||||
if (readModule(row, column - 1, numRows, numColumns)) {
|
||||
currentByte |= 1;
|
||||
}
|
||||
currentByte <<= 1;
|
||||
if (readModule(row, column, numRows, numColumns)) {
|
||||
currentByte |= 1;
|
||||
}
|
||||
return currentByte;
|
||||
}
|
||||
|
||||
int BitMatrixParser::readCorner1(int numRows, int numColumns) {
|
||||
int currentByte = 0;
|
||||
if (readModule(numRows - 1, 0, numRows, numColumns)) {
|
||||
currentByte |= 1;
|
||||
}
|
||||
currentByte <<= 1;
|
||||
if (readModule(numRows - 1, 1, numRows, numColumns)) {
|
||||
currentByte |= 1;
|
||||
}
|
||||
currentByte <<= 1;
|
||||
if (readModule(numRows - 1, 2, numRows, numColumns)) {
|
||||
currentByte |= 1;
|
||||
}
|
||||
currentByte <<= 1;
|
||||
if (readModule(0, numColumns - 2, numRows, numColumns)) {
|
||||
currentByte |= 1;
|
||||
}
|
||||
currentByte <<= 1;
|
||||
if (readModule(0, numColumns - 1, numRows, numColumns)) {
|
||||
currentByte |= 1;
|
||||
}
|
||||
currentByte <<= 1;
|
||||
if (readModule(1, numColumns - 1, numRows, numColumns)) {
|
||||
currentByte |= 1;
|
||||
}
|
||||
currentByte <<= 1;
|
||||
if (readModule(2, numColumns - 1, numRows, numColumns)) {
|
||||
currentByte |= 1;
|
||||
}
|
||||
currentByte <<= 1;
|
||||
if (readModule(3, numColumns - 1, numRows, numColumns)) {
|
||||
currentByte |= 1;
|
||||
}
|
||||
return currentByte;
|
||||
}
|
||||
|
||||
int BitMatrixParser::readCorner2(int numRows, int numColumns) {
|
||||
int currentByte = 0;
|
||||
if (readModule(numRows - 3, 0, numRows, numColumns)) {
|
||||
currentByte |= 1;
|
||||
}
|
||||
currentByte <<= 1;
|
||||
if (readModule(numRows - 2, 0, numRows, numColumns)) {
|
||||
currentByte |= 1;
|
||||
}
|
||||
currentByte <<= 1;
|
||||
if (readModule(numRows - 1, 0, numRows, numColumns)) {
|
||||
currentByte |= 1;
|
||||
}
|
||||
currentByte <<= 1;
|
||||
if (readModule(0, numColumns - 4, numRows, numColumns)) {
|
||||
currentByte |= 1;
|
||||
}
|
||||
currentByte <<= 1;
|
||||
if (readModule(0, numColumns - 3, numRows, numColumns)) {
|
||||
currentByte |= 1;
|
||||
}
|
||||
currentByte <<= 1;
|
||||
if (readModule(0, numColumns - 2, numRows, numColumns)) {
|
||||
currentByte |= 1;
|
||||
}
|
||||
currentByte <<= 1;
|
||||
if (readModule(0, numColumns - 1, numRows, numColumns)) {
|
||||
currentByte |= 1;
|
||||
}
|
||||
currentByte <<= 1;
|
||||
if (readModule(1, numColumns - 1, numRows, numColumns)) {
|
||||
currentByte |= 1;
|
||||
}
|
||||
return currentByte;
|
||||
}
|
||||
|
||||
int BitMatrixParser::readCorner3(int numRows, int numColumns) {
|
||||
int currentByte = 0;
|
||||
if (readModule(numRows - 1, 0, numRows, numColumns)) {
|
||||
currentByte |= 1;
|
||||
}
|
||||
currentByte <<= 1;
|
||||
if (readModule(numRows - 1, numColumns - 1, numRows, numColumns)) {
|
||||
currentByte |= 1;
|
||||
}
|
||||
currentByte <<= 1;
|
||||
if (readModule(0, numColumns - 3, numRows, numColumns)) {
|
||||
currentByte |= 1;
|
||||
}
|
||||
currentByte <<= 1;
|
||||
if (readModule(0, numColumns - 2, numRows, numColumns)) {
|
||||
currentByte |= 1;
|
||||
}
|
||||
currentByte <<= 1;
|
||||
if (readModule(0, numColumns - 1, numRows, numColumns)) {
|
||||
currentByte |= 1;
|
||||
}
|
||||
currentByte <<= 1;
|
||||
if (readModule(1, numColumns - 3, numRows, numColumns)) {
|
||||
currentByte |= 1;
|
||||
}
|
||||
currentByte <<= 1;
|
||||
if (readModule(1, numColumns - 2, numRows, numColumns)) {
|
||||
currentByte |= 1;
|
||||
}
|
||||
currentByte <<= 1;
|
||||
if (readModule(1, numColumns - 1, numRows, numColumns)) {
|
||||
currentByte |= 1;
|
||||
}
|
||||
return currentByte;
|
||||
}
|
||||
|
||||
int BitMatrixParser::readCorner4(int numRows, int numColumns) {
|
||||
int currentByte = 0;
|
||||
if (readModule(numRows - 3, 0, numRows, numColumns)) {
|
||||
currentByte |= 1;
|
||||
}
|
||||
currentByte <<= 1;
|
||||
if (readModule(numRows - 2, 0, numRows, numColumns)) {
|
||||
currentByte |= 1;
|
||||
}
|
||||
currentByte <<= 1;
|
||||
if (readModule(numRows - 1, 0, numRows, numColumns)) {
|
||||
currentByte |= 1;
|
||||
}
|
||||
currentByte <<= 1;
|
||||
if (readModule(0, numColumns - 2, numRows, numColumns)) {
|
||||
currentByte |= 1;
|
||||
}
|
||||
currentByte <<= 1;
|
||||
if (readModule(0, numColumns - 1, numRows, numColumns)) {
|
||||
currentByte |= 1;
|
||||
}
|
||||
currentByte <<= 1;
|
||||
if (readModule(1, numColumns - 1, numRows, numColumns)) {
|
||||
currentByte |= 1;
|
||||
}
|
||||
currentByte <<= 1;
|
||||
if (readModule(2, numColumns - 1, numRows, numColumns)) {
|
||||
currentByte |= 1;
|
||||
}
|
||||
currentByte <<= 1;
|
||||
if (readModule(3, numColumns - 1, numRows, numColumns)) {
|
||||
currentByte |= 1;
|
||||
}
|
||||
return currentByte;
|
||||
}
|
||||
|
||||
Ref<BitMatrix> BitMatrixParser::extractDataRegion(Ref<BitMatrix> bitMatrix) {
|
||||
int symbolSizeRows = parsedVersion_->getSymbolSizeRows();
|
||||
int symbolSizeColumns = parsedVersion_->getSymbolSizeColumns();
|
||||
|
||||
// TODO(bbrown): Make this work with rectangular codes
|
||||
if ((int)bitMatrix->getDimension() != symbolSizeRows) {
|
||||
throw IllegalArgumentException("Dimension of bitMarix must match the version size");
|
||||
}
|
||||
|
||||
int dataRegionSizeRows = parsedVersion_->getDataRegionSizeRows();
|
||||
int dataRegionSizeColumns = parsedVersion_->getDataRegionSizeColumns();
|
||||
|
||||
int numDataRegionsRow = symbolSizeRows / dataRegionSizeRows;
|
||||
int numDataRegionsColumn = symbolSizeColumns / dataRegionSizeColumns;
|
||||
|
||||
int sizeDataRegionRow = numDataRegionsRow * dataRegionSizeRows;
|
||||
//int sizeDataRegionColumn = numDataRegionsColumn * dataRegionSizeColumns;
|
||||
|
||||
// TODO(bbrown): Make this work with rectangular codes
|
||||
Ref<BitMatrix> bitMatrixWithoutAlignment(new BitMatrix(sizeDataRegionRow));
|
||||
for (int dataRegionRow = 0; dataRegionRow < numDataRegionsRow; ++dataRegionRow) {
|
||||
int dataRegionRowOffset = dataRegionRow * dataRegionSizeRows;
|
||||
for (int dataRegionColumn = 0; dataRegionColumn < numDataRegionsColumn; ++dataRegionColumn) {
|
||||
int dataRegionColumnOffset = dataRegionColumn * dataRegionSizeColumns;
|
||||
for (int i = 0; i < dataRegionSizeRows; ++i) {
|
||||
int readRowOffset = dataRegionRow * (dataRegionSizeRows + 2) + 1 + i;
|
||||
int writeRowOffset = dataRegionRowOffset + i;
|
||||
for (int j = 0; j < dataRegionSizeColumns; ++j) {
|
||||
int readColumnOffset = dataRegionColumn * (dataRegionSizeColumns + 2) + 1 + j;
|
||||
if (bitMatrix->get(readColumnOffset, readRowOffset)) {
|
||||
int writeColumnOffset = dataRegionColumnOffset + j;
|
||||
bitMatrixWithoutAlignment->set(writeColumnOffset, writeRowOffset);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return bitMatrixWithoutAlignment;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
#ifndef __BIT_MATRIX_PARSER_DM_H__
|
||||
#define __BIT_MATRIX_PARSER_DM_H__
|
||||
|
||||
/*
|
||||
* BitMatrixParser.h
|
||||
* zxing
|
||||
*
|
||||
* Created by Luiz Silva on 09/02/2010.
|
||||
* Copyright 2010 ZXing authors All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <zxing/ReaderException.h>
|
||||
#include <zxing/common/BitMatrix.h>
|
||||
#include <zxing/common/Counted.h>
|
||||
#include <zxing/common/Array.h>
|
||||
#include <zxing/datamatrix/Version.h>
|
||||
|
||||
namespace zxing {
|
||||
namespace datamatrix {
|
||||
|
||||
class BitMatrixParser : public Counted {
|
||||
private:
|
||||
Ref<BitMatrix> bitMatrix_;
|
||||
Ref<Version> parsedVersion_;
|
||||
Ref<BitMatrix> readBitMatrix_;
|
||||
|
||||
int copyBit(size_t x, size_t y, int versionBits);
|
||||
|
||||
public:
|
||||
BitMatrixParser(Ref<BitMatrix> bitMatrix);
|
||||
Ref<Version> readVersion(Ref<BitMatrix> bitMatrix);
|
||||
ArrayRef<unsigned char> readCodewords();
|
||||
bool readModule(int row, int column, int numRows, int numColumns);
|
||||
|
||||
private:
|
||||
int readUtah(int row, int column, int numRows, int numColumns);
|
||||
int readCorner1(int numRows, int numColumns);
|
||||
int readCorner2(int numRows, int numColumns);
|
||||
int readCorner3(int numRows, int numColumns);
|
||||
int readCorner4(int numRows, int numColumns);
|
||||
Ref<BitMatrix> extractDataRegion(Ref<BitMatrix> bitMatrix);
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif // __BIT_MATRIX_PARSER_DM_H__
|
113
symbian/QQrDecoder/zxing/datamatrix/decoder/DataBlock.cpp
Normal file
113
symbian/QQrDecoder/zxing/datamatrix/decoder/DataBlock.cpp
Normal file
|
@ -0,0 +1,113 @@
|
|||
/*
|
||||
* DataBlock.cpp
|
||||
* zxing
|
||||
*
|
||||
* Created by Luiz Silva on 09/02/2010.
|
||||
* Copyright 2010 ZXing authors All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <zxing/datamatrix/decoder/DataBlock.h>
|
||||
#include <zxing/common/IllegalArgumentException.h>
|
||||
|
||||
namespace zxing {
|
||||
namespace datamatrix {
|
||||
|
||||
using namespace std;
|
||||
|
||||
DataBlock::DataBlock(int numDataCodewords, ArrayRef<unsigned char> codewords) :
|
||||
numDataCodewords_(numDataCodewords), codewords_(codewords) {
|
||||
}
|
||||
|
||||
int DataBlock::getNumDataCodewords() {
|
||||
return numDataCodewords_;
|
||||
}
|
||||
|
||||
ArrayRef<unsigned char> DataBlock::getCodewords() {
|
||||
return codewords_;
|
||||
}
|
||||
|
||||
std::vector<Ref<DataBlock> > DataBlock::getDataBlocks(ArrayRef<unsigned char> rawCodewords, Version *version) {
|
||||
// Figure out the number and size of data blocks used by this version and
|
||||
// error correction level
|
||||
ECBlocks* ecBlocks = version->getECBlocks();
|
||||
|
||||
// First count the total number of data blocks
|
||||
int totalBlocks = 0;
|
||||
vector<ECB*> ecBlockArray = ecBlocks->getECBlocks();
|
||||
for (size_t i = 0; i < ecBlockArray.size(); i++) {
|
||||
totalBlocks += ecBlockArray[i]->getCount();
|
||||
}
|
||||
|
||||
// Now establish DataBlocks of the appropriate size and number of data codewords
|
||||
std::vector<Ref<DataBlock> > result(totalBlocks);
|
||||
int numResultBlocks = 0;
|
||||
for (size_t j = 0; j < ecBlockArray.size(); j++) {
|
||||
ECB *ecBlock = ecBlockArray[j];
|
||||
for (int i = 0; i < ecBlock->getCount(); i++) {
|
||||
int numDataCodewords = ecBlock->getDataCodewords();
|
||||
int numBlockCodewords = ecBlocks->getECCodewords() + numDataCodewords;
|
||||
ArrayRef<unsigned char> buffer(numBlockCodewords);
|
||||
Ref<DataBlock> blockRef(new DataBlock(numDataCodewords, buffer));
|
||||
result[numResultBlocks++] = blockRef;
|
||||
}
|
||||
}
|
||||
|
||||
// All blocks have the same amount of data, except that the last n
|
||||
// (where n may be 0) have 1 more byte. Figure out where these start.
|
||||
int shorterBlocksTotalCodewords = result[0]->codewords_.size();
|
||||
int longerBlocksStartAt = result.size() - 1;
|
||||
while (longerBlocksStartAt >= 0) {
|
||||
int numCodewords = result[longerBlocksStartAt]->codewords_.size();
|
||||
if (numCodewords == shorterBlocksTotalCodewords) {
|
||||
break;
|
||||
}
|
||||
if (numCodewords != shorterBlocksTotalCodewords + 1) {
|
||||
throw IllegalArgumentException("Data block sizes differ by more than 1");
|
||||
}
|
||||
longerBlocksStartAt--;
|
||||
}
|
||||
longerBlocksStartAt++;
|
||||
|
||||
int shorterBlocksNumDataCodewords = shorterBlocksTotalCodewords - ecBlocks->getECCodewords();
|
||||
// The last elements of result may be 1 element longer;
|
||||
// first fill out as many elements as all of them have
|
||||
int rawCodewordsOffset = 0;
|
||||
for (int i = 0; i < shorterBlocksNumDataCodewords; i++) {
|
||||
for (int j = 0; j < numResultBlocks; j++) {
|
||||
result[j]->codewords_[i] = rawCodewords[rawCodewordsOffset++];
|
||||
}
|
||||
}
|
||||
// Fill out the last data block in the longer ones
|
||||
for (int j = longerBlocksStartAt; j < numResultBlocks; j++) {
|
||||
result[j]->codewords_[shorterBlocksNumDataCodewords] = rawCodewords[rawCodewordsOffset++];
|
||||
}
|
||||
// Now add in error correction blocks
|
||||
int max = result[0]->codewords_.size();
|
||||
for (int i = shorterBlocksNumDataCodewords; i < max; i++) {
|
||||
for (int j = 0; j < numResultBlocks; j++) {
|
||||
int iOffset = j < longerBlocksStartAt ? i : i + 1;
|
||||
result[j]->codewords_[iOffset] = rawCodewords[rawCodewordsOffset++];
|
||||
}
|
||||
}
|
||||
|
||||
if ((size_t)rawCodewordsOffset != rawCodewords.size()) {
|
||||
throw IllegalArgumentException("rawCodewordsOffset != rawCodewords.length");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
49
symbian/QQrDecoder/zxing/datamatrix/decoder/DataBlock.h
Normal file
49
symbian/QQrDecoder/zxing/datamatrix/decoder/DataBlock.h
Normal file
|
@ -0,0 +1,49 @@
|
|||
#ifndef __DATA_BLOCK_DM_H__
|
||||
#define __DATA_BLOCK_DM_H__
|
||||
|
||||
/*
|
||||
* DataBlock.h
|
||||
* zxing
|
||||
*
|
||||
* Created by Luiz Silva on 09/02/2010.
|
||||
* Copyright 2010 ZXing authors All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <vector>
|
||||
#include <zxing/common/Counted.h>
|
||||
#include <zxing/common/Array.h>
|
||||
#include <zxing/datamatrix/Version.h>
|
||||
|
||||
namespace zxing {
|
||||
namespace datamatrix {
|
||||
|
||||
class DataBlock : public Counted {
|
||||
private:
|
||||
int numDataCodewords_;
|
||||
ArrayRef<unsigned char> codewords_;
|
||||
|
||||
DataBlock(int numDataCodewords, ArrayRef<unsigned char> codewords);
|
||||
|
||||
public:
|
||||
static std::vector<Ref<DataBlock> > getDataBlocks(ArrayRef<unsigned char> rawCodewords, Version *version);
|
||||
|
||||
int getNumDataCodewords();
|
||||
ArrayRef<unsigned char> getCodewords();
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif // __DATA_BLOCK_DM_H__
|
|
@ -0,0 +1,404 @@
|
|||
/*
|
||||
* DecodedBitStreamParser.cpp
|
||||
* zxing
|
||||
*
|
||||
* Created by Luiz Silva on 09/02/2010.
|
||||
* Copyright 2010 ZXing authors All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <zxing/ReaderException.h>
|
||||
#include <zxing/datamatrix/decoder/DecodedBitStreamParser.h>
|
||||
#include <iostream>
|
||||
|
||||
namespace zxing {
|
||||
namespace datamatrix {
|
||||
|
||||
using namespace std;
|
||||
|
||||
const char DecodedBitStreamParser::C40_BASIC_SET_CHARS[] = {
|
||||
'*', '*', '*', ' ', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
|
||||
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
|
||||
'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'
|
||||
};
|
||||
|
||||
const char DecodedBitStreamParser::C40_SHIFT2_SET_CHARS[] = {
|
||||
'!', '"', '#', '$', '%', '&', '\'', '(', ')', '*', '+', ',', '-', '.',
|
||||
'/', ':', ';', '<', '=', '>', '?', '@', '[', '\\', ']', '^', '_'
|
||||
};
|
||||
|
||||
const char DecodedBitStreamParser::TEXT_BASIC_SET_CHARS[] = {
|
||||
'*', '*', '*', ' ', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
|
||||
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
|
||||
'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'
|
||||
};
|
||||
|
||||
const char DecodedBitStreamParser::TEXT_SHIFT3_SET_CHARS[] = {
|
||||
'\'', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
|
||||
'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '{', '|', '}', '~', (char) 127
|
||||
};
|
||||
|
||||
std::string DecodedBitStreamParser::decode(ArrayRef<unsigned char> bytes) {
|
||||
Ref<BitSource> bits(new BitSource(bytes));
|
||||
ostringstream result;
|
||||
ostringstream resultTrailer;
|
||||
// bool trailer = false;
|
||||
int mode = ASCII_ENCODE;
|
||||
do {
|
||||
if (mode == ASCII_ENCODE) {
|
||||
mode = decodeAsciiSegment(bits, result, resultTrailer);
|
||||
} else {
|
||||
switch (mode) {
|
||||
case C40_ENCODE:
|
||||
decodeC40Segment(bits, result);
|
||||
break;
|
||||
case TEXT_ENCODE:
|
||||
decodeTextSegment(bits, result);
|
||||
break;
|
||||
case ANSIX12_ENCODE:
|
||||
decodeAnsiX12Segment(bits, result);
|
||||
break;
|
||||
case EDIFACT_ENCODE:
|
||||
decodeEdifactSegment(bits, result);
|
||||
break;
|
||||
case BASE256_ENCODE:
|
||||
decodeBase256Segment(bits, result);
|
||||
break;
|
||||
default:
|
||||
throw ReaderException("Unsupported mode indicator");
|
||||
}
|
||||
mode = ASCII_ENCODE;
|
||||
}
|
||||
} while (mode != PAD_ENCODE && bits->available() > 0);
|
||||
/* if (trailer) {
|
||||
result << resultTrailer;
|
||||
}
|
||||
*/
|
||||
return result.str();
|
||||
}
|
||||
|
||||
int DecodedBitStreamParser::decodeAsciiSegment(Ref<BitSource> bits, ostringstream & result,
|
||||
ostringstream & resultTrailer) {
|
||||
bool upperShift = false;
|
||||
do {
|
||||
int oneByte = bits->readBits(8);
|
||||
if (oneByte == 0) {
|
||||
throw ReaderException("Not enough bits to decode");
|
||||
} else if (oneByte <= 128) { // ASCII data (ASCII value + 1)
|
||||
oneByte = upperShift ? (oneByte + 128) : oneByte;
|
||||
upperShift = false;
|
||||
result << (char) (oneByte - 1);
|
||||
return ASCII_ENCODE;
|
||||
} else if (oneByte == 129) { // Pad
|
||||
return PAD_ENCODE;
|
||||
} else if (oneByte <= 229) { // 2-digit data 00-99 (Numeric Value + 130)
|
||||
int value = oneByte - 130;
|
||||
if (value < 10) { // padd with '0' for single digit values
|
||||
result << '0';
|
||||
}
|
||||
result << value;
|
||||
} else if (oneByte == 230) { // Latch to C40 encodation
|
||||
return C40_ENCODE;
|
||||
} else if (oneByte == 231) { // Latch to Base 256 encodation
|
||||
return BASE256_ENCODE;
|
||||
} else if (oneByte == 232) { // FNC1
|
||||
//throw ReaderException.getInstance();
|
||||
// Ignore this symbol for now
|
||||
} else if (oneByte == 233) { // Structured Append
|
||||
//throw ReaderException.getInstance();
|
||||
// Ignore this symbol for now
|
||||
} else if (oneByte == 234) { // Reader Programming
|
||||
//throw ReaderException.getInstance();
|
||||
// Ignore this symbol for now
|
||||
} else if (oneByte == 235) { // Upper Shift (shift to Extended ASCII)
|
||||
upperShift = true;
|
||||
} else if (oneByte == 236) { // 05 Macro
|
||||
/* trailer = false;
|
||||
result << "[)>\u001E05\u001D";
|
||||
resultTrailer << "\u001E\u0004";
|
||||
// Ignore this symbol for now
|
||||
*/ } else if (oneByte == 237) { // 06 Macro
|
||||
/* trailer = false;
|
||||
result << "[)>\u001E06\u001D";
|
||||
resultTrailer << "\u001E\u0004";
|
||||
// Ignore this symbol for now
|
||||
*/ } else if (oneByte == 238) { // Latch to ANSI X12 encodation
|
||||
return ANSIX12_ENCODE;
|
||||
} else if (oneByte == 239) { // Latch to Text encodation
|
||||
return TEXT_ENCODE;
|
||||
} else if (oneByte == 240) { // Latch to EDIFACT encodation
|
||||
return EDIFACT_ENCODE;
|
||||
} else if (oneByte == 241) { // ECI Character
|
||||
// TODO(bbrown): I think we need to support ECI
|
||||
//throw ReaderException.getInstance();
|
||||
// Ignore this symbol for now
|
||||
} else if (oneByte >= 242) { // Not to be used in ASCII encodation
|
||||
throw ReaderException("Not to be used in ASCII encodation");
|
||||
}
|
||||
} while (bits->available() > 0);
|
||||
return ASCII_ENCODE;
|
||||
}
|
||||
|
||||
void DecodedBitStreamParser::decodeC40Segment(Ref<BitSource> bits, ostringstream & result) {
|
||||
// Three C40 values are encoded in a 16-bit value as
|
||||
// (1600 * C1) + (40 * C2) + C3 + 1
|
||||
// TODO(bbrown): The Upper Shift with C40 doesn't work in the 4 value scenario all the time
|
||||
bool upperShift = false;
|
||||
|
||||
int* cValues = new int[3];
|
||||
do {
|
||||
// If there is only one byte left then it will be encoded as ASCII
|
||||
if (bits->available() == 8) {
|
||||
return;
|
||||
}
|
||||
int firstByte = bits->readBits(8);
|
||||
if (firstByte == 254) { // Unlatch codeword
|
||||
return;
|
||||
}
|
||||
|
||||
parseTwoBytes(firstByte, bits->readBits(8), cValues);
|
||||
|
||||
int shift = 0;
|
||||
for (int i = 0; i < 3; i++) {
|
||||
int cValue = cValues[i];
|
||||
switch (shift) {
|
||||
case 0:
|
||||
if (cValue < 3) {
|
||||
shift = cValue + 1;
|
||||
} else {
|
||||
if (upperShift) {
|
||||
result << (char) (C40_BASIC_SET_CHARS[cValue] + 128);
|
||||
upperShift = false;
|
||||
} else {
|
||||
result << C40_BASIC_SET_CHARS[cValue];
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
if (upperShift) {
|
||||
result << cValue + 128;
|
||||
upperShift = false;
|
||||
} else {
|
||||
result << cValue;
|
||||
}
|
||||
shift = 0;
|
||||
break;
|
||||
case 2:
|
||||
if (cValue < 27) {
|
||||
if (upperShift) {
|
||||
result << (char) (C40_SHIFT2_SET_CHARS[cValue] + 128);
|
||||
upperShift = false;
|
||||
} else {
|
||||
result << C40_SHIFT2_SET_CHARS[cValue];
|
||||
}
|
||||
} else if (cValue == 27) { // FNC1
|
||||
throw ReaderException("FNC1");
|
||||
} else if (cValue == 30) { // Upper Shift
|
||||
upperShift = true;
|
||||
} else {
|
||||
throw ReaderException("Upper Shift");
|
||||
}
|
||||
shift = 0;
|
||||
break;
|
||||
case 3:
|
||||
if (upperShift) {
|
||||
result << (char) (cValue + 224);
|
||||
upperShift = false;
|
||||
} else {
|
||||
result << (char) (cValue + 96);
|
||||
}
|
||||
shift = 0;
|
||||
break;
|
||||
default:
|
||||
throw ReaderException("");
|
||||
}
|
||||
}
|
||||
} while (bits->available() > 0);
|
||||
}
|
||||
|
||||
void DecodedBitStreamParser::decodeTextSegment(Ref<BitSource> bits, ostringstream & result) {
|
||||
// Three Text values are encoded in a 16-bit value as
|
||||
// (1600 * C1) + (40 * C2) + C3 + 1
|
||||
// TODO(bbrown): The Upper Shift with Text doesn't work in the 4 value scenario all the time
|
||||
bool upperShift = false;
|
||||
|
||||
int* cValues = new int[3];
|
||||
do {
|
||||
// If there is only one byte left then it will be encoded as ASCII
|
||||
if (bits->available() == 8) {
|
||||
return;
|
||||
}
|
||||
int firstByte = bits->readBits(8);
|
||||
if (firstByte == 254) { // Unlatch codeword
|
||||
return;
|
||||
}
|
||||
|
||||
parseTwoBytes(firstByte, bits->readBits(8), cValues);
|
||||
|
||||
int shift = 0;
|
||||
for (int i = 0; i < 3; i++) {
|
||||
int cValue = cValues[i];
|
||||
switch (shift) {
|
||||
case 0:
|
||||
if (cValue < 3) {
|
||||
shift = cValue + 1;
|
||||
} else {
|
||||
if (upperShift) {
|
||||
result << (char) (TEXT_BASIC_SET_CHARS[cValue] + 128);
|
||||
upperShift = false;
|
||||
} else {
|
||||
result << (TEXT_BASIC_SET_CHARS[cValue]);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
if (upperShift) {
|
||||
result << (char) (cValue + 128);
|
||||
upperShift = false;
|
||||
} else {
|
||||
result << (cValue);
|
||||
}
|
||||
shift = 0;
|
||||
break;
|
||||
case 2:
|
||||
// Shift 2 for Text is the same encoding as C40
|
||||
if (cValue < 27) {
|
||||
if (upperShift) {
|
||||
result << (char) (C40_SHIFT2_SET_CHARS[cValue] + 128);
|
||||
upperShift = false;
|
||||
} else {
|
||||
result << (C40_SHIFT2_SET_CHARS[cValue]);
|
||||
}
|
||||
} else if (cValue == 27) { // FNC1
|
||||
throw ReaderException("FNC1");
|
||||
} else if (cValue == 30) { // Upper Shift
|
||||
upperShift = true;
|
||||
} else {
|
||||
throw ReaderException("Upper Shift");
|
||||
}
|
||||
shift = 0;
|
||||
break;
|
||||
case 3:
|
||||
if (upperShift) {
|
||||
result << (char) (TEXT_SHIFT3_SET_CHARS[cValue] + 128);
|
||||
upperShift = false;
|
||||
} else {
|
||||
result << (TEXT_SHIFT3_SET_CHARS[cValue]);
|
||||
}
|
||||
shift = 0;
|
||||
break;
|
||||
default:
|
||||
throw ReaderException("");
|
||||
}
|
||||
}
|
||||
} while (bits->available() > 0);
|
||||
}
|
||||
|
||||
void DecodedBitStreamParser::decodeAnsiX12Segment(Ref<BitSource> bits, ostringstream & result) {
|
||||
// Three ANSI X12 values are encoded in a 16-bit value as
|
||||
// (1600 * C1) + (40 * C2) + C3 + 1
|
||||
|
||||
int* cValues = new int[3];
|
||||
do {
|
||||
// If there is only one byte left then it will be encoded as ASCII
|
||||
if (bits->available() == 8) {
|
||||
return;
|
||||
}
|
||||
int firstByte = bits->readBits(8);
|
||||
if (firstByte == 254) { // Unlatch codeword
|
||||
return;
|
||||
}
|
||||
|
||||
parseTwoBytes(firstByte, bits->readBits(8), cValues);
|
||||
|
||||
for (int i = 0; i < 3; i++) {
|
||||
int cValue = cValues[i];
|
||||
if (cValue == 0) { // X12 segment terminator <CR>
|
||||
result << '\r';
|
||||
} else if (cValue == 1) { // X12 segment separator *
|
||||
result << '*';
|
||||
} else if (cValue == 2) { // X12 sub-element separator >
|
||||
result << '>';
|
||||
} else if (cValue == 3) { // space
|
||||
result << ' ';
|
||||
} else if (cValue < 14) { // 0 - 9
|
||||
result << (char) (cValue + 44);
|
||||
} else if (cValue < 40) { // A - Z
|
||||
result << (char) (cValue + 51);
|
||||
} else {
|
||||
throw ReaderException("");
|
||||
}
|
||||
}
|
||||
} while (bits->available() > 0);
|
||||
}
|
||||
|
||||
void DecodedBitStreamParser::parseTwoBytes(int firstByte, int secondByte, int*& result) {
|
||||
int fullBitValue = (firstByte << 8) + secondByte - 1;
|
||||
int temp = fullBitValue / 1600;
|
||||
result[0] = temp;
|
||||
fullBitValue -= temp * 1600;
|
||||
temp = fullBitValue / 40;
|
||||
result[1] = temp;
|
||||
result[2] = fullBitValue - temp * 40;
|
||||
}
|
||||
|
||||
void DecodedBitStreamParser::decodeEdifactSegment(Ref<BitSource> bits, ostringstream & result) {
|
||||
bool unlatch = false;
|
||||
do {
|
||||
// If there is only two or less bytes left then it will be encoded as ASCII
|
||||
if (bits->available() <= 16) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
int edifactValue = bits->readBits(6);
|
||||
|
||||
// Check for the unlatch character
|
||||
if (edifactValue == 0x2B67) { // 011111
|
||||
unlatch = true;
|
||||
// If we encounter the unlatch code then continue reading because the Codeword triple
|
||||
// is padded with 0's
|
||||
}
|
||||
|
||||
if (!unlatch) {
|
||||
if ((edifactValue & 32) == 0) { // no 1 in the leading (6th) bit
|
||||
edifactValue |= 64; // Add a leading 01 to the 6 bit binary value
|
||||
}
|
||||
result << (edifactValue);
|
||||
}
|
||||
}
|
||||
} while (!unlatch && bits->available() > 0);
|
||||
}
|
||||
|
||||
void DecodedBitStreamParser::decodeBase256Segment(Ref<BitSource> bits, ostringstream & result){//, vector<unsigned char> byteSegments)
|
||||
// Figure out how long the Base 256 Segment is.
|
||||
int d1 = bits->readBits(8);
|
||||
int count;
|
||||
if (d1 == 0) { // Read the remainder of the symbol
|
||||
count = bits->available() / 8;
|
||||
} else if (d1 < 250) {
|
||||
count = d1;
|
||||
} else {
|
||||
count = 250 * (d1 - 249) + bits->readBits(8);
|
||||
}
|
||||
unsigned char* bytes = new unsigned char[count];
|
||||
for (int i = 0; i < count; i++) {
|
||||
bytes[i] = unrandomize255State(bits->readBits(8), i);
|
||||
}
|
||||
//byteSegments.push_back(bytes);
|
||||
result << bytes;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,103 @@
|
|||
#ifndef __DECODED_BIT_STREAM_PARSER_DM_H__
|
||||
#define __DECODED_BIT_STREAM_PARSER_DM_H__
|
||||
|
||||
/*
|
||||
* DecodedBitStreamParser.h
|
||||
* zxing
|
||||
*
|
||||
* Created by Luiz Silva on 09/02/2010.
|
||||
* Copyright 2010 ZXing authors All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <zxing/common/BitSource.h>
|
||||
#include <zxing/common/Counted.h>
|
||||
#include <zxing/common/Array.h>
|
||||
|
||||
|
||||
namespace zxing {
|
||||
namespace datamatrix {
|
||||
|
||||
class DecodedBitStreamParser {
|
||||
private:
|
||||
static const int PAD_ENCODE = 0; // Not really an encoding
|
||||
static const int ASCII_ENCODE = 1;
|
||||
static const int C40_ENCODE = 2;
|
||||
static const int TEXT_ENCODE = 3;
|
||||
static const int ANSIX12_ENCODE = 4;
|
||||
static const int EDIFACT_ENCODE = 5;
|
||||
static const int BASE256_ENCODE = 6;
|
||||
|
||||
/**
|
||||
* See ISO 16022:2006, Annex C Table C.1
|
||||
* The C40 Basic Character Set (*'s used for placeholders for the shift values)
|
||||
*/
|
||||
static const char C40_BASIC_SET_CHARS[];
|
||||
|
||||
static const char C40_SHIFT2_SET_CHARS[];
|
||||
/**
|
||||
* See ISO 16022:2006, Annex C Table C.2
|
||||
* The Text Basic Character Set (*'s used for placeholders for the shift values)
|
||||
*/
|
||||
static const char TEXT_BASIC_SET_CHARS[];
|
||||
|
||||
static const char TEXT_SHIFT3_SET_CHARS[];
|
||||
/**
|
||||
* See ISO 16022:2006, 5.2.3 and Annex C, Table C.2
|
||||
*/
|
||||
int decodeAsciiSegment(Ref<BitSource> bits, std::ostringstream &result, std::ostringstream &resultTrailer);
|
||||
/**
|
||||
* See ISO 16022:2006, 5.2.5 and Annex C, Table C.1
|
||||
*/
|
||||
void decodeC40Segment(Ref<BitSource> bits, std::ostringstream &result);
|
||||
/**
|
||||
* See ISO 16022:2006, 5.2.6 and Annex C, Table C.2
|
||||
*/
|
||||
void decodeTextSegment(Ref<BitSource> bits, std::ostringstream &result);
|
||||
/**
|
||||
* See ISO 16022:2006, 5.2.7
|
||||
*/
|
||||
void decodeAnsiX12Segment(Ref<BitSource> bits, std::ostringstream &result);
|
||||
/**
|
||||
* See ISO 16022:2006, 5.2.8 and Annex C Table C.3
|
||||
*/
|
||||
void decodeEdifactSegment(Ref<BitSource> bits, std::ostringstream &result);
|
||||
/**
|
||||
* See ISO 16022:2006, 5.2.9 and Annex B, B.2
|
||||
*/
|
||||
void decodeBase256Segment(Ref<BitSource> bits, std::ostringstream &result);//,std::vector<unsigned char> byteSegments);
|
||||
|
||||
void parseTwoBytes(int firstByte, int secondByte, int*& result);
|
||||
/**
|
||||
* See ISO 16022:2006, Annex B, B.2
|
||||
*/
|
||||
unsigned char unrandomize255State(int randomizedBase256Codeword,
|
||||
int base256CodewordPosition) {
|
||||
int pseudoRandomNumber = ((149 * base256CodewordPosition) % 255) + 1;
|
||||
int tempVariable = randomizedBase256Codeword - pseudoRandomNumber;
|
||||
return (unsigned char) (tempVariable >= 0 ? tempVariable : (tempVariable + 256));
|
||||
};
|
||||
void append(std::ostream &ost, const unsigned char *bufIn, size_t nIn, const char *src);
|
||||
|
||||
public:
|
||||
DecodedBitStreamParser() { };
|
||||
std::string decode(ArrayRef<unsigned char> bytes);
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif // __DECODED_BIT_STREAM_PARSER_DM_H__
|
96
symbian/QQrDecoder/zxing/datamatrix/decoder/Decoder.cpp
Normal file
96
symbian/QQrDecoder/zxing/datamatrix/decoder/Decoder.cpp
Normal file
|
@ -0,0 +1,96 @@
|
|||
/*
|
||||
* Decoder.cpp
|
||||
* zxing
|
||||
*
|
||||
* Created by Luiz Silva on 09/02/2010.
|
||||
* Copyright 2010 ZXing authors All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <zxing/datamatrix/decoder/Decoder.h>
|
||||
#include <zxing/datamatrix/decoder/BitMatrixParser.h>
|
||||
#include <zxing/datamatrix/decoder/DataBlock.h>
|
||||
#include <zxing/datamatrix/decoder/DecodedBitStreamParser.h>
|
||||
#include <zxing/datamatrix/Version.h>
|
||||
#include <zxing/ReaderException.h>
|
||||
#include <zxing/common/reedsolomon/ReedSolomonException.h>
|
||||
|
||||
namespace zxing {
|
||||
namespace datamatrix {
|
||||
|
||||
using namespace std;
|
||||
|
||||
Decoder::Decoder() :
|
||||
rsDecoder_(GF256::DATA_MATRIX_FIELD) {
|
||||
}
|
||||
|
||||
|
||||
void Decoder::correctErrors(ArrayRef<unsigned char> codewordBytes, int numDataCodewords) {
|
||||
int numCodewords = codewordBytes->size();
|
||||
ArrayRef<int> codewordInts(numCodewords);
|
||||
for (int i = 0; i < numCodewords; i++) {
|
||||
codewordInts[i] = codewordBytes[i] & 0xff;
|
||||
}
|
||||
int numECCodewords = numCodewords - numDataCodewords;
|
||||
|
||||
try {
|
||||
rsDecoder_.decode(codewordInts, numECCodewords);
|
||||
} catch (ReedSolomonException ex) {
|
||||
ReaderException rex(ex.what());
|
||||
throw rex;
|
||||
}
|
||||
|
||||
for (int i = 0; i < numDataCodewords; i++) {
|
||||
codewordBytes[i] = (unsigned char)codewordInts[i];
|
||||
}
|
||||
}
|
||||
|
||||
Ref<DecoderResult> Decoder::decode(Ref<BitMatrix> bits) {
|
||||
// Construct a parser and read version, error-correction level
|
||||
BitMatrixParser parser(bits);
|
||||
Version *version = parser.readVersion(bits);
|
||||
|
||||
// Read codewords
|
||||
ArrayRef<unsigned char> codewords(parser.readCodewords());
|
||||
// Separate into data blocks
|
||||
std::vector<Ref<DataBlock> > dataBlocks = DataBlock::getDataBlocks(codewords, version);
|
||||
|
||||
// Count total number of data bytes
|
||||
int totalBytes = 0;
|
||||
for (unsigned int i = 0; i < dataBlocks.size(); i++) {
|
||||
totalBytes += dataBlocks[i]->getNumDataCodewords();
|
||||
}
|
||||
ArrayRef<unsigned char> resultBytes(totalBytes);
|
||||
int resultOffset = 0;
|
||||
|
||||
// Error-correct and copy data blocks together into a stream of bytes
|
||||
for (unsigned int j = 0; j < dataBlocks.size(); j++) {
|
||||
Ref<DataBlock> dataBlock(dataBlocks[j]);
|
||||
ArrayRef<unsigned char> codewordBytes = dataBlock->getCodewords();
|
||||
int numDataCodewords = dataBlock->getNumDataCodewords();
|
||||
correctErrors(codewordBytes, numDataCodewords);
|
||||
for (int i = 0; i < numDataCodewords; i++) {
|
||||
resultBytes[resultOffset++] = codewordBytes[i];
|
||||
}
|
||||
}
|
||||
|
||||
// Decode the contents of that stream of bytes
|
||||
DecodedBitStreamParser decodedBSParser;
|
||||
Ref<String> text(new String(decodedBSParser.decode(resultBytes)));
|
||||
|
||||
Ref<DecoderResult> result(new DecoderResult(resultBytes, text));
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
50
symbian/QQrDecoder/zxing/datamatrix/decoder/Decoder.h
Normal file
50
symbian/QQrDecoder/zxing/datamatrix/decoder/Decoder.h
Normal file
|
@ -0,0 +1,50 @@
|
|||
#ifndef __DECODER_DM_H__
|
||||
#define __DECODER_DM_H__
|
||||
|
||||
/*
|
||||
* Decoder.h
|
||||
* zxing
|
||||
*
|
||||
* Created by Luiz Silva on 09/02/2010.
|
||||
* Copyright 2010 ZXing authors All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <zxing/common/reedsolomon/ReedSolomonDecoder.h>
|
||||
#include <zxing/common/reedsolomon/GF256.h>
|
||||
#include <zxing/common/Counted.h>
|
||||
#include <zxing/common/Array.h>
|
||||
#include <zxing/common/DecoderResult.h>
|
||||
#include <zxing/common/BitMatrix.h>
|
||||
|
||||
|
||||
namespace zxing {
|
||||
namespace datamatrix {
|
||||
|
||||
class Decoder {
|
||||
private:
|
||||
ReedSolomonDecoder rsDecoder_;
|
||||
|
||||
void correctErrors(ArrayRef<unsigned char> bytes, int numDataCodewords);
|
||||
|
||||
public:
|
||||
Decoder();
|
||||
|
||||
Ref<DecoderResult> decode(Ref<BitMatrix> bits);
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif // __DECODER_DM_H__
|
54
symbian/QQrDecoder/zxing/datamatrix/detector/CornerPoint.cpp
Normal file
54
symbian/QQrDecoder/zxing/datamatrix/detector/CornerPoint.cpp
Normal file
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
* CornerPoint.cpp
|
||||
* zxing
|
||||
*
|
||||
* Created by Luiz Silva on 09/02/2010.
|
||||
* Copyright 2010 ZXing authors All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <zxing/datamatrix/detector/CornerPoint.h>
|
||||
|
||||
|
||||
namespace zxing {
|
||||
namespace datamatrix {
|
||||
|
||||
using namespace std;
|
||||
|
||||
CornerPoint::CornerPoint(float posX, float posY) :
|
||||
posX_(posX), posY_(posY), counter_(0) {
|
||||
}
|
||||
|
||||
float CornerPoint::getX() const {
|
||||
return posX_;
|
||||
}
|
||||
|
||||
float CornerPoint::getY() const {
|
||||
return posY_;
|
||||
}
|
||||
|
||||
int CornerPoint::getCount() const {
|
||||
return counter_;
|
||||
}
|
||||
|
||||
void CornerPoint::incrementCount() {
|
||||
counter_++;
|
||||
}
|
||||
|
||||
bool CornerPoint::equals(Ref<CornerPoint> other) const {
|
||||
return posX_ == other->getX() && posY_ == other->getY();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
47
symbian/QQrDecoder/zxing/datamatrix/detector/CornerPoint.h
Normal file
47
symbian/QQrDecoder/zxing/datamatrix/detector/CornerPoint.h
Normal file
|
@ -0,0 +1,47 @@
|
|||
#ifndef __CORNER_FINDER_H__
|
||||
#define __CORNER_FINDER_H__
|
||||
|
||||
/*
|
||||
* CornerPoint.h
|
||||
* zxing
|
||||
*
|
||||
* Created by Luiz Silva on 09/02/2010.
|
||||
* Copyright 2010 ZXing authors All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <zxing/ResultPoint.h>
|
||||
#include <cmath>
|
||||
|
||||
namespace zxing {
|
||||
namespace datamatrix {
|
||||
|
||||
class CornerPoint : public ResultPoint {
|
||||
private:
|
||||
float posX_;
|
||||
float posY_;
|
||||
int counter_;
|
||||
|
||||
public:
|
||||
CornerPoint(float posX, float posY);
|
||||
float getX() const;
|
||||
float getY() const;
|
||||
int getCount() const;
|
||||
void incrementCount();
|
||||
bool equals(Ref<CornerPoint> other) const;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif // __CORNER_FINDER_H__
|
315
symbian/QQrDecoder/zxing/datamatrix/detector/Detector.cpp
Normal file
315
symbian/QQrDecoder/zxing/datamatrix/detector/Detector.cpp
Normal file
|
@ -0,0 +1,315 @@
|
|||
/*
|
||||
* Detector.cpp
|
||||
* zxing
|
||||
*
|
||||
* Created by Luiz Silva on 09/02/2010.
|
||||
* Copyright 2010 ZXing authors All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <zxing/common/GridSampler.h>
|
||||
#include <zxing/datamatrix/detector/Detector.h>
|
||||
#include <cmath>
|
||||
#include <sstream>
|
||||
#include <cstdlib>
|
||||
|
||||
namespace zxing {
|
||||
namespace datamatrix {
|
||||
|
||||
using namespace std;
|
||||
|
||||
ResultPointsAndTransitions::ResultPointsAndTransitions() : to_(), from_(), transitions_(0) {
|
||||
Ref<CornerPoint> ref(new CornerPoint(0,0));
|
||||
from_ = ref;
|
||||
to_ = ref;
|
||||
}
|
||||
|
||||
ResultPointsAndTransitions::ResultPointsAndTransitions(Ref<CornerPoint> from, Ref<CornerPoint> to, int transitions) :
|
||||
to_(to), from_(from), transitions_(transitions) {
|
||||
}
|
||||
|
||||
Ref<CornerPoint> ResultPointsAndTransitions::getFrom() {
|
||||
return from_;
|
||||
}
|
||||
|
||||
Ref<CornerPoint> ResultPointsAndTransitions::getTo() {
|
||||
return to_;
|
||||
}
|
||||
|
||||
int ResultPointsAndTransitions::getTransitions() {
|
||||
return transitions_;
|
||||
}
|
||||
|
||||
Detector::Detector(Ref<BitMatrix> image) : image_(image) { }
|
||||
|
||||
Ref<BitMatrix> Detector::getImage() {
|
||||
return image_;
|
||||
}
|
||||
|
||||
Ref<DetectorResult> Detector::detect() {
|
||||
Ref<MonochromeRectangleDetector> rectangleDetector_(new MonochromeRectangleDetector(image_));
|
||||
std::vector<Ref<CornerPoint> > cornerPoints = rectangleDetector_->detect();
|
||||
Ref<CornerPoint> pointA = cornerPoints[0];
|
||||
Ref<CornerPoint> pointB = cornerPoints[1];
|
||||
Ref<CornerPoint> pointC = cornerPoints[2];
|
||||
Ref<CornerPoint> pointD = cornerPoints[3];
|
||||
|
||||
// Point A and D are across the diagonal from one another,
|
||||
// as are B and C. Figure out which are the solid black lines
|
||||
// by counting transitions
|
||||
std::vector<Ref<ResultPointsAndTransitions> > transitions(4);
|
||||
transitions[0].reset(transitionsBetween(pointA, pointB));
|
||||
transitions[1].reset(transitionsBetween(pointA, pointC));
|
||||
transitions[2].reset(transitionsBetween(pointB, pointD));
|
||||
transitions[3].reset(transitionsBetween(pointC, pointD));
|
||||
insertionSort(transitions);
|
||||
|
||||
// Sort by number of transitions. First two will be the two solid sides; last two
|
||||
// will be the two alternating black/white sides
|
||||
Ref<ResultPointsAndTransitions> lSideOne(transitions[0]);
|
||||
Ref<ResultPointsAndTransitions> lSideTwo(transitions[1]);
|
||||
|
||||
// Figure out which point is their intersection by tallying up the number of times we see the
|
||||
// endpoints in the four endpoints. One will show up twice.
|
||||
Ref<CornerPoint> maybeTopLeft;
|
||||
Ref<CornerPoint> bottomLeft;
|
||||
Ref<CornerPoint> maybeBottomRight;
|
||||
if (lSideOne->getFrom()->equals(lSideOne->getTo())) {
|
||||
bottomLeft = lSideOne->getFrom();
|
||||
maybeTopLeft = lSideTwo->getFrom();
|
||||
maybeBottomRight = lSideTwo->getTo();
|
||||
}
|
||||
else if (lSideOne->getFrom()->equals(lSideTwo->getFrom())) {
|
||||
bottomLeft = lSideOne->getFrom();
|
||||
maybeTopLeft = lSideOne->getTo();
|
||||
maybeBottomRight = lSideTwo->getTo();
|
||||
}
|
||||
else if (lSideOne->getFrom()->equals(lSideTwo->getTo())) {
|
||||
bottomLeft = lSideOne->getFrom();
|
||||
maybeTopLeft = lSideOne->getTo();
|
||||
maybeBottomRight = lSideTwo->getFrom();
|
||||
}
|
||||
else if (lSideOne->getTo()->equals(lSideTwo->getFrom())) {
|
||||
bottomLeft = lSideOne->getTo();
|
||||
maybeTopLeft = lSideOne->getFrom();
|
||||
maybeBottomRight = lSideTwo->getTo();
|
||||
}
|
||||
else if (lSideOne->getTo()->equals(lSideTwo->getTo())) {
|
||||
bottomLeft = lSideOne->getTo();
|
||||
maybeTopLeft = lSideOne->getFrom();
|
||||
maybeBottomRight = lSideTwo->getFrom();
|
||||
}
|
||||
else {
|
||||
bottomLeft = lSideTwo->getFrom();
|
||||
maybeTopLeft = lSideOne->getTo();
|
||||
maybeBottomRight = lSideOne->getFrom();
|
||||
}
|
||||
|
||||
// Bottom left is correct but top left and bottom right might be switched
|
||||
std::vector<Ref<CornerPoint> > corners(3);
|
||||
corners[0].reset(maybeTopLeft);
|
||||
corners[1].reset(bottomLeft);
|
||||
corners[2].reset(maybeBottomRight);
|
||||
// Use the dot product trick to sort them out
|
||||
orderBestPatterns(corners);
|
||||
|
||||
// Now we know which is which:
|
||||
Ref<CornerPoint> bottomRight(corners[0]);
|
||||
bottomLeft = corners[1];
|
||||
Ref<CornerPoint> topLeft(corners[2]);
|
||||
|
||||
// Which point didn't we find in relation to the "L" sides? that's the top right corner
|
||||
Ref<CornerPoint> topRight;
|
||||
if (!(pointA->equals(bottomRight) || pointA->equals(bottomLeft) || pointA->equals(topLeft))) {
|
||||
topRight = pointA;
|
||||
} else if (!(pointB->equals(bottomRight) || pointB->equals(bottomLeft) || pointB->equals(topLeft))) {
|
||||
topRight = pointB;
|
||||
} else if (!(pointC->equals(bottomRight) || pointC->equals(bottomLeft) || pointC->equals(topLeft))) {
|
||||
topRight = pointC;
|
||||
} else {
|
||||
topRight = pointD;
|
||||
}
|
||||
|
||||
float topRightX = (bottomRight->getX() - bottomLeft->getX()) + topLeft->getX();
|
||||
float topRightY = (bottomRight->getY() - bottomLeft->getY()) + topLeft->getY();
|
||||
Ref<CornerPoint> topR(new CornerPoint(topRightX,topRightY));
|
||||
|
||||
// Next determine the dimension by tracing along the top or right side and counting black/white
|
||||
// transitions. Since we start inside a black module, we should see a number of transitions
|
||||
// equal to 1 less than the code dimension. Well, actually 2 less, because we are going to
|
||||
// end on a black module:
|
||||
// The top right point is actually the corner of a module, which is one of the two black modules
|
||||
// adjacent to the white module at the top right. Tracing to that corner from either the top left
|
||||
// or bottom right should work here. The number of transitions could be higher than it should be
|
||||
// due to noise. So we try both and take the min.
|
||||
int dimension = min(transitionsBetween(topLeft, topRight)->getTransitions(),
|
||||
transitionsBetween(bottomRight, topRight)->getTransitions());
|
||||
if ((dimension & 0x01) == 1) {
|
||||
// it can't be odd, so, round... up?
|
||||
dimension++;
|
||||
}
|
||||
dimension += 2;
|
||||
|
||||
Ref<PerspectiveTransform> transform = createTransform(topLeft, topR, bottomLeft, bottomRight, dimension);
|
||||
Ref<BitMatrix> bits(sampleGrid(image_, dimension, transform));
|
||||
std::vector<Ref<ResultPoint> > points(4);
|
||||
points[0].reset(pointA);
|
||||
points[1].reset(pointB);
|
||||
points[2].reset(pointC);
|
||||
points[3].reset(pointD);
|
||||
Ref<DetectorResult> detectorResult(new DetectorResult(bits, points, transform));
|
||||
return detectorResult;
|
||||
}
|
||||
|
||||
Ref<ResultPointsAndTransitions> Detector::transitionsBetween(Ref<CornerPoint> from, Ref<CornerPoint> to) {
|
||||
// See QR Code Detector, sizeOfBlackWhiteBlackRun()
|
||||
int fromX = (int) from->getX();
|
||||
int fromY = (int) from->getY();
|
||||
int toX = (int) to->getX();
|
||||
int toY = (int) to->getY();
|
||||
bool steep = abs(toY - fromY) > abs(toX - fromX);
|
||||
if (steep) {
|
||||
int temp = fromX;
|
||||
fromX = fromY;
|
||||
fromY = temp;
|
||||
temp = toX;
|
||||
toX = toY;
|
||||
toY = temp;
|
||||
}
|
||||
|
||||
int dx = abs(toX - fromX);
|
||||
int dy = abs(toY - fromY);
|
||||
int error = -dx >> 1;
|
||||
int ystep = fromY < toY ? 1 : -1;
|
||||
int xstep = fromX < toX ? 1 : -1;
|
||||
int transitions = 0;
|
||||
bool inBlack = image_->get(steep ? fromY : fromX, steep ? fromX : fromY);
|
||||
for (int x = fromX, y = fromY; x != toX; x += xstep) {
|
||||
bool isBlack = image_->get(steep ? y : x, steep ? x : y);
|
||||
if (isBlack != inBlack) {
|
||||
transitions++;
|
||||
inBlack = isBlack;
|
||||
}
|
||||
error += dy;
|
||||
if (error > 0) {
|
||||
if (y == toY) {
|
||||
break;
|
||||
}
|
||||
y += ystep;
|
||||
error -= dx;
|
||||
}
|
||||
}
|
||||
Ref<ResultPointsAndTransitions> result(new ResultPointsAndTransitions(from, to, transitions));
|
||||
return result;
|
||||
}
|
||||
|
||||
Ref<PerspectiveTransform> Detector::createTransform(Ref<ResultPoint> topLeft, Ref<ResultPoint> topRight, Ref <
|
||||
ResultPoint > bottomLeft, Ref<ResultPoint> bottomRight, int dimension) {
|
||||
|
||||
Ref<PerspectiveTransform> transform(PerspectiveTransform::quadrilateralToQuadrilateral(
|
||||
0.0f,
|
||||
0.0f,
|
||||
dimension,
|
||||
0.0f,
|
||||
dimension,
|
||||
dimension,
|
||||
0.0f,
|
||||
dimension,
|
||||
topLeft->getX(),
|
||||
topLeft->getY(),
|
||||
topRight->getX(),
|
||||
topRight->getY(),
|
||||
bottomRight->getX(),
|
||||
bottomRight->getY(),
|
||||
bottomLeft->getX(),
|
||||
bottomLeft->getY()));
|
||||
return transform;
|
||||
}
|
||||
|
||||
Ref<BitMatrix> Detector::sampleGrid(Ref<BitMatrix> image, int dimension, Ref<PerspectiveTransform> transform) {
|
||||
GridSampler &sampler = GridSampler::getInstance();
|
||||
return sampler.sampleGrid(image, dimension, transform);
|
||||
}
|
||||
|
||||
void Detector::insertionSort(std::vector<Ref<ResultPointsAndTransitions> > &vector) {
|
||||
int max = vector.size();
|
||||
bool swapped = true;
|
||||
Ref<ResultPointsAndTransitions> value;
|
||||
Ref<ResultPointsAndTransitions> valueB;
|
||||
do {
|
||||
swapped = false;
|
||||
for (int i = 1; i < max; i++) {
|
||||
value = vector[i-1];
|
||||
if (compare(value, (valueB = vector[i])) > 0) {
|
||||
swapped = true;
|
||||
vector[i-1].reset(valueB);
|
||||
vector[i].reset(value);
|
||||
}
|
||||
}
|
||||
} while (swapped);
|
||||
}
|
||||
void Detector::orderBestPatterns(std::vector<Ref<CornerPoint> > &patterns) {
|
||||
// Find distances between pattern centers
|
||||
float zeroOneDistance = distance(patterns[0]->getX(), patterns[1]->getX(),patterns[0]->getY(), patterns[1]->getY());
|
||||
float oneTwoDistance = distance(patterns[1]->getX(), patterns[2]->getX(),patterns[1]->getY(), patterns[2]->getY());
|
||||
float zeroTwoDistance = distance(patterns[0]->getX(), patterns[2]->getX(),patterns[0]->getY(), patterns[2]->getY());
|
||||
|
||||
Ref<CornerPoint> pointA, pointB, pointC;
|
||||
// Assume one closest to other two is B; A and C will just be guesses at first
|
||||
if (oneTwoDistance >= zeroOneDistance && oneTwoDistance >= zeroTwoDistance) {
|
||||
pointB = patterns[0];
|
||||
pointA = patterns[1];
|
||||
pointC = patterns[2];
|
||||
} else if (zeroTwoDistance >= oneTwoDistance && zeroTwoDistance >= zeroOneDistance) {
|
||||
pointB = patterns[1];
|
||||
pointA = patterns[0];
|
||||
pointC = patterns[2];
|
||||
} else {
|
||||
pointB = patterns[2];
|
||||
pointA = patterns[0];
|
||||
pointC = patterns[1];
|
||||
}
|
||||
|
||||
// Use cross product to figure out whether A and C are correct or flipped.
|
||||
// This asks whether BC x BA has a positive z component, which is the arrangement
|
||||
// we want for A, B, C. If it's negative, then we've got it flipped around and
|
||||
// should swap A and C.
|
||||
if (crossProductZ(pointA, pointB, pointC) < 0.0f) {
|
||||
Ref<CornerPoint> temp = pointA;
|
||||
pointA = pointC;
|
||||
pointC = temp;
|
||||
}
|
||||
|
||||
patterns[0] = pointA;
|
||||
patterns[1] = pointB;
|
||||
patterns[2] = pointC;
|
||||
}
|
||||
|
||||
float Detector::distance(float x1, float x2, float y1, float y2) {
|
||||
float xDiff = x1 - x2;
|
||||
float yDiff = y1 - y2;
|
||||
return (float) sqrt((double) (xDiff * xDiff + yDiff * yDiff));
|
||||
}
|
||||
|
||||
int Detector::compare(Ref<ResultPointsAndTransitions> a, Ref<ResultPointsAndTransitions> b) {
|
||||
return a->getTransitions() - b->getTransitions();
|
||||
}
|
||||
|
||||
float Detector::crossProductZ(Ref<ResultPoint> pointA, Ref<ResultPoint> pointB, Ref<ResultPoint> pointC) {
|
||||
float bX = pointB->getX();
|
||||
float bY = pointB->getY();
|
||||
return ((pointC->getX() - bX) * (pointA->getY() - bY)) - ((pointC->getY() - bY) * (pointA->getX() - bX));
|
||||
}
|
||||
}
|
||||
}
|
79
symbian/QQrDecoder/zxing/datamatrix/detector/Detector.h
Normal file
79
symbian/QQrDecoder/zxing/datamatrix/detector/Detector.h
Normal file
|
@ -0,0 +1,79 @@
|
|||
#ifndef __DETECTOR_H__
|
||||
#define __DETECTOR_H__
|
||||
|
||||
/*
|
||||
* Detector.h
|
||||
* zxing
|
||||
*
|
||||
* Created by Luiz Silva on 09/02/2010.
|
||||
* Copyright 2010 ZXing authors All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
#include <zxing/common/Counted.h>
|
||||
#include <zxing/common/DetectorResult.h>
|
||||
#include <zxing/common/BitMatrix.h>
|
||||
#include <zxing/common/PerspectiveTransform.h>
|
||||
#include <zxing/datamatrix/detector/MonochromeRectangleDetector.h>
|
||||
|
||||
|
||||
namespace zxing {
|
||||
namespace datamatrix {
|
||||
|
||||
class ResultPointsAndTransitions : public Counted {
|
||||
private:
|
||||
Ref<CornerPoint> to_;
|
||||
Ref<CornerPoint> from_;
|
||||
int transitions_;
|
||||
|
||||
public:
|
||||
ResultPointsAndTransitions();
|
||||
ResultPointsAndTransitions(Ref<CornerPoint> from, Ref<CornerPoint> to, int transitions);
|
||||
Ref<CornerPoint> getFrom();
|
||||
Ref<CornerPoint> getTo();
|
||||
int getTransitions();
|
||||
};
|
||||
|
||||
class Detector : public Counted {
|
||||
private:
|
||||
Ref<BitMatrix> image_;
|
||||
|
||||
protected:
|
||||
Ref<BitMatrix> sampleGrid(Ref<BitMatrix> image, int dimension, Ref<PerspectiveTransform> transform);
|
||||
|
||||
void insertionSort(std::vector<Ref<ResultPointsAndTransitions> >& vector);
|
||||
|
||||
Ref<ResultPointsAndTransitions> transitionsBetween(Ref<CornerPoint> from, Ref<CornerPoint> to);
|
||||
int min(int a, int b) { return a > b ? b : a; };
|
||||
|
||||
public:
|
||||
Ref<BitMatrix> getImage();
|
||||
Detector(Ref<BitMatrix> image);
|
||||
|
||||
virtual Ref<PerspectiveTransform> createTransform(Ref<ResultPoint> topLeft, Ref<ResultPoint> topRight, Ref <
|
||||
ResultPoint > bottomLeft, Ref<ResultPoint> bottomRight, int dimension);
|
||||
|
||||
Ref<DetectorResult> detect();
|
||||
void orderBestPatterns(std::vector<Ref<CornerPoint> > &patterns);
|
||||
float distance(float x1, float x2, float y1, float y2);
|
||||
private:
|
||||
int compare(Ref<ResultPointsAndTransitions> a, Ref<ResultPointsAndTransitions> b);
|
||||
float crossProductZ(Ref<ResultPoint> pointA, Ref<ResultPoint> pointB, Ref<ResultPoint> pointC);
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif // __DETECTOR_H__
|
|
@ -0,0 +1,172 @@
|
|||
/*
|
||||
* MonochromeRectangleDetector.cpp
|
||||
* zxing
|
||||
*
|
||||
* Created by Luiz Silva on 09/02/2010.
|
||||
* Copyright 2010 ZXing authors All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <zxing/ReaderException.h>
|
||||
#include <zxing/datamatrix/detector/MonochromeRectangleDetector.h>
|
||||
#include <sstream>
|
||||
|
||||
namespace zxing {
|
||||
namespace datamatrix {
|
||||
|
||||
std::vector<Ref<CornerPoint> > MonochromeRectangleDetector::detect() {
|
||||
int height = image_->getHeight();
|
||||
int width = image_->getWidth();
|
||||
int halfHeight = height >> 1;
|
||||
int halfWidth = width >> 1;
|
||||
int deltaY = max(1, height / (MAX_MODULES << 3));
|
||||
int deltaX = max(1, width / (MAX_MODULES << 3));
|
||||
|
||||
int top = 0;
|
||||
int bottom = height;
|
||||
int left = 0;
|
||||
int right = width;
|
||||
Ref<CornerPoint> pointA(findCornerFromCenter(halfWidth, 0, left, right,
|
||||
halfHeight, -deltaY, top, bottom, halfWidth >> 1));
|
||||
top = (int) pointA->getY() - 1;
|
||||
Ref<CornerPoint> pointB(findCornerFromCenter(halfWidth, -deltaX, left, right,
|
||||
halfHeight, 0, top, bottom, halfHeight >> 1));
|
||||
left = (int) pointB->getX() - 1;
|
||||
Ref<CornerPoint> pointC(findCornerFromCenter(halfWidth, deltaX, left, right,
|
||||
halfHeight, 0, top, bottom, halfHeight >> 1));
|
||||
right = (int) pointC->getX() + 1;
|
||||
Ref<CornerPoint> pointD(findCornerFromCenter(halfWidth, 0, left, right,
|
||||
halfHeight, deltaY, top, bottom, halfWidth >> 1));
|
||||
bottom = (int) pointD->getY() + 1;
|
||||
|
||||
// Go try to find point A again with better information -- might have been off at first.
|
||||
pointA.reset(findCornerFromCenter(halfWidth, 0, left, right,
|
||||
halfHeight, -deltaY, top, bottom, halfWidth >> 2));
|
||||
std::vector<Ref<CornerPoint> > corners(4);
|
||||
|
||||
corners[0].reset(pointA);
|
||||
corners[1].reset(pointB);
|
||||
corners[2].reset(pointC);
|
||||
corners[3].reset(pointD);
|
||||
return corners;
|
||||
}
|
||||
|
||||
Ref<CornerPoint> MonochromeRectangleDetector::findCornerFromCenter(int centerX, int deltaX, int left, int right,
|
||||
int centerY, int deltaY, int top, int bottom, int maxWhiteRun) {
|
||||
Ref<TwoInts> lastRange(NULL);
|
||||
for (int y = centerY, x = centerX;
|
||||
y < bottom && y >= top && x < right && x >= left;
|
||||
y += deltaY, x += deltaX) {
|
||||
Ref<TwoInts> range(NULL);
|
||||
if (deltaX == 0) {
|
||||
// horizontal slices, up and down
|
||||
range = blackWhiteRange(y, maxWhiteRun, left, right, true);
|
||||
} else {
|
||||
// vertical slices, left and right
|
||||
range = blackWhiteRange(x, maxWhiteRun, top, bottom, false);
|
||||
}
|
||||
if (range == NULL) {
|
||||
if (lastRange == NULL) {
|
||||
throw ReaderException("Couldn't find corners (lastRange = NULL) ");
|
||||
} else {
|
||||
// lastRange was found
|
||||
if (deltaX == 0) {
|
||||
int lastY = y - deltaY;
|
||||
if (lastRange->start < centerX) {
|
||||
if (lastRange->end > centerX) {
|
||||
// straddle, choose one or the other based on direction
|
||||
Ref<CornerPoint> result(new CornerPoint(deltaY > 0 ? lastRange->start : lastRange->end, lastY));
|
||||
return result;
|
||||
}
|
||||
Ref<CornerPoint> result(new CornerPoint(lastRange->start, lastY));
|
||||
return result;
|
||||
} else {
|
||||
Ref<CornerPoint> result(new CornerPoint(lastRange->end, lastY));
|
||||
return result;
|
||||
}
|
||||
} else {
|
||||
int lastX = x - deltaX;
|
||||
if (lastRange->start < centerY) {
|
||||
if (lastRange->end > centerY) {
|
||||
Ref<CornerPoint> result(new CornerPoint(lastX, deltaX < 0 ? lastRange->start : lastRange->end));
|
||||
return result;
|
||||
}
|
||||
Ref<CornerPoint> result(new CornerPoint(lastX, lastRange->start));
|
||||
return result;
|
||||
} else {
|
||||
Ref<CornerPoint> result(new CornerPoint(lastX, lastRange->end));
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
lastRange = range;
|
||||
}
|
||||
throw ReaderException("Couldn't find corners");
|
||||
}
|
||||
|
||||
Ref<TwoInts> MonochromeRectangleDetector::blackWhiteRange(int fixedDimension, int maxWhiteRun, int minDim, int maxDim,
|
||||
bool horizontal) {
|
||||
|
||||
int center = (minDim + maxDim) >> 1;
|
||||
|
||||
// Scan left/up first
|
||||
int start = center;
|
||||
while (start >= minDim) {
|
||||
if (horizontal ? image_->get(start, fixedDimension) : image_->get(fixedDimension, start)) {
|
||||
start--;
|
||||
} else {
|
||||
int whiteRunStart = start;
|
||||
do {
|
||||
start--;
|
||||
} while (start >= minDim && !(horizontal ? image_->get(start, fixedDimension) :
|
||||
image_->get(fixedDimension, start)));
|
||||
int whiteRunSize = whiteRunStart - start;
|
||||
if (start < minDim || whiteRunSize > maxWhiteRun) {
|
||||
start = whiteRunStart;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
start++;
|
||||
|
||||
// Then try right/down
|
||||
int end = center;
|
||||
while (end < maxDim) {
|
||||
if (horizontal ? image_->get(end, fixedDimension) : image_->get(fixedDimension, end)) {
|
||||
end++;
|
||||
} else {
|
||||
int whiteRunStart = end;
|
||||
do {
|
||||
end++;
|
||||
} while (end < maxDim && !(horizontal ? image_->get(end, fixedDimension) :
|
||||
image_->get(fixedDimension, end)));
|
||||
int whiteRunSize = end - whiteRunStart;
|
||||
if (end >= maxDim || whiteRunSize > maxWhiteRun) {
|
||||
end = whiteRunStart;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
end--;
|
||||
Ref<TwoInts> result(NULL);
|
||||
if (end > start) {
|
||||
result = new TwoInts;
|
||||
result->start = start;
|
||||
result->end = end;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
#ifndef __MONOCHROMERECTANGLEDETECTOR_H__
|
||||
#define __MONOCHROMERECTANGLEDETECTOR_H__
|
||||
|
||||
/*
|
||||
* MonochromeRectangleDetector.h
|
||||
* zxing
|
||||
*
|
||||
* Created by Luiz Silva on 09/02/2010.
|
||||
* Copyright 2010 ZXing authors All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <vector>
|
||||
#include <zxing/ReaderException.h>
|
||||
#include <zxing/ResultPoint.h>
|
||||
#include <zxing/common/BitMatrix.h>
|
||||
#include <zxing/common/Counted.h>
|
||||
#include <zxing/datamatrix/detector/CornerPoint.h>
|
||||
|
||||
namespace zxing {
|
||||
namespace datamatrix {
|
||||
|
||||
struct TwoInts: public Counted {
|
||||
int start;
|
||||
int end;
|
||||
};
|
||||
|
||||
class MonochromeRectangleDetector : public Counted {
|
||||
private:
|
||||
static const int MAX_MODULES = 32;
|
||||
Ref<BitMatrix> image_;
|
||||
|
||||
public:
|
||||
MonochromeRectangleDetector(Ref<BitMatrix> image) : image_(image) { };
|
||||
|
||||
std::vector<Ref<CornerPoint> > detect();
|
||||
|
||||
private:
|
||||
Ref<CornerPoint> findCornerFromCenter(int centerX, int deltaX, int left, int right,
|
||||
int centerY, int deltaY, int top, int bottom, int maxWhiteRun);
|
||||
|
||||
Ref<TwoInts> blackWhiteRange(int fixedDimension, int maxWhiteRun, int minDim, int maxDim,
|
||||
bool horizontal);
|
||||
|
||||
int max(int a, float b) { return (float) a > b ? a : (int) b;};
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif // __MONOCHROMERECTANGLEDETECTOR_H__
|
|
@ -24,6 +24,7 @@
|
|||
#include <zxing/ReaderException.h>
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
#include <sstream>
|
||||
|
||||
namespace zxing {
|
||||
namespace oned {
|
||||
|
@ -166,10 +167,10 @@ namespace zxing {
|
|||
counters[counterPosition]++;
|
||||
} else {
|
||||
if (counterPosition == patternLength - 1) {
|
||||
int bestVariance = MAX_AVG_VARIANCE;
|
||||
unsigned int bestVariance = MAX_AVG_VARIANCE;
|
||||
int bestMatch = -1;
|
||||
for (int startCode = CODE_START_A; startCode <= CODE_START_C; startCode++) {
|
||||
int variance = patternMatchVariance(counters, sizeof(counters)/sizeof(int), CODE_PATTERNS[startCode], MAX_INDIVIDUAL_VARIANCE);
|
||||
unsigned int variance = patternMatchVariance(counters, sizeof(counters)/sizeof(int), CODE_PATTERNS[startCode], MAX_INDIVIDUAL_VARIANCE);
|
||||
if (variance < bestVariance) {
|
||||
bestVariance = variance;
|
||||
bestMatch = startCode;
|
||||
|
@ -204,7 +205,7 @@ namespace zxing {
|
|||
|
||||
int Code128Reader::decodeCode(Ref<BitArray> row, int counters[], int countersCount, int rowOffset){
|
||||
recordPattern(row, rowOffset, counters, countersCount);
|
||||
int bestVariance = MAX_AVG_VARIANCE; // worst variance we'll accept
|
||||
unsigned int bestVariance = MAX_AVG_VARIANCE; // worst variance we'll accept
|
||||
int bestMatch = -1;
|
||||
for (int d = 0; d < CODE_PATTERNS_LENGTH; d++) {
|
||||
int pattern[countersLength];
|
||||
|
@ -213,7 +214,7 @@ namespace zxing {
|
|||
pattern[ind] = CODE_PATTERNS[d][ind];
|
||||
}
|
||||
// memcpy(pattern, CODE_PATTERNS[d], countersLength);
|
||||
int variance = patternMatchVariance(counters, countersCount, pattern, MAX_INDIVIDUAL_VARIANCE);
|
||||
unsigned int variance = patternMatchVariance(counters, countersCount, pattern, MAX_INDIVIDUAL_VARIANCE);
|
||||
if (variance < bestVariance) {
|
||||
bestVariance = variance;
|
||||
bestMatch = d;
|
||||
|
@ -251,7 +252,7 @@ namespace zxing {
|
|||
bool isNextShifted = false;
|
||||
|
||||
std::string tmpResultString;
|
||||
|
||||
std::stringstream tmpResultSStr; // used if its Code 128C
|
||||
|
||||
int lastStart = startPatternInfo[0];
|
||||
int nextStart = startPatternInfo[1];
|
||||
|
@ -373,11 +374,11 @@ namespace zxing {
|
|||
}
|
||||
break;
|
||||
case CODE_CODE_C:
|
||||
// the code read in this case is the number encoded directly
|
||||
if (code < 100) {
|
||||
if (code < 10) {
|
||||
tmpResultString.append(1, '0');
|
||||
}
|
||||
tmpResultString.append(1, code);
|
||||
if (code < 10)
|
||||
tmpResultSStr << '0';
|
||||
tmpResultSStr << code;
|
||||
} else {
|
||||
if (code != CODE_STOP) {
|
||||
lastCharacterWasPrintable = false;
|
||||
|
@ -437,6 +438,9 @@ namespace zxing {
|
|||
throw ReaderException("");
|
||||
}
|
||||
|
||||
if (codeSet == CODE_CODE_C)
|
||||
tmpResultString.append(tmpResultSStr.str());
|
||||
|
||||
// Need to pull out the check digits from string
|
||||
int resultLength = tmpResultString.length();
|
||||
// Only bother if the result had at least one character, and if the checksum digit happened to
|
||||
|
|
|
@ -27,7 +27,7 @@ namespace zxing {
|
|||
class Code128Reader : public OneDReader {
|
||||
|
||||
private:
|
||||
static const int MAX_AVG_VARIANCE = (int) (PATTERN_MATCH_RESULT_SCALE_FACTOR * 0.25f);
|
||||
static const unsigned int MAX_AVG_VARIANCE = (unsigned int) (PATTERN_MATCH_RESULT_SCALE_FACTOR * 0.25f);
|
||||
static const int MAX_INDIVIDUAL_VARIANCE = (int) (PATTERN_MATCH_RESULT_SCALE_FACTOR * 0.7f);
|
||||
|
||||
static const int CODE_SHIFT = 98;
|
||||
|
|
|
@ -26,321 +26,333 @@
|
|||
#include <limits.h>
|
||||
|
||||
namespace zxing {
|
||||
namespace oned {
|
||||
|
||||
static const char* ALPHABET = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ-. *$/+%";
|
||||
|
||||
|
||||
/**
|
||||
* These represent the encodings of characters, as patterns of wide and narrow bars.
|
||||
* The 9 least-significant bits of each int correspond to the pattern of wide and narrow,
|
||||
* with 1s representing "wide" and 0s representing narrow.
|
||||
*/
|
||||
const int CHARACTER_ENCODINGS_LEN = 44;
|
||||
static int CHARACTER_ENCODINGS[CHARACTER_ENCODINGS_LEN] = {
|
||||
0x034, 0x121, 0x061, 0x160, 0x031, 0x130, 0x070, 0x025, 0x124, 0x064, // 0-9
|
||||
0x109, 0x049, 0x148, 0x019, 0x118, 0x058, 0x00D, 0x10C, 0x04C, 0x01C, // A-J
|
||||
0x103, 0x043, 0x142, 0x013, 0x112, 0x052, 0x007, 0x106, 0x046, 0x016, // K-T
|
||||
0x181, 0x0C1, 0x1C0, 0x091, 0x190, 0x0D0, 0x085, 0x184, 0x0C4, 0x094, // U-*
|
||||
0x0A8, 0x0A2, 0x08A, 0x02A // $-%
|
||||
};
|
||||
|
||||
static int ASTERISK_ENCODING = 0x094;
|
||||
static const char* ALPHABET_STRING = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ-. *$/+%";
|
||||
|
||||
|
||||
/**
|
||||
* Creates a reader that assumes all encoded data is data, and does not treat the final
|
||||
* character as a check digit. It will not decoded "extended Code 39" sequences.
|
||||
*/
|
||||
Code39Reader::Code39Reader() : alphabet_string(ALPHABET_STRING),
|
||||
usingCheckDigit(false),
|
||||
extendedMode(false) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a reader that can be configured to check the last character as a check digit.
|
||||
* It will not decoded "extended Code 39" sequences.
|
||||
*
|
||||
* @param usingCheckDigit if true, treat the last data character as a check digit, not
|
||||
* data, and verify that the checksum passes.
|
||||
*/
|
||||
Code39Reader::Code39Reader(bool usingCheckDigit_) : alphabet_string(ALPHABET_STRING),
|
||||
usingCheckDigit(usingCheckDigit_),
|
||||
extendedMode(false) {
|
||||
}
|
||||
|
||||
namespace oned {
|
||||
|
||||
static const char* ALPHABET = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ-. *$/+%";
|
||||
|
||||
|
||||
/**
|
||||
* These represent the encodings of characters, as patterns of wide and narrow
|
||||
* bars.
|
||||
* The 9 least-significant bits of each int correspond to the pattern of wide
|
||||
* and narrow, with 1s representing "wide" and 0s representing narrow.
|
||||
*/
|
||||
const int CHARACTER_ENCODINGS_LEN = 44;
|
||||
static int CHARACTER_ENCODINGS[CHARACTER_ENCODINGS_LEN] = {
|
||||
0x034, 0x121, 0x061, 0x160, 0x031, 0x130, 0x070, 0x025, 0x124, 0x064, // 0-9
|
||||
0x109, 0x049, 0x148, 0x019, 0x118, 0x058, 0x00D, 0x10C, 0x04C, 0x01C, // A-J
|
||||
0x103, 0x043, 0x142, 0x013, 0x112, 0x052, 0x007, 0x106, 0x046, 0x016, // K-T
|
||||
0x181, 0x0C1, 0x1C0, 0x091, 0x190, 0x0D0, 0x085, 0x184, 0x0C4, 0x094, // U-*
|
||||
0x0A8, 0x0A2, 0x08A, 0x02A // $-%
|
||||
};
|
||||
|
||||
static int ASTERISK_ENCODING = 0x094;
|
||||
static const char* ALPHABET_STRING =
|
||||
"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ-. *$/+%";
|
||||
|
||||
|
||||
/**
|
||||
* Creates a reader that assumes all encoded data is data, and does not treat
|
||||
* the final character as a check digit. It will not decoded "extended
|
||||
* Code 39" sequences.
|
||||
*/
|
||||
Code39Reader::Code39Reader() : alphabet_string(ALPHABET_STRING),
|
||||
usingCheckDigit(false),
|
||||
extendedMode(false) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a reader that can be configured to check the last character as a
|
||||
* check digit. It will not decoded "extended Code 39" sequences.
|
||||
*
|
||||
* @param usingCheckDigit if true, treat the last data character as a check
|
||||
* digit, not data, and verify that the checksum passes.
|
||||
*/
|
||||
Code39Reader::Code39Reader(bool usingCheckDigit_) :
|
||||
alphabet_string(ALPHABET_STRING),
|
||||
usingCheckDigit(usingCheckDigit_),
|
||||
extendedMode(false) {
|
||||
}
|
||||
|
||||
|
||||
|
||||
Ref<Result> Code39Reader::decodeRow(int rowNumber, Ref<BitArray> row){
|
||||
int* 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");
|
||||
}
|
||||
|
||||
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) {
|
||||
delete resultString;
|
||||
resultString = decodeExtended(tmpResultString);
|
||||
}
|
||||
|
||||
if (tmpResultString.length() == 0) {
|
||||
delete [] start;
|
||||
// Almost surely a false positive
|
||||
throw ReaderException("");
|
||||
}
|
||||
|
||||
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 width = row->getSize();
|
||||
int rowOffset = 0;
|
||||
while (rowOffset < width) {
|
||||
if (row->get(rowOffset)) {
|
||||
break;
|
||||
}
|
||||
rowOffset++;
|
||||
}
|
||||
|
||||
int counterPosition = 0;
|
||||
int countersLen = 9;
|
||||
int* counters = new int[countersLen];
|
||||
for (int i=0; i<countersLen; i++) {
|
||||
counters[i] = 0;
|
||||
}
|
||||
int patternStart = rowOffset;
|
||||
bool isWhite = false;
|
||||
int patternLength = countersLen;
|
||||
|
||||
for (int i = rowOffset; i < width; i++) {
|
||||
bool pixel = row->get(i);
|
||||
if (pixel ^ isWhite) {
|
||||
counters[counterPosition]++;
|
||||
} else {
|
||||
if (counterPosition == patternLength - 1) {
|
||||
if (toNarrowWidePattern(counters, countersLen) == ASTERISK_ENCODING) {
|
||||
// Look for whitespace before start pattern, >= 50% of width of
|
||||
// start pattern.
|
||||
long double longPatternOffset =
|
||||
fmaxl(0, patternStart - (i - patternStart) / 2);
|
||||
if (row->isRange(longPatternOffset, patternStart, false)) {
|
||||
int* resultValue = new int[2];
|
||||
resultValue[0] = patternStart;
|
||||
resultValue[1] = i;
|
||||
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;
|
||||
}
|
||||
}
|
||||
// IS begin
|
||||
delete [] counters;
|
||||
// IS end
|
||||
throw ReaderException("");
|
||||
}
|
||||
|
||||
// For efficiency, returns -1 on failure. Not throwing here saved as many as
|
||||
// 700 exceptions per image when using some of our blackbox images.
|
||||
int Code39Reader::toNarrowWidePattern(int counters[], int countersLen){
|
||||
int numCounters = countersLen;
|
||||
int maxNarrowCounter = 0;
|
||||
int wideCounters;
|
||||
do {
|
||||
int minCounter = INT_MAX;
|
||||
for (int i = 0; i < numCounters; i++) {
|
||||
int counter = counters[i];
|
||||
if (counter < minCounter && counter > maxNarrowCounter) {
|
||||
minCounter = counter;
|
||||
}
|
||||
}
|
||||
maxNarrowCounter = minCounter;
|
||||
wideCounters = 0;
|
||||
int totalWideCountersWidth = 0;
|
||||
int pattern = 0;
|
||||
for (int i = 0; i < numCounters; i++) {
|
||||
int counter = counters[i];
|
||||
if (counters[i] > maxNarrowCounter) {
|
||||
pattern |= 1 << (numCounters - 1 - i);
|
||||
wideCounters++;
|
||||
totalWideCountersWidth += counter;
|
||||
}
|
||||
}
|
||||
if (wideCounters == 3) {
|
||||
// Found 3 wide counters, but are they close enough in width?
|
||||
// We can perform a cheap, conservative check to see if any individual
|
||||
// counter is more than 1.5 times the average:
|
||||
for (int i = 0; i < numCounters && wideCounters > 0; i++) {
|
||||
int counter = counters[i];
|
||||
if (counters[i] > maxNarrowCounter) {
|
||||
wideCounters--;
|
||||
// totalWideCountersWidth = 3 * average, so this checks if
|
||||
// counter >= 3/2 * average.
|
||||
if ((counter << 1) >= totalWideCountersWidth) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return pattern;
|
||||
}
|
||||
} while (wideCounters > 3);
|
||||
return -1;
|
||||
}
|
||||
|
||||
char Code39Reader::patternToChar(int pattern){
|
||||
for (int i = 0; i < CHARACTER_ENCODINGS_LEN; i++) {
|
||||
if (CHARACTER_ENCODINGS[i] == pattern) {
|
||||
return ALPHABET[i];
|
||||
}
|
||||
}
|
||||
throw ReaderException("");
|
||||
}
|
||||
|
||||
Ref<String> Code39Reader::decodeExtended(std::string encoded){
|
||||
int length = encoded.length();
|
||||
std::string tmpDecoded;
|
||||
for (int i = 0; i < length; i++) {
|
||||
char c = encoded[i];
|
||||
if (c == '+' || c == '$' || c == '%' || c == '/') {
|
||||
char next = encoded[i + 1];
|
||||
char decodedChar = '\0';
|
||||
switch (c) {
|
||||
case '+':
|
||||
// +A to +Z map to a to z
|
||||
if (next >= 'A' && next <= 'Z') {
|
||||
decodedChar = (char) (next + 32);
|
||||
} else {
|
||||
throw ReaderException("");
|
||||
}
|
||||
break;
|
||||
case '$':
|
||||
// $A to $Z map to control codes SH to SB
|
||||
if (next >= 'A' && next <= 'Z') {
|
||||
decodedChar = (char) (next - 64);
|
||||
} else {
|
||||
throw ReaderException("");
|
||||
}
|
||||
break;
|
||||
case '%':
|
||||
// %A to %E map to control codes ESC to US
|
||||
if (next >= 'A' && next <= 'E') {
|
||||
decodedChar = (char) (next - 38);
|
||||
} else if (next >= 'F' && next <= 'W') {
|
||||
decodedChar = (char) (next - 11);
|
||||
} else {
|
||||
throw ReaderException("");
|
||||
}
|
||||
break;
|
||||
case '/':
|
||||
// /A to /O map to ! to , and /Z maps to :
|
||||
if (next >= 'A' && next <= 'O') {
|
||||
decodedChar = (char) (next - 32);
|
||||
} else if (next == 'Z') {
|
||||
decodedChar = ':';
|
||||
} else {
|
||||
throw ReaderException("");
|
||||
}
|
||||
break;
|
||||
}
|
||||
tmpDecoded.append(1, decodedChar);
|
||||
// bump up i again since we read two characters
|
||||
i++;
|
||||
} else {
|
||||
tmpDecoded.append(1, c);
|
||||
}
|
||||
}
|
||||
Ref<String> decoded(new String(tmpDecoded));
|
||||
return decoded;
|
||||
}
|
||||
} // namespace oned
|
||||
} // namespace zxing
|
||||
|
||||
|
||||
Ref<Result> Code39Reader::decodeRow(int rowNumber, Ref<BitArray> row){
|
||||
int* 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");
|
||||
}
|
||||
|
||||
if (usingCheckDigit) {
|
||||
int max = tmpResultString.length() - 1;
|
||||
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) {
|
||||
delete resultString;
|
||||
resultString = decodeExtended(tmpResultString);
|
||||
}
|
||||
|
||||
if (tmpResultString.length() == 0) {
|
||||
delete [] start;
|
||||
// Almost surely a false positive
|
||||
throw ReaderException("");
|
||||
}
|
||||
|
||||
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 width = row->getSize();
|
||||
int rowOffset = 0;
|
||||
while (rowOffset < width) {
|
||||
if (row->get(rowOffset)) {
|
||||
break;
|
||||
}
|
||||
rowOffset++;
|
||||
}
|
||||
|
||||
int counterPosition = 0;
|
||||
int countersLen = 9;
|
||||
int* counters = new int[countersLen];
|
||||
for (int i=0; i<countersLen; i++) {
|
||||
counters[i] = 0;
|
||||
}
|
||||
int patternStart = rowOffset;
|
||||
bool isWhite = false;
|
||||
int patternLength = countersLen;
|
||||
|
||||
for (int i = rowOffset; i < width; i++) {
|
||||
bool pixel = row->get(i);
|
||||
if (pixel ^ isWhite) {
|
||||
counters[counterPosition]++;
|
||||
} else {
|
||||
if (counterPosition == patternLength - 1) {
|
||||
if (toNarrowWidePattern(counters, countersLen) == ASTERISK_ENCODING) {
|
||||
// Look for whitespace before start pattern, >= 50% of width of start pattern
|
||||
if (row->isRange(fmaxl(0, patternStart - (i - patternStart) / 2), patternStart, false)) {
|
||||
int* resultValue = new int[2];
|
||||
resultValue[0] = patternStart;
|
||||
resultValue[1] = i;
|
||||
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;
|
||||
}
|
||||
}
|
||||
// IS begin
|
||||
delete [] counters;
|
||||
// IS end
|
||||
throw ReaderException("");
|
||||
}
|
||||
|
||||
// For efficiency, returns -1 on failure. Not throwing here saved as many as 700 exceptions
|
||||
// per image when using some of our blackbox images.
|
||||
int Code39Reader::toNarrowWidePattern(int counters[], int countersLen){
|
||||
int numCounters = countersLen;
|
||||
int maxNarrowCounter = 0;
|
||||
int wideCounters;
|
||||
do {
|
||||
int minCounter = INT_MAX;
|
||||
for (int i = 0; i < numCounters; i++) {
|
||||
int counter = counters[i];
|
||||
if (counter < minCounter && counter > maxNarrowCounter) {
|
||||
minCounter = counter;
|
||||
}
|
||||
}
|
||||
maxNarrowCounter = minCounter;
|
||||
wideCounters = 0;
|
||||
int totalWideCountersWidth = 0;
|
||||
int pattern = 0;
|
||||
for (int i = 0; i < numCounters; i++) {
|
||||
int counter = counters[i];
|
||||
if (counters[i] > maxNarrowCounter) {
|
||||
pattern |= 1 << (numCounters - 1 - i);
|
||||
wideCounters++;
|
||||
totalWideCountersWidth += counter;
|
||||
}
|
||||
}
|
||||
if (wideCounters == 3) {
|
||||
// Found 3 wide counters, but are they close enough in width?
|
||||
// We can perform a cheap, conservative check to see if any individual
|
||||
// counter is more than 1.5 times the average:
|
||||
for (int i = 0; i < numCounters && wideCounters > 0; i++) {
|
||||
int counter = counters[i];
|
||||
if (counters[i] > maxNarrowCounter) {
|
||||
wideCounters--;
|
||||
// totalWideCountersWidth = 3 * average, so this checks if counter >= 3/2 * average
|
||||
if ((counter << 1) >= totalWideCountersWidth) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return pattern;
|
||||
}
|
||||
} while (wideCounters > 3);
|
||||
return -1;
|
||||
}
|
||||
|
||||
char Code39Reader::patternToChar(int pattern){
|
||||
for (int i = 0; i < CHARACTER_ENCODINGS_LEN; i++) {
|
||||
if (CHARACTER_ENCODINGS[i] == pattern) {
|
||||
return ALPHABET[i];
|
||||
}
|
||||
}
|
||||
throw ReaderException("");
|
||||
}
|
||||
|
||||
Ref<String> Code39Reader::decodeExtended(std::string encoded){
|
||||
int length = encoded.length();
|
||||
std::string tmpDecoded;
|
||||
for (int i = 0; i < length; i++) {
|
||||
char c = encoded[i];
|
||||
if (c == '+' || c == '$' || c == '%' || c == '/') {
|
||||
char next = encoded[i + 1];
|
||||
char decodedChar = '\0';
|
||||
switch (c) {
|
||||
case '+':
|
||||
// +A to +Z map to a to z
|
||||
if (next >= 'A' && next <= 'Z') {
|
||||
decodedChar = (char) (next + 32);
|
||||
} else {
|
||||
throw ReaderException("");
|
||||
}
|
||||
break;
|
||||
case '$':
|
||||
// $A to $Z map to control codes SH to SB
|
||||
if (next >= 'A' && next <= 'Z') {
|
||||
decodedChar = (char) (next - 64);
|
||||
} else {
|
||||
throw ReaderException("");
|
||||
}
|
||||
break;
|
||||
case '%':
|
||||
// %A to %E map to control codes ESC to US
|
||||
if (next >= 'A' && next <= 'E') {
|
||||
decodedChar = (char) (next - 38);
|
||||
} else if (next >= 'F' && next <= 'W') {
|
||||
decodedChar = (char) (next - 11);
|
||||
} else {
|
||||
throw ReaderException("");
|
||||
}
|
||||
break;
|
||||
case '/':
|
||||
// /A to /O map to ! to , and /Z maps to :
|
||||
if (next >= 'A' && next <= 'O') {
|
||||
decodedChar = (char) (next - 32);
|
||||
} else if (next == 'Z') {
|
||||
decodedChar = ':';
|
||||
} else {
|
||||
throw ReaderException("");
|
||||
}
|
||||
break;
|
||||
}
|
||||
tmpDecoded.append(1, decodedChar);
|
||||
// bump up i again since we read two characters
|
||||
i++;
|
||||
} else {
|
||||
tmpDecoded.append(1, c);
|
||||
}
|
||||
}
|
||||
Ref<String> decoded(new String(tmpDecoded));
|
||||
return decoded;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -237,7 +237,7 @@ namespace zxing {
|
|||
* @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
|
||||
//#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--) {
|
||||
|
@ -335,7 +335,7 @@ namespace zxing {
|
|||
* @throws ReaderException if digit cannot be decoded
|
||||
*/
|
||||
int ITFReader::decodeDigit(int counters[], int countersLen){
|
||||
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 max = PATTERNS_LEN;
|
||||
for (int i = 0; i < max; i++) {
|
||||
|
@ -343,7 +343,7 @@ namespace zxing {
|
|||
for(int ind = 0; ind<countersLen; ind++){
|
||||
pattern[ind] = PATTERNS[i][ind];
|
||||
}
|
||||
int variance = patternMatchVariance(counters, countersLen, pattern, MAX_INDIVIDUAL_VARIANCE);
|
||||
unsigned int variance = patternMatchVariance(counters, countersLen, pattern, MAX_INDIVIDUAL_VARIANCE);
|
||||
if (variance < bestVariance) {
|
||||
bestVariance = variance;
|
||||
bestMatch = i;
|
||||
|
|
|
@ -27,7 +27,7 @@ namespace zxing {
|
|||
class ITFReader : public OneDReader {
|
||||
|
||||
private:
|
||||
static const int MAX_AVG_VARIANCE = (int) (PATTERN_MATCH_RESULT_SCALE_FACTOR * 0.42f);
|
||||
static const unsigned int MAX_AVG_VARIANCE = (unsigned int) (PATTERN_MATCH_RESULT_SCALE_FACTOR * 0.42f);
|
||||
static const int MAX_INDIVIDUAL_VARIANCE = (int) (PATTERN_MATCH_RESULT_SCALE_FACTOR * 0.8f);
|
||||
|
||||
// Stores the actual narrow line width of the image being decoded.
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
|
||||
#include "OneDReader.h"
|
||||
#include <zxing/ReaderException.h>
|
||||
#include <zxing/oned/OneDResultPoint.h>
|
||||
#include <math.h>
|
||||
#include <limits.h>
|
||||
|
||||
|
@ -93,6 +94,8 @@ namespace zxing {
|
|||
row = image->getBlackRow(rowNumber, row);
|
||||
}catch (ReaderException re) {
|
||||
continue;
|
||||
}catch (IllegalArgumentException re) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// While we have the image data in a BitArray, it's fairly cheap to reverse it in place to
|
||||
|
@ -109,9 +112,17 @@ namespace zxing {
|
|||
// // But it was upside down, so note that
|
||||
// result.putMetadata(ResultMetadataType.ORIENTATION, new Integer(180));
|
||||
// // And remember to flip the result points horizontally.
|
||||
// ResultPoint[] points = result.getResultPoints();
|
||||
// points[0] = new ResultPoint(width - points[0].getX() - 1, points[0].getY());
|
||||
// points[1] = new ResultPoint(width - points[1].getX() - 1, points[1].getY());
|
||||
std::vector<Ref<ResultPoint> > points(result->getResultPoints());
|
||||
if (points.size() == 2) {
|
||||
Ref<ResultPoint> pointZero(new OneDResultPoint(width - points[0]->getX() - 1, points[0]->getY()));
|
||||
points[0] = pointZero;
|
||||
|
||||
Ref<ResultPoint> pointOne(new OneDResultPoint(width - points[1]->getX() - 1, points[1]->getY()));
|
||||
points[1] = pointOne;
|
||||
|
||||
result.reset(new Result(result->getText(),result->getRawBytes(),points,result->getBarcodeFormat()));
|
||||
}
|
||||
|
||||
}
|
||||
return result;
|
||||
} catch (ReaderException re) {
|
||||
|
@ -119,13 +130,13 @@ namespace zxing {
|
|||
}
|
||||
}
|
||||
}
|
||||
throw ReaderException("");
|
||||
throw ReaderException("doDecode() failed");
|
||||
}
|
||||
|
||||
int OneDReader::patternMatchVariance(int counters[], int countersSize, const int pattern[], int maxIndividualVariance) {
|
||||
unsigned int OneDReader::patternMatchVariance(int counters[], int countersSize, const int pattern[], int maxIndividualVariance) {
|
||||
int numCounters = countersSize;
|
||||
int total = 0;
|
||||
int patternLength = 0;
|
||||
unsigned int total = 0;
|
||||
unsigned int patternLength = 0;
|
||||
for (int i = 0; i < numCounters; i++) {
|
||||
total += counters[i];
|
||||
patternLength += pattern[i];
|
||||
|
@ -138,10 +149,10 @@ namespace zxing {
|
|||
// We're going to fake floating-point math in integers. We just need to use more bits.
|
||||
// Scale up patternLength so that intermediate values below like scaledCounter will have
|
||||
// more "significant digits"
|
||||
int unitBarWidth = (total << INTEGER_MATH_SHIFT) / patternLength;
|
||||
unsigned int unitBarWidth = (total << INTEGER_MATH_SHIFT) / patternLength;
|
||||
maxIndividualVariance = (maxIndividualVariance * unitBarWidth) >> INTEGER_MATH_SHIFT;
|
||||
|
||||
int totalVariance = 0;
|
||||
unsigned int totalVariance = 0;
|
||||
for (int x = 0; x < numCounters; x++) {
|
||||
int counter = counters[x] << INTEGER_MATH_SHIFT;
|
||||
int scaledPattern = pattern[x] * unitBarWidth;
|
||||
|
|
|
@ -38,7 +38,7 @@ namespace zxing {
|
|||
virtual Ref<Result> decode(Ref<BinaryBitmap> image);
|
||||
virtual Ref<Result> decodeRow(int rowNumber, Ref<BitArray> row) = 0;
|
||||
|
||||
static int patternMatchVariance(int counters[], int countersSize, const int pattern[], int maxIndividualVariance);
|
||||
static unsigned int patternMatchVariance(int counters[], int countersSize, const int pattern[], int maxIndividualVariance);
|
||||
static void recordPattern(Ref<BitArray> row, int start, int counters[], int countersCount);
|
||||
virtual ~OneDReader();
|
||||
};
|
||||
|
|
|
@ -239,7 +239,7 @@ namespace zxing {
|
|||
// 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);
|
||||
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 max = 0;
|
||||
|
@ -252,7 +252,7 @@ namespace zxing {
|
|||
pattern[j] = L_PATTERNS[i][j];
|
||||
}
|
||||
|
||||
int variance = patternMatchVariance(counters, countersLen, pattern, MAX_INDIVIDUAL_VARIANCE);
|
||||
unsigned int variance = patternMatchVariance(counters, countersLen, pattern, MAX_INDIVIDUAL_VARIANCE);
|
||||
if (variance < bestVariance) {
|
||||
bestVariance = variance;
|
||||
bestMatch = i;
|
||||
|
@ -267,7 +267,7 @@ namespace zxing {
|
|||
pattern[j] = L_AND_G_PATTERNS[i][j];
|
||||
}
|
||||
|
||||
int variance = patternMatchVariance(counters, countersLen, pattern, MAX_INDIVIDUAL_VARIANCE);
|
||||
unsigned int variance = patternMatchVariance(counters, countersLen, pattern, MAX_INDIVIDUAL_VARIANCE);
|
||||
if (variance < bestVariance) {
|
||||
bestVariance = variance;
|
||||
bestMatch = i;
|
||||
|
|
|
@ -32,7 +32,7 @@ namespace zxing {
|
|||
class UPCEANReader : public OneDReader {
|
||||
|
||||
private:
|
||||
static const int MAX_AVG_VARIANCE = (int) (PATTERN_MATCH_RESULT_SCALE_FACTOR * 0.42f);
|
||||
static const unsigned int MAX_AVG_VARIANCE = (unsigned int) (PATTERN_MATCH_RESULT_SCALE_FACTOR * 0.42f);
|
||||
static const int MAX_INDIVIDUAL_VARIANCE = (int) (PATTERN_MATCH_RESULT_SCALE_FACTOR * 0.7f);
|
||||
|
||||
static int* findStartGuardPattern(Ref<BitArray> row); //throws ReaderException
|
||||
|
|
|
@ -4,8 +4,8 @@
|
|||
<cproject storage_type_id="org.eclipse.cdt.core.XmlProjectDescriptionStorage">
|
||||
<storageModule buildFromInf="true" buildingTestComps="true" cleanLevel="0" concurrentBuildJobs="4" defaultMMPChangedAction="2" extraSBSv2Args="" infBuildComponents="" infFileLocation="group\bld.inf" macrosFile="" makeEngineToUse="make" manageDependencies="true" moduleId="com.nokia.carbide.cdt.builder.carbideCPPBuilder" overrideMakeEngine="false" overrideWorkspaceSettings="false" promptForMMPChangedAction="false" useConcurrentBuilding="true" useDebugMode="false" useIncrementalBuilder="false" useKeepGoing="false" useMMPMacros="true"/>
|
||||
<storageModule moduleId="org.eclipse.cdt.core.settings">
|
||||
<cconfiguration id="Emulator Debug (WINSCW) [S60_3rd_FP2_SDK_v1.1]">
|
||||
<storageModule buildSystemId="com.nokia.carbide.cdt.builder.CarbideConfigurationDataProvider" id="Emulator Debug (WINSCW) [S60_3rd_FP2_SDK_v1.1]" moduleId="org.eclipse.cdt.core.settings" name="Emulator Debug (WINSCW) [S60_3rd_FP2_SDK_v1.1]">
|
||||
<cconfiguration id="Emulator Debug (WINSCW) [S60_5th_Edition_SDK_v1.0]">
|
||||
<storageModule buildSystemId="com.nokia.carbide.cdt.builder.CarbideConfigurationDataProvider" id="Emulator Debug (WINSCW) [S60_5th_Edition_SDK_v1.0]" moduleId="org.eclipse.cdt.core.settings" name="Emulator Debug (WINSCW) [S60_5th_Edition_SDK_v1.0]">
|
||||
<externalSettings/>
|
||||
<extensions>
|
||||
<extension id="org.eclipse.cdt.core.ELF" point="org.eclipse.cdt.core.BinaryParser"/>
|
||||
|
@ -21,18 +21,18 @@
|
|||
<extension id="com.nokia.carbide.cdt.builder.MakeDefErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
|
||||
</extensions>
|
||||
</storageModule>
|
||||
<storageModule moduleId="org.eclipse.cdt.core.language.mapping"/>
|
||||
<storageModule moduleId="org.eclipse.cdt.internal.ui.text.commentOwnerProjectMappings"/>
|
||||
<storageModule moduleId="CarbideConfigurationDataProvider">
|
||||
<ENV_VAR_DATA_ID/>
|
||||
<ARGUMENTS_DATA_ID ABLDFREEZEARGSSTORAGE="-r"/>
|
||||
<ROM_BUILDER_DATA_ID ROMBUILDWORKINGDIRECTORYSTORAGE="C:\Symbian\9.2\S60_3rd_FP2_SDK_v1.1\epoc32\rom\"/>
|
||||
<ROM_BUILDER_DATA_ID ROMBUILDWORKINGDIRECTORYSTORAGE="C:\"/>
|
||||
</storageModule>
|
||||
<storageModule filesCache="C:\Carbide\Testworkspace\ZXingBarcodeReader\group\bld.inf;C:\Carbide\Testworkspace\ZXingBarcodeReader\group\ZXingBarcodeReader.mmp;" includesCache="C:/Symbian/9.2/S60_3rd_FP2_SDK_v1.1/epoc32/include;C:/Symbian/9.2/S60_3rd_FP2_SDK_v1.1/epoc32/include/stdapis;C:/Symbian/9.2/S60_3rd_FP2_SDK_v1.1/epoc32/include/stdapis/sys;C:/Symbian/9.2/S60_3rd_FP2_SDK_v1.1/epoc32/include/stdapis/stlport;C:/Symbian/9.2/S60_3rd_FP2_SDK_v1.1/epoc32/include/variant;C:/Symbian/9.2/S60_3rd_FP2_SDK_v1.1/epoc32/include/ecom;C:/Symbian/9.2/S60_3rd_FP2_SDK_v1.1/epoc32/include/stdapis/stlport/stl;C:/Carbide/Testworkspace/ZXingBarcodeReader/group;C:/Carbide/Testworkspace/ZXingBarcodeReader/inc;C:/Carbide/Testworkspace/ZXingBarcodeReader/group/zxing/common/reedsolomon;C:/Carbide/Testworkspace/ZXingBarcodeReader/group/zxing/oned;C:/Carbide/Testworkspace/ZXingBarcodeReader/group/zxing/qrcode;C:/Carbide/Testworkspace/ZXingBarcodeReader/group/zxing/qrcode/decoder;C:/Carbide/Testworkspace/ZXingBarcodeReader/group/zxing/qrcode/detector;" macrosCache="_UNICODE;__SYMBIAN32__;__SUPPORT_CPP_EXCEPTIONS__;__EXE__;__S60_3X__;__SERIES60_3X__;__S60_32__;__CW32__;__WINS__;__WINSCW__;_DEBUG;" moduleId="configDataCache" sourcesCache="/ZXingBarcodeReader/data;/ZXingBarcodeReader/group;/ZXingBarcodeReader/group/zxing;/ZXingBarcodeReader/group/zxing/common;/ZXingBarcodeReader/group/zxing/common/reedsolomon;/ZXingBarcodeReader/group/zxing/oned;/ZXingBarcodeReader/group/zxing/qrcode;/ZXingBarcodeReader/group/zxing/qrcode/decoder;/ZXingBarcodeReader/group/zxing/qrcode/detector;/ZXingBarcodeReader/inc;/ZXingBarcodeReader/src;" timestampCache="1274434344850" useMmpMacrosCache="true"/>
|
||||
<storageModule filesCache="C:\Carbide\workspace\ZXingBarcodeReader\group\bld.inf;C:\Carbide\workspace\ZXingBarcodeReader\group\ZXingBarcodeReader.mmp;" includesCache="C:/S60/devices/S60_5th_Edition_SDK_v1.0/epoc32/include;C:/S60/devices/S60_5th_Edition_SDK_v1.0/epoc32/include/stdapis;C:/S60/devices/S60_5th_Edition_SDK_v1.0/epoc32/include/stdapis/sys;C:/S60/devices/S60_5th_Edition_SDK_v1.0/epoc32/include/stdapis/stlport;C:/S60/devices/S60_5th_Edition_SDK_v1.0/epoc32/include/variant;C:/S60/devices/S60_5th_Edition_SDK_v1.0/epoc32/include/ecom;C:/S60/devices/S60_5th_Edition_SDK_v1.0/epoc32/include/stdapis/stlport/stl;C:/Carbide/workspace/ZXingBarcodeReader/group;C:/Carbide/workspace/ZXingBarcodeReader/inc;C:/Carbide/workspace/ZXingBarcodeReader/group/zxing/common;C:/Carbide/workspace/ZXingBarcodeReader/group/zxing/common/reedsolomon;C:/Carbide/workspace/ZXingBarcodeReader/group/zxing/oned;C:/Carbide/workspace/ZXingBarcodeReader/group/zxing/qrcode;C:/Carbide/workspace/ZXingBarcodeReader/group/zxing/qrcode/decoder;C:/Carbide/workspace/ZXingBarcodeReader/group/zxing/qrcode/detector;" macrosCache="_UNICODE;__SYMBIAN32__;__SUPPORT_CPP_EXCEPTIONS__;__EXE__;__S60_3X__;__SERIES60_3X__;__S60_5X__;__CW32__;__WINS__;__WINSCW__;__S60_50__;_DEBUG;" moduleId="configDataCache" sourcesCache="/ZXingBarcodeReader/data;/ZXingBarcodeReader/group;/ZXingBarcodeReader/group/zxing;/ZXingBarcodeReader/group/zxing/common;/ZXingBarcodeReader/group/zxing/common/reedsolomon;/ZXingBarcodeReader/group/zxing/oned;/ZXingBarcodeReader/group/zxing/qrcode;/ZXingBarcodeReader/group/zxing/qrcode/decoder;/ZXingBarcodeReader/group/zxing/qrcode/detector;/ZXingBarcodeReader/inc;/ZXingBarcodeReader/src;" timestampCache="1279097973179" useMmpMacrosCache="true"/>
|
||||
<storageModule moduleId="org.eclipse.cdt.core.externalSettings"/>
|
||||
<storageModule moduleId="org.eclipse.cdt.core.language.mapping"/>
|
||||
<storageModule moduleId="org.eclipse.cdt.internal.ui.text.commentOwnerProjectMappings"/>
|
||||
</cconfiguration>
|
||||
<cconfiguration id="Phone Debug (ARMV5) [S60_3rd_FP2_SDK_v1.1]">
|
||||
<storageModule buildSystemId="com.nokia.carbide.cdt.builder.CarbideConfigurationDataProvider" id="Phone Debug (ARMV5) [S60_3rd_FP2_SDK_v1.1]" moduleId="org.eclipse.cdt.core.settings" name="Phone Debug (ARMV5) [S60_3rd_FP2_SDK_v1.1]">
|
||||
<cconfiguration id="Phone Debug (ARMV5) [S60_5th_Edition_SDK_v1.0]">
|
||||
<storageModule buildSystemId="com.nokia.carbide.cdt.builder.CarbideConfigurationDataProvider" id="Phone Debug (ARMV5) [S60_5th_Edition_SDK_v1.0]" moduleId="org.eclipse.cdt.core.settings" name="Phone Debug (ARMV5) [S60_5th_Edition_SDK_v1.0]">
|
||||
<externalSettings/>
|
||||
<extensions>
|
||||
<extension id="org.eclipse.cdt.core.ELF" point="org.eclipse.cdt.core.BinaryParser"/>
|
||||
|
@ -49,18 +49,18 @@
|
|||
<extension id="com.nokia.carbide.cdt.builder.RVCTCompilerErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
|
||||
</extensions>
|
||||
</storageModule>
|
||||
<storageModule moduleId="org.eclipse.cdt.core.language.mapping"/>
|
||||
<storageModule moduleId="org.eclipse.cdt.internal.ui.text.commentOwnerProjectMappings"/>
|
||||
<storageModule moduleId="CarbideConfigurationDataProvider">
|
||||
<ENV_VAR_DATA_ID/>
|
||||
<ARGUMENTS_DATA_ID ABLDFREEZEARGSSTORAGE="-r"/>
|
||||
<ROM_BUILDER_DATA_ID ROMBUILDWORKINGDIRECTORYSTORAGE="C:\Symbian\9.2\S60_3rd_FP2_SDK_v1.1\epoc32\rom\"/>
|
||||
<ROM_BUILDER_DATA_ID ROMBUILDWORKINGDIRECTORYSTORAGE="C:\"/>
|
||||
</storageModule>
|
||||
<storageModule filesCache="C:\Carbide\Testworkspace\ZXingBarcodeReader\group\bld.inf;C:\Carbide\Testworkspace\ZXingBarcodeReader\group\ZXingBarcodeReader.mmp;" includesCache="C:/Symbian/9.2/S60_3rd_FP2_SDK_v1.1/epoc32/include;C:/Symbian/9.2/S60_3rd_FP2_SDK_v1.1/epoc32/include/stdapis;C:/Symbian/9.2/S60_3rd_FP2_SDK_v1.1/epoc32/include/stdapis/sys;C:/Symbian/9.2/S60_3rd_FP2_SDK_v1.1/epoc32/include/stdapis/stlport;C:/Symbian/9.2/S60_3rd_FP2_SDK_v1.1/epoc32/include/variant;C:/Symbian/9.2/S60_3rd_FP2_SDK_v1.1/epoc32/include/ecom;C:/Symbian/9.2/S60_3rd_FP2_SDK_v1.1/epoc32/include/stdapis/stlport/stl;C:/Carbide/Testworkspace/ZXingBarcodeReader/group;C:/Carbide/Testworkspace/ZXingBarcodeReader/inc;C:/Carbide/Testworkspace/ZXingBarcodeReader/group/zxing/common/reedsolomon;C:/Carbide/Testworkspace/ZXingBarcodeReader/group/zxing/oned;C:/Carbide/Testworkspace/ZXingBarcodeReader/group/zxing/qrcode;C:/Carbide/Testworkspace/ZXingBarcodeReader/group/zxing/qrcode/decoder;C:/Carbide/Testworkspace/ZXingBarcodeReader/group/zxing/qrcode/detector;" macrosCache="_UNICODE;__SUPPORT_CPP_EXCEPTIONS__;__S60_32__;__MARM_ARMV5__;__ARMCC__;__ARMCC_2_2__;__SYMBIAN32__;__MARM__;__EXE__;__S60_3X__;__SERIES60_3X__;__EPOC32__;__GENERIC_MARM__;__EABI__;_DEBUG;" moduleId="configDataCache" sourcesCache="/ZXingBarcodeReader/data;/ZXingBarcodeReader/group;/ZXingBarcodeReader/group/zxing;/ZXingBarcodeReader/group/zxing/common;/ZXingBarcodeReader/group/zxing/common/reedsolomon;/ZXingBarcodeReader/group/zxing/oned;/ZXingBarcodeReader/group/zxing/qrcode;/ZXingBarcodeReader/group/zxing/qrcode/decoder;/ZXingBarcodeReader/group/zxing/qrcode/detector;/ZXingBarcodeReader/inc;/ZXingBarcodeReader/src;" timestampCache="1274434344850" useMmpMacrosCache="true"/>
|
||||
<storageModule moduleId="org.eclipse.cdt.core.language.mapping"/>
|
||||
<storageModule moduleId="org.eclipse.cdt.internal.ui.text.commentOwnerProjectMappings"/>
|
||||
<storageModule filesCache="C:\Carbide\workspace\ZXingBarcodeReader\group\bld.inf;C:\Carbide\workspace\ZXingBarcodeReader\group\ZXingBarcodeReader.mmp;" includesCache="C:/S60/devices/S60_5th_Edition_SDK_v1.0/epoc32/include;C:/S60/devices/S60_5th_Edition_SDK_v1.0/epoc32/include/stdapis;C:/S60/devices/S60_5th_Edition_SDK_v1.0/epoc32/include/stdapis/sys;C:/S60/devices/S60_5th_Edition_SDK_v1.0/epoc32/include/stdapis/stlport;C:/S60/devices/S60_5th_Edition_SDK_v1.0/epoc32/include/variant;C:/S60/devices/S60_5th_Edition_SDK_v1.0/epoc32/include/ecom;C:/S60/devices/S60_5th_Edition_SDK_v1.0/epoc32/include/stdapis/stlport/stl;C:/Carbide/workspace/ZXingBarcodeReader/group;C:/Carbide/workspace/ZXingBarcodeReader/inc;C:/Carbide/workspace/ZXingBarcodeReader/group/zxing/common;C:/Carbide/workspace/ZXingBarcodeReader/group/zxing/common/reedsolomon;C:/Carbide/workspace/ZXingBarcodeReader/group/zxing/oned;C:/Carbide/workspace/ZXingBarcodeReader/group/zxing/qrcode;C:/Carbide/workspace/ZXingBarcodeReader/group/zxing/qrcode/decoder;C:/Carbide/workspace/ZXingBarcodeReader/group/zxing/qrcode/detector;" macrosCache="_UNICODE;__SUPPORT_CPP_EXCEPTIONS__;__MARM_ARMV5__;__ARMCC__;__ARMCC_2_2__;__SYMBIAN32__;__MARM__;__EXE__;__S60_3X__;__SERIES60_3X__;__ARMCC_2__;__S60_5X__;__EPOC32__;__GENERIC_MARM__;__EABI__;__S60_50__;_DEBUG;" moduleId="configDataCache" sourcesCache="/ZXingBarcodeReader/data;/ZXingBarcodeReader/group;/ZXingBarcodeReader/group/zxing;/ZXingBarcodeReader/group/zxing/common;/ZXingBarcodeReader/group/zxing/common/reedsolomon;/ZXingBarcodeReader/group/zxing/oned;/ZXingBarcodeReader/group/zxing/qrcode;/ZXingBarcodeReader/group/zxing/qrcode/decoder;/ZXingBarcodeReader/group/zxing/qrcode/detector;/ZXingBarcodeReader/inc;/ZXingBarcodeReader/src;" timestampCache="1279097973195" useMmpMacrosCache="true"/>
|
||||
<storageModule moduleId="org.eclipse.cdt.core.externalSettings"/>
|
||||
</cconfiguration>
|
||||
<cconfiguration id="Phone Release (ARMV5) [S60_3rd_FP2_SDK_v1.1]">
|
||||
<storageModule buildSystemId="com.nokia.carbide.cdt.builder.CarbideConfigurationDataProvider" id="Phone Release (ARMV5) [S60_3rd_FP2_SDK_v1.1]" moduleId="org.eclipse.cdt.core.settings" name="Phone Release (ARMV5) [S60_3rd_FP2_SDK_v1.1]">
|
||||
<cconfiguration id="Phone Release (ARMV5) [S60_5th_Edition_SDK_v1.0]">
|
||||
<storageModule buildSystemId="com.nokia.carbide.cdt.builder.CarbideConfigurationDataProvider" id="Phone Release (ARMV5) [S60_5th_Edition_SDK_v1.0]" moduleId="org.eclipse.cdt.core.settings" name="Phone Release (ARMV5) [S60_5th_Edition_SDK_v1.0]">
|
||||
<externalSettings/>
|
||||
<extensions>
|
||||
<extension id="org.eclipse.cdt.core.ELF" point="org.eclipse.cdt.core.BinaryParser"/>
|
||||
|
@ -77,18 +77,18 @@
|
|||
<extension id="com.nokia.carbide.cdt.builder.RVCTCompilerErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
|
||||
</extensions>
|
||||
</storageModule>
|
||||
<storageModule moduleId="org.eclipse.cdt.core.language.mapping"/>
|
||||
<storageModule moduleId="org.eclipse.cdt.internal.ui.text.commentOwnerProjectMappings"/>
|
||||
<storageModule moduleId="CarbideConfigurationDataProvider">
|
||||
<ENV_VAR_DATA_ID/>
|
||||
<ARGUMENTS_DATA_ID ABLDFREEZEARGSSTORAGE="-r"/>
|
||||
<ROM_BUILDER_DATA_ID ROMBUILDWORKINGDIRECTORYSTORAGE="C:\Symbian\9.2\S60_3rd_FP2_SDK_v1.1\epoc32\rom\"/>
|
||||
<ROM_BUILDER_DATA_ID ROMBUILDWORKINGDIRECTORYSTORAGE="C:\"/>
|
||||
</storageModule>
|
||||
<storageModule filesCache="C:\Carbide\Testworkspace\ZXingBarcodeReader\group\bld.inf;C:\Carbide\Testworkspace\ZXingBarcodeReader\group\ZXingBarcodeReader.mmp;" includesCache="C:/Symbian/9.2/S60_3rd_FP2_SDK_v1.1/epoc32/include;C:/Symbian/9.2/S60_3rd_FP2_SDK_v1.1/epoc32/include/stdapis;C:/Symbian/9.2/S60_3rd_FP2_SDK_v1.1/epoc32/include/stdapis/sys;C:/Symbian/9.2/S60_3rd_FP2_SDK_v1.1/epoc32/include/stdapis/stlport;C:/Symbian/9.2/S60_3rd_FP2_SDK_v1.1/epoc32/include/variant;C:/Symbian/9.2/S60_3rd_FP2_SDK_v1.1/epoc32/include/ecom;C:/Symbian/9.2/S60_3rd_FP2_SDK_v1.1/epoc32/include/stdapis/stlport/stl;C:/Carbide/Testworkspace/ZXingBarcodeReader/group;C:/Carbide/Testworkspace/ZXingBarcodeReader/inc;C:/Carbide/Testworkspace/ZXingBarcodeReader/group/zxing/common/reedsolomon;C:/Carbide/Testworkspace/ZXingBarcodeReader/group/zxing/oned;C:/Carbide/Testworkspace/ZXingBarcodeReader/group/zxing/qrcode;C:/Carbide/Testworkspace/ZXingBarcodeReader/group/zxing/qrcode/decoder;C:/Carbide/Testworkspace/ZXingBarcodeReader/group/zxing/qrcode/detector;" macrosCache="_UNICODE;__SUPPORT_CPP_EXCEPTIONS__;__S60_32__;__MARM_ARMV5__;NDEBUG;__ARMCC__;__ARMCC_2_2__;__SYMBIAN32__;__MARM__;__EXE__;__S60_3X__;__SERIES60_3X__;__EPOC32__;__GENERIC_MARM__;__EABI__;" moduleId="configDataCache" sourcesCache="/ZXingBarcodeReader/data;/ZXingBarcodeReader/group;/ZXingBarcodeReader/group/zxing;/ZXingBarcodeReader/group/zxing/common;/ZXingBarcodeReader/group/zxing/common/reedsolomon;/ZXingBarcodeReader/group/zxing/oned;/ZXingBarcodeReader/group/zxing/qrcode;/ZXingBarcodeReader/group/zxing/qrcode/decoder;/ZXingBarcodeReader/group/zxing/qrcode/detector;/ZXingBarcodeReader/inc;/ZXingBarcodeReader/src;" timestampCache="1274434344865" useMmpMacrosCache="true"/>
|
||||
<storageModule moduleId="org.eclipse.cdt.core.language.mapping"/>
|
||||
<storageModule moduleId="org.eclipse.cdt.internal.ui.text.commentOwnerProjectMappings"/>
|
||||
<storageModule filesCache="C:\Carbide\workspace\ZXingBarcodeReader\group\bld.inf;C:\Carbide\workspace\ZXingBarcodeReader\group\ZXingBarcodeReader.mmp;" includesCache="C:/S60/devices/S60_5th_Edition_SDK_v1.0/epoc32/include;C:/S60/devices/S60_5th_Edition_SDK_v1.0/epoc32/include/stdapis;C:/S60/devices/S60_5th_Edition_SDK_v1.0/epoc32/include/stdapis/sys;C:/S60/devices/S60_5th_Edition_SDK_v1.0/epoc32/include/stdapis/stlport;C:/S60/devices/S60_5th_Edition_SDK_v1.0/epoc32/include/variant;C:/S60/devices/S60_5th_Edition_SDK_v1.0/epoc32/include/ecom;C:/S60/devices/S60_5th_Edition_SDK_v1.0/epoc32/include/stdapis/stlport/stl;C:/Carbide/workspace/ZXingBarcodeReader/group;C:/Carbide/workspace/ZXingBarcodeReader/inc;C:/Carbide/workspace/ZXingBarcodeReader/group/zxing/common;C:/Carbide/workspace/ZXingBarcodeReader/group/zxing/common/reedsolomon;C:/Carbide/workspace/ZXingBarcodeReader/group/zxing/oned;C:/Carbide/workspace/ZXingBarcodeReader/group/zxing/qrcode;C:/Carbide/workspace/ZXingBarcodeReader/group/zxing/qrcode/decoder;C:/Carbide/workspace/ZXingBarcodeReader/group/zxing/qrcode/detector;" macrosCache="_UNICODE;__SUPPORT_CPP_EXCEPTIONS__;__MARM_ARMV5__;NDEBUG;__ARMCC__;__ARMCC_2_2__;__SYMBIAN32__;__MARM__;__EXE__;__S60_3X__;__SERIES60_3X__;__ARMCC_2__;__S60_5X__;__EPOC32__;__GENERIC_MARM__;__EABI__;__S60_50__;" moduleId="configDataCache" sourcesCache="/ZXingBarcodeReader/data;/ZXingBarcodeReader/group;/ZXingBarcodeReader/group/zxing;/ZXingBarcodeReader/group/zxing/common;/ZXingBarcodeReader/group/zxing/common/reedsolomon;/ZXingBarcodeReader/group/zxing/oned;/ZXingBarcodeReader/group/zxing/qrcode;/ZXingBarcodeReader/group/zxing/qrcode/decoder;/ZXingBarcodeReader/group/zxing/qrcode/detector;/ZXingBarcodeReader/inc;/ZXingBarcodeReader/src;" timestampCache="1279097973226" useMmpMacrosCache="true"/>
|
||||
<storageModule moduleId="org.eclipse.cdt.core.externalSettings"/>
|
||||
</cconfiguration>
|
||||
<cconfiguration id="Phone Debug (GCCE) [S60_3rd_FP2_SDK_v1.1]">
|
||||
<storageModule buildSystemId="com.nokia.carbide.cdt.builder.CarbideConfigurationDataProvider" id="Phone Debug (GCCE) [S60_3rd_FP2_SDK_v1.1]" moduleId="org.eclipse.cdt.core.settings" name="Phone Debug (GCCE) [S60_3rd_FP2_SDK_v1.1]">
|
||||
<cconfiguration id="Phone Debug (GCCE) [S60_5th_Edition_SDK_v1.0]">
|
||||
<storageModule buildSystemId="com.nokia.carbide.cdt.builder.CarbideConfigurationDataProvider" id="Phone Debug (GCCE) [S60_5th_Edition_SDK_v1.0]" moduleId="org.eclipse.cdt.core.settings" name="Phone Debug (GCCE) [S60_5th_Edition_SDK_v1.0]">
|
||||
<externalSettings/>
|
||||
<extensions>
|
||||
<extension id="org.eclipse.cdt.core.ELF" point="org.eclipse.cdt.core.BinaryParser"/>
|
||||
|
@ -105,19 +105,19 @@
|
|||
<extension id="com.nokia.carbide.cdt.builder.GCCELinkerErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
|
||||
</extensions>
|
||||
</storageModule>
|
||||
<storageModule moduleId="CarbideConfigurationDataProvider">
|
||||
<SIS_BUILDER_DATA_ID CREATESTUBSTORAGE="false" ENABLEDSTORAGE="true" PARTIALUPGRADESTORAGE="false" PKGFILESTORAGE="C:\Carbide\Testworkspace\ZXingBarcodeReader\sis\ZXingBarcodeReader_S60.pkg" SIGNINGTYPESTORAGE="1"/>
|
||||
<ENV_VAR_DATA_ID/>
|
||||
<ARGUMENTS_DATA_ID ABLDFREEZEARGSSTORAGE="-r"/>
|
||||
<ROM_BUILDER_DATA_ID ROMBUILDWORKINGDIRECTORYSTORAGE="C:\Symbian\9.2\S60_3rd_FP2_SDK_v1.1\epoc32\rom\"/>
|
||||
</storageModule>
|
||||
<storageModule filesCache="C:\Carbide\Testworkspace\ZXingBarcodeReader\group\bld.inf;C:\Carbide\Testworkspace\ZXingBarcodeReader\group\ZXingBarcodeReader.mmp;" includesCache="C:/Symbian/9.2/S60_3rd_FP2_SDK_v1.1/epoc32/include;C:/Symbian/9.2/S60_3rd_FP2_SDK_v1.1/epoc32/include/stdapis;C:/Symbian/9.2/S60_3rd_FP2_SDK_v1.1/epoc32/include/stdapis/sys;C:/Symbian/9.2/S60_3rd_FP2_SDK_v1.1/epoc32/include/stdapis/stlport;C:/Symbian/9.2/S60_3rd_FP2_SDK_v1.1/epoc32/include/variant;C:/Symbian/9.2/S60_3rd_FP2_SDK_v1.1/epoc32/include/ecom;C:/Symbian/9.2/S60_3rd_FP2_SDK_v1.1/epoc32/include/stdapis/stlport/stl;C:/Carbide/Testworkspace/ZXingBarcodeReader/group;C:/Carbide/Testworkspace/ZXingBarcodeReader/inc;C:/Carbide/Testworkspace/ZXingBarcodeReader/group/zxing/common/reedsolomon;C:/Carbide/Testworkspace/ZXingBarcodeReader/group/zxing/oned;C:/Carbide/Testworkspace/ZXingBarcodeReader/group/zxing/qrcode;C:/Carbide/Testworkspace/ZXingBarcodeReader/group/zxing/qrcode/decoder;C:/Carbide/Testworkspace/ZXingBarcodeReader/group/zxing/qrcode/detector;" macrosCache="_UNICODE;__SUPPORT_CPP_EXCEPTIONS__;__S60_32__;__MARM_ARMV5__;__SYMBIAN32__;__GCCE__;__MARM__;__EXE__;__SERIES60_3X__;__S60_3X__;__GENERIC_MARM__;__EPOC32__;__EABI__;_DEBUG;" moduleId="configDataCache" sourcesCache="/ZXingBarcodeReader/data;/ZXingBarcodeReader/group;/ZXingBarcodeReader/group/zxing;/ZXingBarcodeReader/group/zxing/common;/ZXingBarcodeReader/group/zxing/common/reedsolomon;/ZXingBarcodeReader/group/zxing/oned;/ZXingBarcodeReader/group/zxing/qrcode;/ZXingBarcodeReader/group/zxing/qrcode/decoder;/ZXingBarcodeReader/group/zxing/qrcode/detector;/ZXingBarcodeReader/inc;/ZXingBarcodeReader/src;" timestampCache="1274434344881" useMmpMacrosCache="true"/>
|
||||
<storageModule moduleId="org.eclipse.cdt.core.language.mapping"/>
|
||||
<storageModule moduleId="org.eclipse.cdt.internal.ui.text.commentOwnerProjectMappings"/>
|
||||
<storageModule moduleId="CarbideConfigurationDataProvider">
|
||||
<SIS_BUILDER_DATA_ID CREATESTUBSTORAGE="false" ENABLEDSTORAGE="true" PARTIALUPGRADESTORAGE="false" PKGFILESTORAGE="C:\Carbide\workspace\ZXingBarcodeReader\sis\ZXingBarcodeReader_S60.pkg" SIGNINGTYPESTORAGE="1"/>
|
||||
<ENV_VAR_DATA_ID/>
|
||||
<ARGUMENTS_DATA_ID ABLDFREEZEARGSSTORAGE="-r"/>
|
||||
<ROM_BUILDER_DATA_ID ROMBUILDWORKINGDIRECTORYSTORAGE="C:\"/>
|
||||
</storageModule>
|
||||
<storageModule filesCache="C:\Carbide\workspace\ZXingBarcodeReader\group\bld.inf;C:\Carbide\workspace\ZXingBarcodeReader\group\ZXingBarcodeReader.mmp;" includesCache="C:/S60/devices/S60_5th_Edition_SDK_v1.0/epoc32/include;C:/S60/devices/S60_5th_Edition_SDK_v1.0/epoc32/include/stdapis;C:/S60/devices/S60_5th_Edition_SDK_v1.0/epoc32/include/stdapis/sys;C:/S60/devices/S60_5th_Edition_SDK_v1.0/epoc32/include/stdapis/stlport;C:/S60/devices/S60_5th_Edition_SDK_v1.0/epoc32/include/variant;C:/S60/devices/S60_5th_Edition_SDK_v1.0/epoc32/include/ecom;C:/S60/devices/S60_5th_Edition_SDK_v1.0/epoc32/include/stdapis/stlport/stl;C:/Carbide/workspace/ZXingBarcodeReader/group;C:/Carbide/workspace/ZXingBarcodeReader/inc;C:/Carbide/workspace/ZXingBarcodeReader/group/zxing/common;C:/Carbide/workspace/ZXingBarcodeReader/group/zxing/common/reedsolomon;C:/Carbide/workspace/ZXingBarcodeReader/group/zxing/oned;C:/Carbide/workspace/ZXingBarcodeReader/group/zxing/qrcode;C:/Carbide/workspace/ZXingBarcodeReader/group/zxing/qrcode/decoder;C:/Carbide/workspace/ZXingBarcodeReader/group/zxing/qrcode/detector;" macrosCache="_UNICODE;__SUPPORT_CPP_EXCEPTIONS__;__MARM_ARMV5__;__SYMBIAN32__;__GCCE__;__MARM__;__EXE__;__SERIES60_3X__;__S60_3X__;__S60_5X__;__EPOC32__;__GENERIC_MARM__;__EABI__;_DEBUG;__S60_50__;" moduleId="configDataCache" sourcesCache="/ZXingBarcodeReader/data;/ZXingBarcodeReader/group;/ZXingBarcodeReader/group/zxing;/ZXingBarcodeReader/group/zxing/common;/ZXingBarcodeReader/group/zxing/common/reedsolomon;/ZXingBarcodeReader/group/zxing/oned;/ZXingBarcodeReader/group/zxing/qrcode;/ZXingBarcodeReader/group/zxing/qrcode/decoder;/ZXingBarcodeReader/group/zxing/qrcode/detector;/ZXingBarcodeReader/inc;/ZXingBarcodeReader/src;" timestampCache="1279097973257" useMmpMacrosCache="true"/>
|
||||
<storageModule moduleId="org.eclipse.cdt.core.externalSettings"/>
|
||||
</cconfiguration>
|
||||
<cconfiguration id="Phone Release (GCCE) [S60_3rd_FP2_SDK_v1.1]">
|
||||
<storageModule buildSystemId="com.nokia.carbide.cdt.builder.CarbideConfigurationDataProvider" id="Phone Release (GCCE) [S60_3rd_FP2_SDK_v1.1]" moduleId="org.eclipse.cdt.core.settings" name="Phone Release (GCCE) [S60_3rd_FP2_SDK_v1.1]">
|
||||
<cconfiguration id="Phone Release (GCCE) [S60_5th_Edition_SDK_v1.0]">
|
||||
<storageModule buildSystemId="com.nokia.carbide.cdt.builder.CarbideConfigurationDataProvider" id="Phone Release (GCCE) [S60_5th_Edition_SDK_v1.0]" moduleId="org.eclipse.cdt.core.settings" name="Phone Release (GCCE) [S60_5th_Edition_SDK_v1.0]">
|
||||
<externalSettings/>
|
||||
<extensions>
|
||||
<extension id="org.eclipse.cdt.core.ELF" point="org.eclipse.cdt.core.BinaryParser"/>
|
||||
|
@ -134,14 +134,14 @@
|
|||
<extension id="com.nokia.carbide.cdt.builder.GCCELinkerErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
|
||||
</extensions>
|
||||
</storageModule>
|
||||
<storageModule moduleId="org.eclipse.cdt.core.language.mapping"/>
|
||||
<storageModule moduleId="org.eclipse.cdt.internal.ui.text.commentOwnerProjectMappings"/>
|
||||
<storageModule moduleId="CarbideConfigurationDataProvider">
|
||||
<ENV_VAR_DATA_ID/>
|
||||
<ARGUMENTS_DATA_ID ABLDFREEZEARGSSTORAGE="-r"/>
|
||||
<ROM_BUILDER_DATA_ID ROMBUILDWORKINGDIRECTORYSTORAGE="C:\Symbian\9.2\S60_3rd_FP2_SDK_v1.1\epoc32\rom\"/>
|
||||
<ROM_BUILDER_DATA_ID ROMBUILDWORKINGDIRECTORYSTORAGE="C:\"/>
|
||||
</storageModule>
|
||||
<storageModule filesCache="C:\Carbide\Testworkspace\ZXingBarcodeReader\group\bld.inf;C:\Carbide\Testworkspace\ZXingBarcodeReader\group\ZXingBarcodeReader.mmp;" includesCache="C:/Symbian/9.2/S60_3rd_FP2_SDK_v1.1/epoc32/include;C:/Symbian/9.2/S60_3rd_FP2_SDK_v1.1/epoc32/include/stdapis;C:/Symbian/9.2/S60_3rd_FP2_SDK_v1.1/epoc32/include/stdapis/sys;C:/Symbian/9.2/S60_3rd_FP2_SDK_v1.1/epoc32/include/stdapis/stlport;C:/Symbian/9.2/S60_3rd_FP2_SDK_v1.1/epoc32/include/variant;C:/Symbian/9.2/S60_3rd_FP2_SDK_v1.1/epoc32/include/ecom;C:/Symbian/9.2/S60_3rd_FP2_SDK_v1.1/epoc32/include/stdapis/stlport/stl;C:/Carbide/Testworkspace/ZXingBarcodeReader/group;C:/Carbide/Testworkspace/ZXingBarcodeReader/inc;C:/Carbide/Testworkspace/ZXingBarcodeReader/group/zxing/common/reedsolomon;C:/Carbide/Testworkspace/ZXingBarcodeReader/group/zxing/oned;C:/Carbide/Testworkspace/ZXingBarcodeReader/group/zxing/qrcode;C:/Carbide/Testworkspace/ZXingBarcodeReader/group/zxing/qrcode/decoder;C:/Carbide/Testworkspace/ZXingBarcodeReader/group/zxing/qrcode/detector;" macrosCache="_UNICODE;__SUPPORT_CPP_EXCEPTIONS__;__S60_32__;__MARM_ARMV5__;NDEBUG;__SYMBIAN32__;__GCCE__;__MARM__;__EXE__;__SERIES60_3X__;__S60_3X__;__GENERIC_MARM__;__EPOC32__;__EABI__;" moduleId="configDataCache" sourcesCache="/ZXingBarcodeReader/data;/ZXingBarcodeReader/group;/ZXingBarcodeReader/group/zxing;/ZXingBarcodeReader/group/zxing/common;/ZXingBarcodeReader/group/zxing/common/reedsolomon;/ZXingBarcodeReader/group/zxing/oned;/ZXingBarcodeReader/group/zxing/qrcode;/ZXingBarcodeReader/group/zxing/qrcode/decoder;/ZXingBarcodeReader/group/zxing/qrcode/detector;/ZXingBarcodeReader/inc;/ZXingBarcodeReader/src;" timestampCache="1274434344912" useMmpMacrosCache="true"/>
|
||||
<storageModule moduleId="org.eclipse.cdt.core.language.mapping"/>
|
||||
<storageModule moduleId="org.eclipse.cdt.internal.ui.text.commentOwnerProjectMappings"/>
|
||||
<storageModule filesCache="C:\Carbide\workspace\ZXingBarcodeReader\group\bld.inf;C:\Carbide\workspace\ZXingBarcodeReader\group\ZXingBarcodeReader.mmp;" includesCache="C:/S60/devices/S60_5th_Edition_SDK_v1.0/epoc32/include;C:/S60/devices/S60_5th_Edition_SDK_v1.0/epoc32/include/stdapis;C:/S60/devices/S60_5th_Edition_SDK_v1.0/epoc32/include/stdapis/sys;C:/S60/devices/S60_5th_Edition_SDK_v1.0/epoc32/include/stdapis/stlport;C:/S60/devices/S60_5th_Edition_SDK_v1.0/epoc32/include/variant;C:/S60/devices/S60_5th_Edition_SDK_v1.0/epoc32/include/ecom;C:/S60/devices/S60_5th_Edition_SDK_v1.0/epoc32/include/stdapis/stlport/stl;C:/Carbide/workspace/ZXingBarcodeReader/group;C:/Carbide/workspace/ZXingBarcodeReader/inc;C:/Carbide/workspace/ZXingBarcodeReader/group/zxing/common;C:/Carbide/workspace/ZXingBarcodeReader/group/zxing/common/reedsolomon;C:/Carbide/workspace/ZXingBarcodeReader/group/zxing/oned;C:/Carbide/workspace/ZXingBarcodeReader/group/zxing/qrcode;C:/Carbide/workspace/ZXingBarcodeReader/group/zxing/qrcode/decoder;C:/Carbide/workspace/ZXingBarcodeReader/group/zxing/qrcode/detector;" macrosCache="_UNICODE;__SUPPORT_CPP_EXCEPTIONS__;__MARM_ARMV5__;NDEBUG;__SYMBIAN32__;__GCCE__;__MARM__;__EXE__;__SERIES60_3X__;__S60_3X__;__S60_5X__;__EPOC32__;__GENERIC_MARM__;__EABI__;__S60_50__;" moduleId="configDataCache" sourcesCache="/ZXingBarcodeReader/data;/ZXingBarcodeReader/group;/ZXingBarcodeReader/group/zxing;/ZXingBarcodeReader/group/zxing/common;/ZXingBarcodeReader/group/zxing/common/reedsolomon;/ZXingBarcodeReader/group/zxing/oned;/ZXingBarcodeReader/group/zxing/qrcode;/ZXingBarcodeReader/group/zxing/qrcode/decoder;/ZXingBarcodeReader/group/zxing/qrcode/detector;/ZXingBarcodeReader/inc;/ZXingBarcodeReader/src;" timestampCache="1279097973273" useMmpMacrosCache="true"/>
|
||||
<storageModule moduleId="org.eclipse.cdt.core.externalSettings"/>
|
||||
</cconfiguration>
|
||||
</storageModule>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
REM Bldmake-generated batch file - ABLD.BAT
|
||||
REM ** DO NOT EDIT **
|
||||
|
||||
perl -S ABLD.PL "\Carbide\ZXingWorkspace\ZXingBarcodeReader\group\\" %1 %2 %3 %4 %5 %6 %7 %8 %9
|
||||
perl -S ABLD.PL "\Carbide\workspace\ZXingBarcodeReader\group\\" %1 %2 %3 %4 %5 %6 %7 %8 %9
|
||||
if errorlevel==1 goto CheckPerl
|
||||
goto End
|
||||
|
||||
|
|
|
@ -31,12 +31,19 @@ SYSTEMINCLUDE /epoc32/include/stdapis/stlport/stl
|
|||
|
||||
SYSTEMINCLUDE .
|
||||
SYSTEMINCLUDE ../inc
|
||||
SYSTEMINCLUDE zxing/common
|
||||
SYSTEMINCLUDE zxing/common/reedsolomon
|
||||
SYSTEMINCLUDE zxing/oned
|
||||
SYSTEMINCLUDE zxing/qrcode
|
||||
SYSTEMINCLUDE zxing/qrcode/decoder
|
||||
SYSTEMINCLUDE zxing/qrcode/detector
|
||||
|
||||
/*
|
||||
SYSTEMINCLUDE zxing/datamatrix
|
||||
SYSTEMINCLUDE zxing/datamatrix/decoder
|
||||
SYSTEMINCLUDE zxing/datamatrix/detector
|
||||
*/
|
||||
|
||||
SOURCEPATH ../src
|
||||
SOURCE ZXingBarcodeReader.cpp
|
||||
SOURCE ZXingBarcodeReaderApplication.cpp ZXingBarcodeReaderAppView.cpp
|
||||
|
@ -81,6 +88,15 @@ SOURCE ErrorCorrectionLevel.cpp FormatInformation.cpp QRCodeReader.cpp Version.c
|
|||
SOURCEPATH zxing
|
||||
SOURCE BarcodeFormat.cpp Binarizer.cpp BinaryBitmap.cpp Exception.cpp LuminanceSource.cpp MultiFormatReader.cpp Reader.cpp ReaderException.cpp Result.cpp ResultPoint.cpp
|
||||
|
||||
/*
|
||||
SOURCEPATH zxing/datamatrix/detector
|
||||
SOURCE CornerPoint.cpp Detector.cpp MonochromeRectangleDetector.cpp
|
||||
SOURCEPATH zxing/datamatrix/decoder
|
||||
SOURCE BitMatrixParser.cpp DataBlock.cpp DecodedBitStreamParser.cpp Decoder.cpp
|
||||
SOURCEPATH zxing/datamatrix
|
||||
SOURCE Version.cpp DataMatrixReader.cpp
|
||||
*/
|
||||
|
||||
OPTION CW -wchar_t on
|
||||
OPTION ARMCC --visibility_inlines_hidden
|
||||
OPTION GCCE -fvisibility-inlines-hidden
|
||||
|
|
|
@ -23,15 +23,17 @@
|
|||
|
||||
namespace zxing {
|
||||
|
||||
Binarizer::Binarizer(Ref<LuminanceSource> source) : source_(source) {
|
||||
Binarizer::Binarizer(Ref<LuminanceSource> source) : source_(source), array_(NULL), matrix_(NULL), cached_y_(-1) {
|
||||
}
|
||||
|
||||
Binarizer::~Binarizer() {
|
||||
}
|
||||
|
||||
Ref<BitArray> Binarizer::getBlackRow(int y, Ref<BitArray> row){
|
||||
if (array_ == NULL)
|
||||
if (array_ == NULL && cached_y_ != y) {
|
||||
array_ = estimateBlackRow(y, row);
|
||||
cached_y_ = y;
|
||||
}
|
||||
return array_;
|
||||
}
|
||||
|
||||
|
|
|
@ -28,24 +28,25 @@
|
|||
#include <zxing/common/Counted.h>
|
||||
|
||||
namespace zxing {
|
||||
|
||||
class Binarizer : public Counted {
|
||||
private:
|
||||
Ref<LuminanceSource> source_;
|
||||
Ref<BitMatrix> matrix_;
|
||||
Ref<BitArray> array_;
|
||||
|
||||
public:
|
||||
Binarizer(Ref<LuminanceSource> source);
|
||||
virtual ~Binarizer();
|
||||
|
||||
virtual Ref<BitArray> estimateBlackRow(int y, Ref<BitArray> row)=0;
|
||||
Ref<BitArray> getBlackRow(int y, Ref<BitArray> row);
|
||||
|
||||
virtual Ref<BitMatrix> estimateBlackMatrix() = 0;
|
||||
Ref<BitMatrix> getBlackMatrix();
|
||||
Ref<LuminanceSource> getSource();
|
||||
};
|
||||
|
||||
|
||||
class Binarizer : public Counted {
|
||||
private:
|
||||
Ref<LuminanceSource> source_;
|
||||
Ref<BitArray> array_;
|
||||
Ref<BitMatrix> matrix_;
|
||||
int cached_y_;
|
||||
|
||||
public:
|
||||
Binarizer(Ref<LuminanceSource> source);
|
||||
virtual ~Binarizer();
|
||||
|
||||
virtual Ref<BitArray> estimateBlackRow(int y, Ref<BitArray> row)=0;
|
||||
Ref<BitArray> getBlackRow(int y, Ref<BitArray> row);
|
||||
|
||||
virtual Ref<BitMatrix> estimateBlackMatrix() = 0;
|
||||
Ref<BitMatrix> getBlackMatrix();
|
||||
Ref<LuminanceSource> getSource();
|
||||
};
|
||||
|
||||
}
|
||||
#endif /* BINARIZER_H_ */
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
|
||||
namespace zxing {
|
||||
|
||||
BinaryBitmap::BinaryBitmap(Ref<Binarizer> binarizer) : bits_(NULL), binarizer_(binarizer) {
|
||||
BinaryBitmap::BinaryBitmap(Ref<Binarizer> binarizer) : bits_(NULL), array_bits_(NULL), binarizer_(binarizer), cached_y_(-1) {
|
||||
|
||||
}
|
||||
|
||||
|
@ -31,8 +31,9 @@ namespace zxing {
|
|||
}
|
||||
|
||||
Ref<BitArray> BinaryBitmap::getBlackRow(int y, Ref<BitArray> row) {
|
||||
if (array_bits_ == NULL) {
|
||||
if (array_bits_ == NULL && cached_y_ != y) {
|
||||
array_bits_ = binarizer_->getBlackRow(y, row);
|
||||
cached_y_ = y;
|
||||
}
|
||||
return array_bits_;
|
||||
}
|
||||
|
|
|
@ -33,6 +33,7 @@ namespace zxing {
|
|||
Ref<BitMatrix> bits_;
|
||||
Ref<BitArray> array_bits_;
|
||||
Ref<Binarizer> binarizer_;
|
||||
int cached_y_;
|
||||
|
||||
public:
|
||||
BinaryBitmap(Ref<Binarizer> binarizer);
|
||||
|
|
|
@ -16,7 +16,7 @@ Exception::Exception(const char *msg) :
|
|||
}
|
||||
|
||||
const char* Exception::what() const throw() {
|
||||
return message;
|
||||
return message.c_str();
|
||||
}
|
||||
|
||||
Exception::~Exception() throw() {
|
||||
|
|
|
@ -28,7 +28,7 @@ namespace zxing {
|
|||
|
||||
class Exception : public std::exception {
|
||||
private:
|
||||
const char * message;
|
||||
std::string message;
|
||||
|
||||
public:
|
||||
Exception(const char *msg);
|
||||
|
|
|
@ -30,10 +30,10 @@ public:
|
|||
LuminanceSource();
|
||||
virtual ~LuminanceSource();
|
||||
|
||||
virtual int getWidth() = 0;
|
||||
virtual int getHeight() = 0;
|
||||
virtual int getWidth() const = 0;
|
||||
virtual int getHeight() const = 0;
|
||||
|
||||
virtual unsigned char getPixel(int x, int y) = 0;
|
||||
virtual unsigned char getPixel(int x, int y) const = 0;
|
||||
virtual unsigned char* copyMatrix();
|
||||
};
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "MultiFormatReader.h"
|
||||
#include <zxing/MultiFormatReader.h>
|
||||
#include <zxing/qrcode/QRCodeReader.h>
|
||||
//#include <zxing/datamatrix/DataMatrixReader.h>
|
||||
#include <zxing/oned/MultiFormatUPCEANReader.h>
|
||||
|
@ -27,28 +27,27 @@
|
|||
#include <zxing/ReaderException.h>
|
||||
|
||||
namespace zxing {
|
||||
MultiFormatReader::MultiFormatReader(){
|
||||
readers = new std::vector<Reader*>();
|
||||
|
||||
readers->push_back(new zxing::qrcode::QRCodeReader());
|
||||
//readers->push_back(new zxing::datamatrix::DataMatrixReader());
|
||||
readers->push_back(new zxing::oned::MultiFormatUPCEANReader());
|
||||
readers->push_back(new zxing::oned::MultiFormatOneDReader());
|
||||
MultiFormatReader::MultiFormatReader() {
|
||||
readers.push_back(new zxing::qrcode::QRCodeReader());
|
||||
//readers.push_back(new zxing::datamatrix::DataMatrixReader());
|
||||
readers.push_back(new zxing::oned::MultiFormatUPCEANReader());
|
||||
readers.push_back(new zxing::oned::MultiFormatOneDReader());
|
||||
}
|
||||
|
||||
Ref<Result> MultiFormatReader::decode(Ref<BinaryBitmap> image){
|
||||
int size = readers->size();
|
||||
for (int i = 0; i < size; i++) {
|
||||
Reader* reader = (*readers)[i];
|
||||
for (unsigned int i = 0; i < readers.size(); i++) {
|
||||
try {
|
||||
return reader->decode(image);
|
||||
return readers[i]->decode(image);
|
||||
} catch (ReaderException re) {
|
||||
// continue
|
||||
}
|
||||
}
|
||||
throw ReaderException("No code detected");
|
||||
}
|
||||
|
||||
MultiFormatReader::~MultiFormatReader(){
|
||||
delete readers;
|
||||
for (unsigned int i = 0; i < readers.size(); i++) {
|
||||
delete readers[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
* ZXing
|
||||
*
|
||||
* Created by Lukasz Warchol on 10-01-26.
|
||||
* Modified by Luiz Silva on 09/02/2010.
|
||||
* Copyright 2010 ZXing authors All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
|
@ -27,12 +28,12 @@ namespace zxing {
|
|||
class MultiFormatReader : public Reader {
|
||||
|
||||
private:
|
||||
std::vector<Reader*>* readers;
|
||||
std::vector<Reader*>readers;
|
||||
public:
|
||||
MultiFormatReader();
|
||||
|
||||
Ref<Result> decode(Ref<BinaryBitmap> image);
|
||||
|
||||
|
||||
~MultiFormatReader();
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,16 +21,17 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <map>
|
||||
#include <zxing/BinaryBitmap.h>
|
||||
#include <zxing/Result.h>
|
||||
|
||||
namespace zxing {
|
||||
|
||||
class Reader {
|
||||
public:
|
||||
virtual Ref<Result> decode(Ref<BinaryBitmap> image) = 0;
|
||||
virtual ~Reader();
|
||||
class Reader : public Counted {
|
||||
protected:
|
||||
Reader() {}
|
||||
public:
|
||||
virtual Ref<Result> decode(Ref<BinaryBitmap> image) = 0;
|
||||
virtual ~Reader();
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -39,11 +39,11 @@ ArrayRef<unsigned char> Result::getRawBytes() {
|
|||
return rawBytes_;
|
||||
}
|
||||
|
||||
std::vector<Ref<ResultPoint> > Result::getResultPoints() {
|
||||
const std::vector<Ref<ResultPoint> >& Result::getResultPoints() const {
|
||||
return resultPoints_;
|
||||
}
|
||||
|
||||
BarcodeFormat Result::getBarcodeFormat() {
|
||||
BarcodeFormat Result::getBarcodeFormat() const {
|
||||
return format_;
|
||||
}
|
||||
|
||||
|
|
|
@ -44,8 +44,8 @@ public:
|
|||
~Result();
|
||||
Ref<String> getText();
|
||||
ArrayRef<unsigned char> getRawBytes();
|
||||
std::vector<Ref<ResultPoint> > getResultPoints();
|
||||
BarcodeFormat getBarcodeFormat();
|
||||
const std::vector<Ref<ResultPoint> >& getResultPoints() const;
|
||||
BarcodeFormat getBarcodeFormat() const;
|
||||
|
||||
friend std::ostream& operator<<(std::ostream &out, Result& result);
|
||||
};
|
||||
|
|
|
@ -26,9 +26,11 @@
|
|||
namespace zxing {
|
||||
|
||||
class ResultPoint : public Counted {
|
||||
protected:
|
||||
ResultPoint() {}
|
||||
public:
|
||||
virtual float getX() = 0;
|
||||
virtual float getY() = 0;
|
||||
virtual float getX() const = 0;
|
||||
virtual float getY() const = 0;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -21,8 +21,7 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <valarray>
|
||||
#include <cstdarg>
|
||||
#include <vector>
|
||||
|
||||
#ifdef DEBUG_COUNTING
|
||||
#include <iostream>
|
||||
|
@ -37,17 +36,17 @@ namespace zxing {
|
|||
template<typename T> class Array : public Counted {
|
||||
protected:
|
||||
public:
|
||||
std::valarray<T> values_;
|
||||
std::vector<T> values_;
|
||||
Array(size_t n) :
|
||||
Counted(), values_(T(), n) {
|
||||
Counted(), values_(n, T()) {
|
||||
}
|
||||
Array(T *ts, size_t n) :
|
||||
Counted(), values_(ts, n) {
|
||||
Counted(), values_(ts, ts+n) {
|
||||
}
|
||||
Array(T v, size_t n) :
|
||||
Counted(), values_(v, n) {
|
||||
Counted(), values_(n, v) {
|
||||
}
|
||||
Array(std::valarray<T> &v) :
|
||||
Array(std::vector<T> &v) :
|
||||
Counted(), values_(v) {
|
||||
}
|
||||
Array(Array<T> &other) :
|
||||
|
@ -68,7 +67,7 @@ public:
|
|||
#endif
|
||||
return *this;
|
||||
}
|
||||
Array<T>& operator=(const std::valarray<T> &array) {
|
||||
Array<T>& operator=(const std::vector<T> &array) {
|
||||
#ifdef DEBUG_COUNTING
|
||||
cout << "assigning values from Array " << &array << " to this Array " << this << ", ";
|
||||
#endif
|
||||
|
@ -87,10 +86,10 @@ public:
|
|||
size_t size() const {
|
||||
return values_.size();
|
||||
}
|
||||
std::valarray<T> values() const {
|
||||
std::vector<T> values() const {
|
||||
return values_;
|
||||
}
|
||||
std::valarray<T>& values() {
|
||||
std::vector<T>& values() {
|
||||
return values_;
|
||||
}
|
||||
};
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
|
||||
#include <zxing/common/BitArray.h>
|
||||
#include <iostream>
|
||||
#include <limits>
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
@ -43,12 +44,9 @@ size_t BitArray::wordsForBits(size_t bits) {
|
|||
}
|
||||
return arraySize;
|
||||
}
|
||||
BitArray::BitArray() {
|
||||
cout << "hey! don't use this BitArrayConstructor!\n";
|
||||
}
|
||||
|
||||
BitArray::BitArray(size_t size) :
|
||||
size_(size), bits_((const unsigned int)0, wordsForBits(size)) {
|
||||
size_(size), bits_(wordsForBits(size), (const unsigned int)0) {
|
||||
}
|
||||
BitArray::~BitArray() {
|
||||
}
|
||||
|
@ -105,14 +103,16 @@ bool BitArray::isRange(size_t start, size_t end, bool value) {
|
|||
}
|
||||
return true;
|
||||
}
|
||||
valarray<unsigned int>& BitArray::getBitArray() {
|
||||
vector<unsigned int>& BitArray::getBitArray() {
|
||||
return bits_;
|
||||
}
|
||||
void BitArray::reverse() {
|
||||
unsigned int allBits = numeric_limits<unsigned int>::max();
|
||||
size_t max = bits_.size();
|
||||
for (size_t i = 0; i < max; i++) {
|
||||
bits_[i] = bits_[i] ^ allBits;
|
||||
std::vector<unsigned int> newBits(bits_.size(),(const unsigned int) 0);
|
||||
for (size_t i = 0; i < size_; i++) {
|
||||
if (get(size_ - i - 1)) {
|
||||
newBits[i >> logBits_] |= 1<< (i & bitsMask_);
|
||||
}
|
||||
}
|
||||
bits_ = newBits;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,8 +23,7 @@
|
|||
|
||||
#include <zxing/common/Counted.h>
|
||||
#include <zxing/common/IllegalArgumentException.h>
|
||||
#include <valarray>
|
||||
#include <limits>
|
||||
#include <vector>
|
||||
#include <iostream>
|
||||
|
||||
namespace zxing {
|
||||
|
@ -32,7 +31,7 @@ namespace zxing {
|
|||
class BitArray : public Counted {
|
||||
private:
|
||||
size_t size_;
|
||||
std::valarray<unsigned int> bits_;
|
||||
std::vector<unsigned int> bits_;
|
||||
static const unsigned int bitsPerWord_;
|
||||
static const unsigned int logBits_;
|
||||
static const unsigned int bitsMask_;
|
||||
|
@ -48,7 +47,7 @@ public:
|
|||
void setBulk(size_t i, unsigned int newBits);
|
||||
void clear();
|
||||
bool isRange(size_t start, size_t end, bool value);
|
||||
std::valarray<unsigned int>& getBitArray();
|
||||
std::vector<unsigned int>& getBitArray();
|
||||
void reverse();
|
||||
};
|
||||
|
||||
|
|
|
@ -24,7 +24,6 @@
|
|||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <cstring>
|
||||
|
||||
namespace zxing {
|
||||
using namespace std;
|
||||
|
@ -40,7 +39,7 @@ unsigned int logDigits(unsigned digits) {
|
|||
}
|
||||
|
||||
|
||||
const unsigned int bitsPerWord = std::numeric_limits<unsigned int>::digits;
|
||||
const unsigned int bitsPerWord = numeric_limits<unsigned int>::digits;
|
||||
const unsigned int logBits = logDigits(bitsPerWord);
|
||||
const unsigned int bitsMask = (1 << logBits) - 1;
|
||||
|
||||
|
@ -54,7 +53,7 @@ static size_t wordsForSize(size_t width, size_t height) {
|
|||
}
|
||||
|
||||
BitMatrix::BitMatrix(size_t dimension) :
|
||||
width_(dimension), height_(dimension), bits_(NULL) {
|
||||
width_(dimension), height_(dimension), words_(0), bits_(NULL) {
|
||||
|
||||
words_ = wordsForSize(width_, height_);
|
||||
bits_ = new unsigned int[words_];
|
||||
|
@ -62,7 +61,7 @@ BitMatrix::BitMatrix(size_t dimension) :
|
|||
}
|
||||
|
||||
BitMatrix::BitMatrix(size_t width, size_t height) :
|
||||
width_(width), height_(height), bits_(NULL) {
|
||||
width_(width), height_(height), words_(0), bits_(NULL) {
|
||||
|
||||
words_ = wordsForSize(width_, height_);
|
||||
bits_ = new unsigned int[words_];
|
||||
|
@ -90,7 +89,7 @@ void BitMatrix::flip(size_t x, size_t y) {
|
|||
}
|
||||
|
||||
void BitMatrix::clear() {
|
||||
std::memset(bits_, 0, sizeof(unsigned int) * words_);
|
||||
std::fill(bits_, bits_+words_, 0);
|
||||
}
|
||||
|
||||
void BitMatrix::setRegion(size_t left, size_t top, size_t width, size_t height) {
|
||||
|
@ -126,11 +125,11 @@ size_t BitMatrix::getDimension() const {
|
|||
return width_;
|
||||
}
|
||||
|
||||
unsigned int* BitMatrix::getBits() {
|
||||
unsigned int* BitMatrix::getBits() const {
|
||||
return bits_;
|
||||
}
|
||||
|
||||
ostream& operator<<(ostream &out, BitMatrix &bm) {
|
||||
ostream& operator<<(ostream &out, const BitMatrix &bm) {
|
||||
for (size_t y = 0; y < bm.height_; y++) {
|
||||
for (size_t x = 0; x < bm.width_; x++) {
|
||||
out << (bm.get(x, y) ? "X " : " ");
|
||||
|
|
|
@ -22,7 +22,6 @@
|
|||
*/
|
||||
|
||||
#include <zxing/common/Counted.h>
|
||||
#include <valarray>
|
||||
#include <limits>
|
||||
|
||||
namespace zxing {
|
||||
|
@ -50,10 +49,14 @@ public:
|
|||
size_t getWidth() const;
|
||||
size_t getHeight() const;
|
||||
|
||||
unsigned int* getBits();
|
||||
unsigned int* getBits() const;
|
||||
|
||||
friend std::ostream& operator<<(std::ostream &out, BitMatrix &bm);
|
||||
friend std::ostream& operator<<(std::ostream &out, const BitMatrix &bm);
|
||||
const char *description();
|
||||
|
||||
private:
|
||||
BitMatrix(const BitMatrix&);
|
||||
BitMatrix& operator =(const BitMatrix&);
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -172,10 +172,10 @@ public:
|
|||
T& operator*() {
|
||||
return *object_;
|
||||
}
|
||||
T* operator->() {
|
||||
T* operator->() const {
|
||||
return object_;
|
||||
}
|
||||
operator T*() {
|
||||
operator T*() const {
|
||||
return object_;
|
||||
}
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
|
||||
#include <zxing/common/EdgeDetector.h>
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
|
|
@ -24,154 +24,160 @@
|
|||
#include <zxing/common/IllegalArgumentException.h>
|
||||
|
||||
namespace zxing {
|
||||
using namespace std;
|
||||
|
||||
const int LUMINANCE_BITS = 5;
|
||||
const int LUMINANCE_SHIFT = 8 - LUMINANCE_BITS;
|
||||
const int LUMINANCE_BUCKETS = 1 << LUMINANCE_BITS;
|
||||
|
||||
GlobalHistogramBinarizer::GlobalHistogramBinarizer(Ref<LuminanceSource> source) :
|
||||
Binarizer(source) {
|
||||
|
||||
}
|
||||
|
||||
GlobalHistogramBinarizer::~GlobalHistogramBinarizer() {
|
||||
}
|
||||
|
||||
|
||||
Ref<BitArray> GlobalHistogramBinarizer::estimateBlackRow(int y, Ref<BitArray> row){
|
||||
valarray<int> histogram(0, LUMINANCE_BUCKETS);
|
||||
LuminanceSource& source = *getSource();
|
||||
int width = source.getWidth();
|
||||
if (row == NULL || row->getSize() < width) {
|
||||
row = new BitArray(width);
|
||||
} else {
|
||||
row->clear();
|
||||
}
|
||||
|
||||
for (int x = 0; x < width; x++) {
|
||||
unsigned char pixel = source.getPixel(x, y);
|
||||
histogram[pixel >> LUMINANCE_SHIFT]++;
|
||||
}
|
||||
int blackPoint = estimate(histogram) << LUMINANCE_SHIFT;
|
||||
|
||||
|
||||
Ref<BitArray> array_ref(new BitArray(width));
|
||||
BitArray& array = *array_ref;
|
||||
|
||||
int left = source.getPixel(0, y);
|
||||
int center = source.getPixel(1, y);
|
||||
for (int x = 1; x < width - 1; x++) {
|
||||
int right = source.getPixel(x+1, y);
|
||||
// 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;
|
||||
}
|
||||
|
||||
return array_ref;
|
||||
}
|
||||
|
||||
Ref<BitMatrix> GlobalHistogramBinarizer::estimateBlackMatrix() {
|
||||
// Faster than working with the reference
|
||||
LuminanceSource& source = *getSource();
|
||||
int width = source.getWidth();
|
||||
int height = source.getHeight();
|
||||
valarray<int> histogram(0, LUMINANCE_BUCKETS);
|
||||
|
||||
|
||||
// Quickly calculates the histogram by sampling four rows from the image. This proved to be
|
||||
// more robust on the blackbox tests than sampling a diagonal as we used to do.
|
||||
for (int y = 1; y < 5; y++) {
|
||||
int row = height * y / 5;
|
||||
int right = (width << 2) / 5;
|
||||
int sdf;
|
||||
for (int x = width / 5; x < right; x++) {
|
||||
unsigned char pixel = source.getPixel(x, row);
|
||||
histogram[pixel >> LUMINANCE_SHIFT]++;
|
||||
sdf = histogram[pixel >> LUMINANCE_SHIFT];
|
||||
}
|
||||
}
|
||||
|
||||
int blackPoint = estimate(histogram) << LUMINANCE_SHIFT;
|
||||
|
||||
Ref<BitMatrix> matrix_ref(new BitMatrix(width, height));
|
||||
BitMatrix& matrix = *matrix_ref;
|
||||
for (int y = 0; y < height; y++) {
|
||||
for (int x = 0; x < width; x++) {
|
||||
if (source.getPixel(x, y) <= blackPoint)
|
||||
matrix.set(x, y);
|
||||
}
|
||||
}
|
||||
return matrix_ref;
|
||||
}
|
||||
|
||||
int GlobalHistogramBinarizer::estimate(valarray<int> &histogram) {
|
||||
int numBuckets = histogram.size();
|
||||
int maxBucketCount = 0;
|
||||
|
||||
|
||||
// Find tallest peak in histogram
|
||||
int firstPeak = 0;
|
||||
int firstPeakSize = 0;
|
||||
for (int i = 0; i < numBuckets; i++) {
|
||||
if (histogram[i] > firstPeakSize) {
|
||||
firstPeak = i;
|
||||
firstPeakSize = histogram[i];
|
||||
}
|
||||
if (histogram[i] > maxBucketCount) {
|
||||
maxBucketCount = histogram[i];
|
||||
}
|
||||
}
|
||||
|
||||
// Find second-tallest peak -- well, another peak that is tall and not
|
||||
// so close to the first one
|
||||
int secondPeak = 0;
|
||||
int secondPeakScore = 0;
|
||||
for (int i = 0; i < numBuckets; i++) {
|
||||
int distanceToBiggest = i - firstPeak;
|
||||
// Encourage more distant second peaks by multiplying by square of distance
|
||||
int score = histogram[i] * distanceToBiggest * distanceToBiggest;
|
||||
if (score > secondPeakScore) {
|
||||
secondPeak = i;
|
||||
secondPeakScore = score;
|
||||
}
|
||||
}
|
||||
|
||||
// Put firstPeak first
|
||||
if (firstPeak > secondPeak) {
|
||||
int temp = firstPeak;
|
||||
firstPeak = secondPeak;
|
||||
secondPeak = temp;
|
||||
}
|
||||
|
||||
// Kind of arbitrary; if the two peaks are very close, then we figure there is so little
|
||||
// dynamic range in the image, that discriminating black and white is too error-prone.
|
||||
// Decoding the image/line is either pointless, or may in some cases lead to a false positive
|
||||
// for 1D formats, which are relatively lenient.
|
||||
// We arbitrarily say "close" is "<= 1/16 of the total histogram buckets apart"
|
||||
if (secondPeak - firstPeak <= numBuckets >> 4) {
|
||||
throw IllegalArgumentException("Too little dynamic range in luminance");
|
||||
}
|
||||
|
||||
// Find a valley between them that is low and closer to the white peak
|
||||
int bestValley = secondPeak - 1;
|
||||
int bestValleyScore = -1;
|
||||
for (int i = secondPeak - 1; i > firstPeak; i--) {
|
||||
int fromFirst = i - firstPeak;
|
||||
// Favor a "valley" that is not too close to either peak -- especially not the black peak --
|
||||
// and that has a low value of course
|
||||
int score = fromFirst * fromFirst * (secondPeak - i) * (maxBucketCount - histogram[i]);
|
||||
if (score > bestValleyScore) {
|
||||
bestValley = i;
|
||||
bestValleyScore = score;
|
||||
}
|
||||
}
|
||||
|
||||
return bestValley;
|
||||
}
|
||||
|
||||
using namespace std;
|
||||
|
||||
const int LUMINANCE_BITS = 5;
|
||||
const int LUMINANCE_SHIFT = 8 - LUMINANCE_BITS;
|
||||
const int LUMINANCE_BUCKETS = 1 << LUMINANCE_BITS;
|
||||
|
||||
GlobalHistogramBinarizer::GlobalHistogramBinarizer(Ref<LuminanceSource> source) :
|
||||
Binarizer(source) {
|
||||
|
||||
}
|
||||
|
||||
GlobalHistogramBinarizer::~GlobalHistogramBinarizer() {
|
||||
}
|
||||
|
||||
|
||||
Ref<BitArray> GlobalHistogramBinarizer::estimateBlackRow(int y,
|
||||
Ref<BitArray> row){
|
||||
vector<int> histogram(LUMINANCE_BUCKETS, 0);
|
||||
LuminanceSource& source = *getSource();
|
||||
int width = source.getWidth();
|
||||
if (row == NULL || static_cast<int>(row->getSize()) < width) {
|
||||
row = new BitArray(width);
|
||||
} else {
|
||||
row->clear();
|
||||
}
|
||||
|
||||
for (int x = 0; x < width; x++) {
|
||||
unsigned char pixel = source.getPixel(x, y);
|
||||
histogram[pixel >> LUMINANCE_SHIFT]++;
|
||||
}
|
||||
int blackPoint = estimate(histogram) << LUMINANCE_SHIFT;
|
||||
|
||||
|
||||
Ref<BitArray> array_ref(new BitArray(width));
|
||||
BitArray& array = *array_ref;
|
||||
|
||||
int left = source.getPixel(0, y);
|
||||
int center = source.getPixel(1, y);
|
||||
for (int x = 1; x < width - 1; x++) {
|
||||
int right = source.getPixel(x+1, y);
|
||||
// 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;
|
||||
}
|
||||
|
||||
return array_ref;
|
||||
}
|
||||
|
||||
Ref<BitMatrix> GlobalHistogramBinarizer::estimateBlackMatrix() {
|
||||
// Faster than working with the reference
|
||||
LuminanceSource& source = *getSource();
|
||||
int width = source.getWidth();
|
||||
int height = source.getHeight();
|
||||
vector<int> histogram(LUMINANCE_BUCKETS, 0);
|
||||
|
||||
|
||||
// Quickly calculates the histogram by sampling four rows from the image.
|
||||
// This proved to be more robust on the blackbox tests than sampling a
|
||||
// diagonal as we used to do.
|
||||
for (int y = 1; y < 5; y++) {
|
||||
int row = height * y / 5;
|
||||
int right = (width << 2) / 5;
|
||||
int sdf;
|
||||
for (int x = width / 5; x < right; x++) {
|
||||
unsigned char pixel = source.getPixel(x, row);
|
||||
histogram[pixel >> LUMINANCE_SHIFT]++;
|
||||
sdf = histogram[pixel >> LUMINANCE_SHIFT];
|
||||
}
|
||||
}
|
||||
|
||||
int blackPoint = estimate(histogram) << LUMINANCE_SHIFT;
|
||||
|
||||
Ref<BitMatrix> matrix_ref(new BitMatrix(width, height));
|
||||
BitMatrix& matrix = *matrix_ref;
|
||||
for (int y = 0; y < height; y++) {
|
||||
for (int x = 0; x < width; x++) {
|
||||
if (source.getPixel(x, y) <= blackPoint)
|
||||
matrix.set(x, y);
|
||||
}
|
||||
}
|
||||
return matrix_ref;
|
||||
}
|
||||
|
||||
int GlobalHistogramBinarizer::estimate(vector<int> &histogram) {
|
||||
int numBuckets = histogram.size();
|
||||
int maxBucketCount = 0;
|
||||
|
||||
|
||||
// Find tallest peak in histogram
|
||||
int firstPeak = 0;
|
||||
int firstPeakSize = 0;
|
||||
for (int i = 0; i < numBuckets; i++) {
|
||||
if (histogram[i] > firstPeakSize) {
|
||||
firstPeak = i;
|
||||
firstPeakSize = histogram[i];
|
||||
}
|
||||
if (histogram[i] > maxBucketCount) {
|
||||
maxBucketCount = histogram[i];
|
||||
}
|
||||
}
|
||||
|
||||
// Find second-tallest peak -- well, another peak that is tall and not
|
||||
// so close to the first one
|
||||
int secondPeak = 0;
|
||||
int secondPeakScore = 0;
|
||||
for (int i = 0; i < numBuckets; i++) {
|
||||
int distanceToBiggest = i - firstPeak;
|
||||
// Encourage more distant second peaks by multiplying by square of distance
|
||||
int score = histogram[i] * distanceToBiggest * distanceToBiggest;
|
||||
if (score > secondPeakScore) {
|
||||
secondPeak = i;
|
||||
secondPeakScore = score;
|
||||
}
|
||||
}
|
||||
|
||||
// Put firstPeak first
|
||||
if (firstPeak > secondPeak) {
|
||||
int temp = firstPeak;
|
||||
firstPeak = secondPeak;
|
||||
secondPeak = temp;
|
||||
}
|
||||
|
||||
// Kind of arbitrary; if the two peaks are very close, then we figure there is
|
||||
// so little dynamic range in the image, that discriminating black and white
|
||||
// is too error-prone.
|
||||
// Decoding the image/line is either pointless, or may in some cases lead to
|
||||
// a false positive for 1D formats, which are relatively lenient.
|
||||
// We arbitrarily say "close" is
|
||||
// "<= 1/16 of the total histogram buckets apart"
|
||||
if (secondPeak - firstPeak <= numBuckets >> 4) {
|
||||
throw IllegalArgumentException("Too little dynamic range in luminance");
|
||||
}
|
||||
|
||||
// Find a valley between them that is low and closer to the white peak
|
||||
int bestValley = secondPeak - 1;
|
||||
int bestValleyScore = -1;
|
||||
for (int i = secondPeak - 1; i > firstPeak; i--) {
|
||||
int fromFirst = i - firstPeak;
|
||||
// Favor a "valley" that is not too close to either peak -- especially not
|
||||
// the black peak -- and that has a low value of course
|
||||
int score = fromFirst * fromFirst * (secondPeak - i) *
|
||||
(maxBucketCount - histogram[i]);
|
||||
if (score > bestValleyScore) {
|
||||
bestValley = i;
|
||||
bestValleyScore = score;
|
||||
}
|
||||
}
|
||||
|
||||
return bestValley;
|
||||
}
|
||||
|
||||
} // namespace zxing
|
||||
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
#ifndef GLOBALHISTOGRAMBINARIZER_H_
|
||||
#define GLOBALHISTOGRAMBINARIZER_H_
|
||||
|
||||
#include <valarray>
|
||||
#include <vector>
|
||||
#include <zxing/Binarizer.h>
|
||||
#include <zxing/common/BitArray.h>
|
||||
#include <zxing/common/BitMatrix.h>
|
||||
|
@ -36,7 +36,7 @@ namespace zxing {
|
|||
|
||||
virtual Ref<BitArray> estimateBlackRow(int y, Ref<BitArray> row);
|
||||
virtual Ref<BitMatrix> estimateBlackMatrix();
|
||||
static int estimate(std::valarray<int> &histogram);
|
||||
static int estimate(std::vector<int> &histogram);
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -34,7 +34,7 @@ GridSampler::GridSampler() {
|
|||
|
||||
Ref<BitMatrix> GridSampler::sampleGrid(Ref<BitMatrix> image, int dimension, Ref<PerspectiveTransform> transform) {
|
||||
Ref<BitMatrix> bits(new BitMatrix(dimension));
|
||||
valarray<float> points((const float)0.0f, dimension << 1);
|
||||
vector<float> points(dimension << 1, (const float)0.0f);
|
||||
for (int y = 0; y < dimension; y++) {
|
||||
int max = points.size();
|
||||
float yValue = (float)y + 0.5f;
|
||||
|
@ -63,7 +63,7 @@ Ref<BitMatrix> GridSampler::sampleGrid(Ref<BitMatrix> image, int dimension, floa
|
|||
|
||||
}
|
||||
|
||||
void GridSampler::checkAndNudgePoints(Ref<BitMatrix> image, valarray<float> &points) {
|
||||
void GridSampler::checkAndNudgePoints(Ref<BitMatrix> image, vector<float> &points) {
|
||||
int width = image->getWidth();
|
||||
int height = image->getHeight();
|
||||
|
||||
|
|
|
@ -36,7 +36,7 @@ public:
|
|||
Ref<BitMatrix> sampleGrid(Ref<BitMatrix> image, int dimension, float p1ToX, float p1ToY, float p2ToX, float p2ToY,
|
||||
float p3ToX, float p3ToY, float p4ToX, float p4ToY, float p1FromX, float p1FromY, float p2FromX,
|
||||
float p2FromY, float p3FromX, float p3FromY, float p4FromX, float p4FromY);
|
||||
static void checkAndNudgePoints(Ref<BitMatrix> image, std::valarray<float> &points);
|
||||
static void checkAndNudgePoints(Ref<BitMatrix> image, std::vector<float> &points);
|
||||
static GridSampler &getInstance();
|
||||
};
|
||||
}
|
||||
|
|
|
@ -23,18 +23,13 @@
|
|||
namespace zxing {
|
||||
using namespace std;
|
||||
|
||||
PerspectiveTransform::PerspectiveTransform(float a11, float a21, float a31, float a12, float a22, float a32, float a13,
|
||||
float a23, float a33) {
|
||||
this->a11 = a11;
|
||||
this->a12 = a12;
|
||||
this->a13 = a13;
|
||||
this->a21 = a21;
|
||||
this->a22 = a22;
|
||||
this->a23 = a23;
|
||||
this->a31 = a31;
|
||||
this->a32 = a32;
|
||||
this->a33 = a33;
|
||||
}
|
||||
PerspectiveTransform::PerspectiveTransform(float inA11, float inA21,
|
||||
float inA31, float inA12,
|
||||
float inA22, float inA32,
|
||||
float inA13, float inA23,
|
||||
float inA33) :
|
||||
a11(inA11), a12(inA12), a13(inA13), a21(inA21), a22(inA22), a23(inA23),
|
||||
a31(inA31), a32(inA32), a33(inA33) {}
|
||||
|
||||
Ref<PerspectiveTransform> PerspectiveTransform::quadrilateralToQuadrilateral(float x0, float y0, float x1, float y1,
|
||||
float x2, float y2, float x3, float y3, float x0p, float y0p, float x1p, float y1p, float x2p, float y2p,
|
||||
|
@ -91,17 +86,8 @@ Ref<PerspectiveTransform> PerspectiveTransform::times(Ref<PerspectiveTransform>
|
|||
return result;
|
||||
}
|
||||
|
||||
void PerspectiveTransform::transformPoints(valarray<float> &points) {
|
||||
void PerspectiveTransform::transformPoints(vector<float> &points) {
|
||||
int max = points.size();
|
||||
float a11 = this->a11;
|
||||
float a12 = this->a12;
|
||||
float a13 = this->a13;
|
||||
float a21 = this->a21;
|
||||
float a22 = this->a22;
|
||||
float a23 = this->a23;
|
||||
float a31 = this->a31;
|
||||
float a32 = this->a32;
|
||||
float a33 = this->a33;
|
||||
for (int i = 0; i < max; i += 2) {
|
||||
float x = points[i];
|
||||
float y = points[i + 1];
|
||||
|
@ -111,7 +97,7 @@ void PerspectiveTransform::transformPoints(valarray<float> &points) {
|
|||
}
|
||||
}
|
||||
|
||||
ostream& operator<<(ostream& out, PerspectiveTransform &pt) {
|
||||
ostream& operator<<(ostream& out, const PerspectiveTransform &pt) {
|
||||
out << pt.a11 << ", " << pt.a12 << ", " << pt.a13 << ", \n";
|
||||
out << pt.a21 << ", " << pt.a22 << ", " << pt.a23 << ", \n";
|
||||
out << pt.a31 << ", " << pt.a32 << ", " << pt.a33 << "\n";
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
*/
|
||||
|
||||
#include <zxing/common/Counted.h>
|
||||
#include <valarray>
|
||||
#include <vector>
|
||||
|
||||
namespace zxing {
|
||||
class PerspectiveTransform : public Counted {
|
||||
|
@ -41,9 +41,9 @@ public:
|
|||
float x3, float y3);
|
||||
Ref<PerspectiveTransform> buildAdjoint();
|
||||
Ref<PerspectiveTransform> times(Ref<PerspectiveTransform> other);
|
||||
void transformPoints(std::valarray<float> &points);
|
||||
void transformPoints(std::vector<float> &points);
|
||||
|
||||
friend std::ostream& operator<<(std::ostream& out, PerspectiveTransform &pt);
|
||||
friend std::ostream& operator<<(std::ostream& out, const PerspectiveTransform &pt);
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -18,10 +18,10 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef ZXING_POINT_H_
|
||||
#define ZXING_POINT_H_
|
||||
#ifndef ZXING_POINT_H_
|
||||
#define ZXING_POINT_H_
|
||||
|
||||
namespace zxing {
|
||||
namespace zxing {
|
||||
class PointI {
|
||||
public:
|
||||
int x;
|
||||
|
@ -30,6 +30,7 @@ public:
|
|||
|
||||
class Point {
|
||||
public:
|
||||
Point() : x(0.0f), y(0.0f) {};
|
||||
Point(float x_, float y_) : x(x_), y(y_) {};
|
||||
|
||||
float x;
|
||||
|
@ -42,6 +43,6 @@ public:
|
|||
|
||||
Point start;
|
||||
Point end;
|
||||
};
|
||||
}
|
||||
#endif // POINT_H_
|
||||
};
|
||||
}
|
||||
#endif // POINT_H_
|
||||
|
|
|
@ -26,7 +26,7 @@ using namespace std;
|
|||
String::String(const std::string &text) :
|
||||
text_(text) {
|
||||
}
|
||||
std::string& String::getText() {
|
||||
const std::string& String::getText() const {
|
||||
return text_;
|
||||
}
|
||||
|
||||
|
|
|
@ -32,7 +32,7 @@ private:
|
|||
std::string text_;
|
||||
public:
|
||||
String(const std::string &text);
|
||||
std::string &getText();
|
||||
const std::string &getText() const;
|
||||
friend std::ostream &operator<<(std::ostream &out, const String &s);
|
||||
};
|
||||
|
||||
|
|
|
@ -18,7 +18,6 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <valarray>
|
||||
#include <vector>
|
||||
#include <iostream>
|
||||
#include <zxing/common/reedsolomon/GF256.h>
|
||||
|
@ -42,7 +41,7 @@ static inline Ref<GF256Poly> refPoly(GF256 &field, int value) {
|
|||
}
|
||||
|
||||
GF256::GF256(int primitive) :
|
||||
exp_((const int)0, 256), log_((const int)0, 256), zero_(refPoly(*this, 0)), one_(refPoly(*this, 1)) {
|
||||
exp_(256, (const int)0), log_(256, (const int)0), zero_(refPoly(*this, 0)), one_(refPoly(*this, 1)) {
|
||||
int x = 1;
|
||||
for (int i = 0; i < 256; i++) {
|
||||
exp_[i] = x;
|
||||
|
@ -110,13 +109,10 @@ int GF256::multiply(int a, int b) {
|
|||
if (a == 0 || b == 0) {
|
||||
return 0;
|
||||
}
|
||||
if (a == 1) {
|
||||
return b;
|
||||
}
|
||||
if (b == 1) {
|
||||
return a;
|
||||
}
|
||||
return exp_[(log_[a] + log_[b]) % 255];
|
||||
int logSum = log_[a] + log_[b];
|
||||
// index is a sped-up alternative to logSum % 255 since sum
|
||||
// is in [0,510]. Thanks to jmsachs for the idea
|
||||
return exp_[(logSum & 0xFF) + (logSum >> 8)];
|
||||
}
|
||||
|
||||
GF256 GF256::QR_CODE_FIELD(0x011D); // x^8 + x^4 + x^3 + x^2 + 1
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
*/
|
||||
|
||||
#include <memory>
|
||||
#include <valarray>
|
||||
#include <vector>
|
||||
#include <zxing/common/Counted.h>
|
||||
|
||||
namespace zxing {
|
||||
|
@ -42,8 +42,8 @@ class GF256 {
|
|||
* @author christian.brunschen@gmail.com (Christian Brunschen)
|
||||
*/
|
||||
private:
|
||||
std::valarray<int> exp_;
|
||||
std::valarray<int> log_;
|
||||
std::vector<int> exp_;
|
||||
std::vector<int> log_;
|
||||
Ref<GF256Poly> zero_;
|
||||
Ref<GF256Poly> one_;
|
||||
|
||||
|
|
|
@ -0,0 +1,82 @@
|
|||
/*
|
||||
* DataMatrixReader.cpp
|
||||
* zxing
|
||||
*
|
||||
* Created by Luiz Silva on 09/02/2010.
|
||||
* Copyright 2010 ZXing authors All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <zxing/datamatrix/DataMatrixReader.h>
|
||||
#include <zxing/datamatrix/detector/Detector.h>
|
||||
#include <iostream>
|
||||
|
||||
namespace zxing {
|
||||
namespace datamatrix {
|
||||
|
||||
using namespace std;
|
||||
|
||||
DataMatrixReader::DataMatrixReader() :
|
||||
decoder_() {
|
||||
}
|
||||
|
||||
Ref<Result> DataMatrixReader::decode(Ref<BinaryBitmap> image) {
|
||||
#ifdef DEBUG
|
||||
cout << "decoding image " << image.object_ << ":\n" << flush;
|
||||
#endif
|
||||
|
||||
Detector detector(image->getBlackMatrix());
|
||||
|
||||
|
||||
#ifdef DEBUG
|
||||
cout << "(1) created detector " << &detector << "\n" << flush;
|
||||
#endif
|
||||
|
||||
Ref<DetectorResult> detectorResult(detector.detect());
|
||||
#ifdef DEBUG
|
||||
cout << "(2) detected, have detectorResult " << detectorResult.object_ << "\n" << flush;
|
||||
#endif
|
||||
|
||||
std::vector<Ref<ResultPoint> > points(detectorResult->getPoints());
|
||||
|
||||
|
||||
#ifdef DEBUG
|
||||
cout << "(3) extracted points " << &points << "\n" << flush;
|
||||
cout << "found " << points.size() << " points:\n";
|
||||
for (size_t i = 0; i < points.size(); i++) {
|
||||
cout << " " << points[i]->getX() << "," << points[i]->getY() << "\n";
|
||||
}
|
||||
cout << "bits:\n";
|
||||
cout << *(detectorResult->getBits()) << "\n";
|
||||
#endif
|
||||
|
||||
Ref<DecoderResult> decoderResult(decoder_.decode(detectorResult->getBits()));
|
||||
#ifdef DEBUG
|
||||
cout << "(4) decoded, have decoderResult " << decoderResult.object_ << "\n" << flush;
|
||||
#endif
|
||||
|
||||
Ref<Result> result(
|
||||
new Result(decoderResult->getText(), decoderResult->getRawBytes(), points, BarcodeFormat_DATA_MATRIX));
|
||||
#ifdef DEBUG
|
||||
cout << "(5) created result " << result.object_ << ", returning\n" << flush;
|
||||
#endif
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
DataMatrixReader::~DataMatrixReader() {
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
#ifndef __DATA_MATRIX_READER_H__
|
||||
#define __DATA_MATRIX_READER_H__
|
||||
|
||||
/*
|
||||
* DataMatrixReader.h
|
||||
* zxing
|
||||
*
|
||||
* Created by Luiz Silva on 09/02/2010.
|
||||
* Copyright 2010 ZXing authors All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <zxing/Reader.h>
|
||||
#include <zxing/datamatrix/decoder/Decoder.h>
|
||||
|
||||
namespace zxing {
|
||||
namespace datamatrix {
|
||||
|
||||
class DataMatrixReader : public Reader {
|
||||
private:
|
||||
Decoder decoder_;
|
||||
|
||||
public:
|
||||
DataMatrixReader();
|
||||
virtual Ref<Result> decode(Ref<BinaryBitmap> image);
|
||||
virtual ~DataMatrixReader();
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif // __DATA_MATRIX_READER_H__
|
199
symbian/ZXingBarcodeReader/group/zxing/datamatrix/Version.cpp
Normal file
199
symbian/ZXingBarcodeReader/group/zxing/datamatrix/Version.cpp
Normal file
|
@ -0,0 +1,199 @@
|
|||
/*
|
||||
* Version.cpp
|
||||
* zxing
|
||||
*
|
||||
* Created by Luiz Silva on 09/02/2010.
|
||||
* Copyright 2010 ZXing authors All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <zxing/datamatrix/Version.h>
|
||||
#include <limits>
|
||||
#include <iostream>
|
||||
|
||||
namespace zxing {
|
||||
namespace datamatrix {
|
||||
using namespace std;
|
||||
|
||||
ECB::ECB(int count, int dataCodewords) :
|
||||
count_(count), dataCodewords_(dataCodewords) {
|
||||
}
|
||||
|
||||
int ECB::getCount() {
|
||||
return count_;
|
||||
}
|
||||
|
||||
int ECB::getDataCodewords() {
|
||||
return dataCodewords_;
|
||||
}
|
||||
|
||||
ECBlocks::ECBlocks(int ecCodewords, ECB *ecBlocks) :
|
||||
ecCodewords_(ecCodewords), ecBlocks_(1, ecBlocks) {
|
||||
}
|
||||
|
||||
ECBlocks::ECBlocks(int ecCodewords, ECB *ecBlocks1, ECB *ecBlocks2) :
|
||||
ecCodewords_(ecCodewords), ecBlocks_(1, ecBlocks1) {
|
||||
ecBlocks_.push_back(ecBlocks2);
|
||||
}
|
||||
|
||||
int ECBlocks::getECCodewords() {
|
||||
return ecCodewords_;
|
||||
}
|
||||
|
||||
std::vector<ECB*>& ECBlocks::getECBlocks() {
|
||||
return ecBlocks_;
|
||||
}
|
||||
|
||||
ECBlocks::~ECBlocks() {
|
||||
for (size_t i = 0; i < ecBlocks_.size(); i++) {
|
||||
delete ecBlocks_[i];
|
||||
}
|
||||
}
|
||||
|
||||
vector<Ref<Version> > Version::VERSIONS;
|
||||
static int N_VERSIONS = Version::buildVersions();
|
||||
|
||||
Version::Version(int versionNumber, int symbolSizeRows, int symbolSizeColumns, int dataRegionSizeRows,
|
||||
int dataRegionSizeColumns, ECBlocks* ecBlocks) : versionNumber_(versionNumber),
|
||||
symbolSizeRows_(symbolSizeRows), symbolSizeColumns_(symbolSizeColumns),
|
||||
dataRegionSizeRows_(dataRegionSizeRows), dataRegionSizeColumns_(dataRegionSizeColumns),
|
||||
ecBlocks_(ecBlocks), totalCodewords_(0) {
|
||||
// Calculate the total number of codewords
|
||||
int total = 0;
|
||||
int ecCodewords = ecBlocks_->getECCodewords();
|
||||
vector<ECB*> &ecbArray = ecBlocks_->getECBlocks();
|
||||
for (unsigned int i = 0; i < ecbArray.size(); i++) {
|
||||
ECB *ecBlock = ecbArray[i];
|
||||
total += ecBlock->getCount() * (ecBlock->getDataCodewords() + ecCodewords);
|
||||
}
|
||||
totalCodewords_ = total;
|
||||
}
|
||||
|
||||
Version::~Version() {
|
||||
delete ecBlocks_;
|
||||
}
|
||||
|
||||
int Version::getVersionNumber() {
|
||||
return versionNumber_;
|
||||
}
|
||||
|
||||
int Version::getSymbolSizeRows() {
|
||||
return symbolSizeRows_;
|
||||
}
|
||||
|
||||
int Version::getSymbolSizeColumns() {
|
||||
return symbolSizeColumns_;
|
||||
}
|
||||
|
||||
int Version::getDataRegionSizeRows() {
|
||||
return dataRegionSizeRows_;
|
||||
}
|
||||
|
||||
int Version::getDataRegionSizeColumns() {
|
||||
return dataRegionSizeColumns_;
|
||||
}
|
||||
|
||||
int Version::getTotalCodewords() {
|
||||
return totalCodewords_;
|
||||
}
|
||||
|
||||
ECBlocks* Version::getECBlocks() {
|
||||
return ecBlocks_;
|
||||
}
|
||||
|
||||
Ref<Version> Version::getVersionForDimensions(int numRows, int numColumns) {
|
||||
if ((numRows & 0x01) != 0 || (numColumns & 0x01) != 0) {
|
||||
throw ReaderException("Number of rows and columns must be even");
|
||||
}
|
||||
|
||||
// TODO(bbrown): This is doing a linear search through the array of versions.
|
||||
// If we interleave the rectangular versions with the square versions we could
|
||||
// do a binary search.
|
||||
for (int i = 0; i < N_VERSIONS; ++i){
|
||||
Ref<Version> version(VERSIONS[i]);
|
||||
if (version->getSymbolSizeRows() == numRows && version->getSymbolSizeColumns() == numColumns) {
|
||||
return version;
|
||||
}
|
||||
}
|
||||
throw ReaderException("Error version not found");
|
||||
}
|
||||
|
||||
/**
|
||||
* See ISO 16022:2006 5.5.1 Table 7
|
||||
*/
|
||||
int Version::buildVersions() {
|
||||
VERSIONS.push_back(Ref<Version>(new Version(1, 10, 10, 8, 8,
|
||||
new ECBlocks(5, new ECB(1, 3)))));
|
||||
VERSIONS.push_back(Ref<Version>(new Version(2, 12, 12, 10, 10,
|
||||
new ECBlocks(7, new ECB(1, 5)))));
|
||||
VERSIONS.push_back(Ref<Version>(new Version(3, 14, 14, 12, 12,
|
||||
new ECBlocks(10, new ECB(1, 8)))));
|
||||
VERSIONS.push_back(Ref<Version>(new Version(4, 16, 16, 14, 14,
|
||||
new ECBlocks(12, new ECB(1, 12)))));
|
||||
VERSIONS.push_back(Ref<Version>(new Version(5, 18, 18, 16, 16,
|
||||
new ECBlocks(14, new ECB(1, 18)))));
|
||||
VERSIONS.push_back(Ref<Version>(new Version(6, 20, 20, 18, 18,
|
||||
new ECBlocks(18, new ECB(1, 22)))));
|
||||
VERSIONS.push_back(Ref<Version>(new Version(7, 22, 22, 20, 20,
|
||||
new ECBlocks(20, new ECB(1, 30)))));
|
||||
VERSIONS.push_back(Ref<Version>(new Version(8, 24, 24, 22, 22,
|
||||
new ECBlocks(24, new ECB(1, 36)))));
|
||||
VERSIONS.push_back(Ref<Version>(new Version(9, 26, 26, 24, 24,
|
||||
new ECBlocks(28, new ECB(1, 44)))));
|
||||
VERSIONS.push_back(Ref<Version>(new Version(10, 32, 32, 14, 14,
|
||||
new ECBlocks(36, new ECB(1, 62)))));
|
||||
VERSIONS.push_back(Ref<Version>(new Version(11, 36, 36, 16, 16,
|
||||
new ECBlocks(42, new ECB(1, 86)))));
|
||||
VERSIONS.push_back(Ref<Version>(new Version(12, 40, 40, 18, 18,
|
||||
new ECBlocks(48, new ECB(1, 114)))));
|
||||
VERSIONS.push_back(Ref<Version>(new Version(13, 44, 44, 20, 20,
|
||||
new ECBlocks(56, new ECB(1, 144)))));
|
||||
VERSIONS.push_back(Ref<Version>(new Version(14, 48, 48, 22, 22,
|
||||
new ECBlocks(68, new ECB(1, 174)))));
|
||||
VERSIONS.push_back(Ref<Version>(new Version(15, 52, 52, 24, 24,
|
||||
new ECBlocks(42, new ECB(2, 102)))));
|
||||
VERSIONS.push_back(Ref<Version>(new Version(16, 64, 64, 14, 14,
|
||||
new ECBlocks(56, new ECB(2, 140)))));
|
||||
VERSIONS.push_back(Ref<Version>(new Version(17, 72, 72, 16, 16,
|
||||
new ECBlocks(36, new ECB(4, 92)))));
|
||||
VERSIONS.push_back(Ref<Version>(new Version(18, 80, 80, 18, 18,
|
||||
new ECBlocks(48, new ECB(4, 114)))));
|
||||
VERSIONS.push_back(Ref<Version>(new Version(19, 88, 88, 20, 20,
|
||||
new ECBlocks(56, new ECB(4, 144)))));
|
||||
VERSIONS.push_back(Ref<Version>(new Version(20, 96, 96, 22, 22,
|
||||
new ECBlocks(68, new ECB(4, 174)))));
|
||||
VERSIONS.push_back(Ref<Version>(new Version(21, 104, 104, 24, 24,
|
||||
new ECBlocks(56, new ECB(6, 136)))));
|
||||
VERSIONS.push_back(Ref<Version>(new Version(22, 120, 120, 18, 18,
|
||||
new ECBlocks(68, new ECB(6, 175)))));
|
||||
VERSIONS.push_back(Ref<Version>(new Version(23, 132, 132, 20, 20,
|
||||
new ECBlocks(62, new ECB(8, 163)))));
|
||||
VERSIONS.push_back(Ref<Version>(new Version(24, 144, 144, 22, 22,
|
||||
new ECBlocks(62, new ECB(8, 156), new ECB(2, 155)))));
|
||||
VERSIONS.push_back(Ref<Version>(new Version(25, 8, 18, 6, 16,
|
||||
new ECBlocks(7, new ECB(1, 5)))));
|
||||
VERSIONS.push_back(Ref<Version>(new Version(26, 8, 32, 6, 14,
|
||||
new ECBlocks(11, new ECB(1, 10)))));
|
||||
VERSIONS.push_back(Ref<Version>(new Version(27, 12, 26, 10, 24,
|
||||
new ECBlocks(14, new ECB(1, 16)))));
|
||||
VERSIONS.push_back(Ref<Version>(new Version(28, 12, 36, 10, 16,
|
||||
new ECBlocks(18, new ECB(1, 22)))));
|
||||
VERSIONS.push_back(Ref<Version>(new Version(29, 16, 36, 10, 16,
|
||||
new ECBlocks(24, new ECB(1, 32)))));
|
||||
VERSIONS.push_back(Ref<Version>(new Version(30, 16, 48, 14, 22,
|
||||
new ECBlocks(28, new ECB(1, 49)))));
|
||||
return VERSIONS.size();
|
||||
}
|
||||
}
|
||||
}
|
87
symbian/ZXingBarcodeReader/group/zxing/datamatrix/Version.h
Normal file
87
symbian/ZXingBarcodeReader/group/zxing/datamatrix/Version.h
Normal file
|
@ -0,0 +1,87 @@
|
|||
#ifndef __VERSION_H__
|
||||
#define __VERSION_H__
|
||||
|
||||
/*
|
||||
* Version.h
|
||||
* zxing
|
||||
*
|
||||
* Created by Luiz Silva on 09/02/2010.
|
||||
* Copyright 2010 ZXing authors All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <zxing/ReaderException.h>
|
||||
#include <zxing/common/BitMatrix.h>
|
||||
#include <zxing/common/Counted.h>
|
||||
#include <vector>
|
||||
|
||||
namespace zxing {
|
||||
namespace datamatrix {
|
||||
|
||||
class ECB {
|
||||
private:
|
||||
int count_;
|
||||
int dataCodewords_;
|
||||
public:
|
||||
ECB(int count, int dataCodewords);
|
||||
int getCount();
|
||||
int getDataCodewords();
|
||||
};
|
||||
|
||||
class ECBlocks {
|
||||
private:
|
||||
int ecCodewords_;
|
||||
std::vector<ECB*> ecBlocks_;
|
||||
public:
|
||||
ECBlocks(int ecCodewords, ECB *ecBlocks);
|
||||
ECBlocks(int ecCodewords, ECB *ecBlocks1, ECB *ecBlocks2);
|
||||
int getECCodewords();
|
||||
std::vector<ECB*>& getECBlocks();
|
||||
~ECBlocks();
|
||||
};
|
||||
|
||||
class Version : public Counted {
|
||||
private:
|
||||
int versionNumber_;
|
||||
int symbolSizeRows_;
|
||||
int symbolSizeColumns_;
|
||||
int dataRegionSizeRows_;
|
||||
int dataRegionSizeColumns_;
|
||||
ECBlocks* ecBlocks_;
|
||||
int totalCodewords_;
|
||||
Version(int versionNumber, int symbolSizeRows, int symbolSizeColumns, int dataRegionSizeRows,
|
||||
int dataRegionSizeColumns, ECBlocks *ecBlocks);
|
||||
|
||||
public:
|
||||
static std::vector<Ref<Version> > VERSIONS;
|
||||
|
||||
~Version();
|
||||
int getVersionNumber();
|
||||
int getSymbolSizeRows();
|
||||
int getSymbolSizeColumns();
|
||||
int getDataRegionSizeRows();
|
||||
int getDataRegionSizeColumns();
|
||||
int getTotalCodewords();
|
||||
ECBlocks* getECBlocks();
|
||||
static int buildVersions();
|
||||
Ref<Version> getVersionForDimensions(int numRows, int numColumns);
|
||||
|
||||
private:
|
||||
Version(const Version&);
|
||||
Version & operator=(const Version&);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif // __VERSION_H__
|
|
@ -0,0 +1,364 @@
|
|||
/*
|
||||
* BitMatrixParser.cpp
|
||||
* zxing
|
||||
*
|
||||
* Created by Luiz Silva on 09/02/2010.
|
||||
* Copyright 2010 ZXing authors All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <zxing/datamatrix/decoder/BitMatrixParser.h>
|
||||
#include <zxing/common/IllegalArgumentException.h>
|
||||
|
||||
namespace zxing {
|
||||
namespace datamatrix {
|
||||
|
||||
int BitMatrixParser::copyBit(size_t x, size_t y, int versionBits) {
|
||||
return bitMatrix_->get(x, y) ? (versionBits << 1) | 0x1 : versionBits << 1;
|
||||
}
|
||||
|
||||
BitMatrixParser::BitMatrixParser(Ref<BitMatrix> bitMatrix) : bitMatrix_(NULL),
|
||||
parsedVersion_(NULL),
|
||||
readBitMatrix_(NULL) {
|
||||
size_t dimension = bitMatrix->getDimension();
|
||||
if (dimension < 10 || dimension > 144 || (dimension & 0x01) != 0)
|
||||
throw ReaderException("Dimension must be even, > 10 < 144");
|
||||
|
||||
parsedVersion_ = readVersion(bitMatrix);
|
||||
bitMatrix_ = extractDataRegion(bitMatrix);
|
||||
// TODO(bbrown): Make this work for rectangular symbols
|
||||
readBitMatrix_ = new BitMatrix(bitMatrix_->getDimension());
|
||||
}
|
||||
|
||||
Ref<Version> BitMatrixParser::readVersion(Ref<BitMatrix> bitMatrix) {
|
||||
if (parsedVersion_ != 0) {
|
||||
return parsedVersion_;
|
||||
}
|
||||
|
||||
// TODO(bbrown): make this work for rectangular dimensions as well.
|
||||
int numRows = bitMatrix->getDimension();
|
||||
int numColumns = numRows;
|
||||
|
||||
Ref<Version> version = parsedVersion_->getVersionForDimensions(numRows, numColumns);
|
||||
if (version != 0) {
|
||||
return version;
|
||||
}
|
||||
throw ReaderException("Couldn't decode version");
|
||||
}
|
||||
|
||||
ArrayRef<unsigned char> BitMatrixParser::readCodewords() {
|
||||
ArrayRef<unsigned char> result(parsedVersion_->getTotalCodewords());
|
||||
int resultOffset = 0;
|
||||
int row = 4;
|
||||
int column = 0;
|
||||
|
||||
// TODO(bbrown): Data Matrix can be rectangular, assuming square for now
|
||||
int numRows = bitMatrix_->getDimension();
|
||||
int numColumns = numRows;
|
||||
|
||||
bool corner1Read = false;
|
||||
bool corner2Read = false;
|
||||
bool corner3Read = false;
|
||||
bool corner4Read = false;
|
||||
|
||||
// Read all of the codewords
|
||||
do {
|
||||
// Check the four corner cases
|
||||
if ((row == numRows) && (column == 0) && !corner1Read) {
|
||||
result[resultOffset++] = (unsigned char) readCorner1(numRows, numColumns);
|
||||
row -= 2;
|
||||
column +=2;
|
||||
corner1Read = true;
|
||||
} else if ((row == numRows-2) && (column == 0) && ((numColumns & 0x03) != 0) && !corner2Read) {
|
||||
result[resultOffset++] = (unsigned char) readCorner2(numRows, numColumns);
|
||||
row -= 2;
|
||||
column +=2;
|
||||
corner2Read = true;
|
||||
} else if ((row == numRows+4) && (column == 2) && ((numColumns & 0x07) == 0) && !corner3Read) {
|
||||
result[resultOffset++] = (unsigned char) readCorner3(numRows, numColumns);
|
||||
row -= 2;
|
||||
column +=2;
|
||||
corner3Read = true;
|
||||
} else if ((row == numRows-2) && (column == 0) && ((numColumns & 0x07) == 4) && !corner4Read) {
|
||||
result[resultOffset++] = (unsigned char) readCorner4(numRows, numColumns);
|
||||
row -= 2;
|
||||
column +=2;
|
||||
corner4Read = true;
|
||||
} else {
|
||||
// Sweep upward diagonally to the right
|
||||
do {
|
||||
if ((row < numRows) && (column >= 0) && !readBitMatrix_->get(column, row)) {
|
||||
result[resultOffset++] = (unsigned char) readUtah(row, column, numRows, numColumns);
|
||||
}
|
||||
row -= 2;
|
||||
column +=2;
|
||||
} while ((row >= 0) && (column < numColumns));
|
||||
row += 1;
|
||||
column +=3;
|
||||
|
||||
// Sweep downward diagonally to the left
|
||||
do {
|
||||
if ((row >= 0) && (column < numColumns) && !readBitMatrix_->get(column, row)) {
|
||||
result[resultOffset++] = (unsigned char) readUtah(row, column, numRows, numColumns);
|
||||
}
|
||||
row += 2;
|
||||
column -=2;
|
||||
} while ((row < numRows) && (column >= 0));
|
||||
row += 3;
|
||||
column +=1;
|
||||
}
|
||||
} while ((row < numRows) || (column < numColumns));
|
||||
|
||||
if (resultOffset != parsedVersion_->getTotalCodewords()) {
|
||||
throw ReaderException("Did not read all codewords");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool BitMatrixParser::readModule(int row, int column, int numRows, int numColumns) {
|
||||
// Adjust the row and column indices based on boundary wrapping
|
||||
if (row < 0) {
|
||||
row += numRows;
|
||||
column += 4 - ((numRows + 4) & 0x07);
|
||||
}
|
||||
if (column < 0) {
|
||||
column += numColumns;
|
||||
row += 4 - ((numColumns + 4) & 0x07);
|
||||
}
|
||||
readBitMatrix_->set(column, row);
|
||||
return bitMatrix_->get(column, row);
|
||||
}
|
||||
|
||||
int BitMatrixParser::readUtah(int row, int column, int numRows, int numColumns) {
|
||||
int currentByte = 0;
|
||||
if (readModule(row - 2, column - 2, numRows, numColumns)) {
|
||||
currentByte |= 1;
|
||||
}
|
||||
currentByte <<= 1;
|
||||
if (readModule(row - 2, column - 1, numRows, numColumns)) {
|
||||
currentByte |= 1;
|
||||
}
|
||||
currentByte <<= 1;
|
||||
if (readModule(row - 1, column - 2, numRows, numColumns)) {
|
||||
currentByte |= 1;
|
||||
}
|
||||
currentByte <<= 1;
|
||||
if (readModule(row - 1, column - 1, numRows, numColumns)) {
|
||||
currentByte |= 1;
|
||||
}
|
||||
currentByte <<= 1;
|
||||
if (readModule(row - 1, column, numRows, numColumns)) {
|
||||
currentByte |= 1;
|
||||
}
|
||||
currentByte <<= 1;
|
||||
if (readModule(row, column - 2, numRows, numColumns)) {
|
||||
currentByte |= 1;
|
||||
}
|
||||
currentByte <<= 1;
|
||||
if (readModule(row, column - 1, numRows, numColumns)) {
|
||||
currentByte |= 1;
|
||||
}
|
||||
currentByte <<= 1;
|
||||
if (readModule(row, column, numRows, numColumns)) {
|
||||
currentByte |= 1;
|
||||
}
|
||||
return currentByte;
|
||||
}
|
||||
|
||||
int BitMatrixParser::readCorner1(int numRows, int numColumns) {
|
||||
int currentByte = 0;
|
||||
if (readModule(numRows - 1, 0, numRows, numColumns)) {
|
||||
currentByte |= 1;
|
||||
}
|
||||
currentByte <<= 1;
|
||||
if (readModule(numRows - 1, 1, numRows, numColumns)) {
|
||||
currentByte |= 1;
|
||||
}
|
||||
currentByte <<= 1;
|
||||
if (readModule(numRows - 1, 2, numRows, numColumns)) {
|
||||
currentByte |= 1;
|
||||
}
|
||||
currentByte <<= 1;
|
||||
if (readModule(0, numColumns - 2, numRows, numColumns)) {
|
||||
currentByte |= 1;
|
||||
}
|
||||
currentByte <<= 1;
|
||||
if (readModule(0, numColumns - 1, numRows, numColumns)) {
|
||||
currentByte |= 1;
|
||||
}
|
||||
currentByte <<= 1;
|
||||
if (readModule(1, numColumns - 1, numRows, numColumns)) {
|
||||
currentByte |= 1;
|
||||
}
|
||||
currentByte <<= 1;
|
||||
if (readModule(2, numColumns - 1, numRows, numColumns)) {
|
||||
currentByte |= 1;
|
||||
}
|
||||
currentByte <<= 1;
|
||||
if (readModule(3, numColumns - 1, numRows, numColumns)) {
|
||||
currentByte |= 1;
|
||||
}
|
||||
return currentByte;
|
||||
}
|
||||
|
||||
int BitMatrixParser::readCorner2(int numRows, int numColumns) {
|
||||
int currentByte = 0;
|
||||
if (readModule(numRows - 3, 0, numRows, numColumns)) {
|
||||
currentByte |= 1;
|
||||
}
|
||||
currentByte <<= 1;
|
||||
if (readModule(numRows - 2, 0, numRows, numColumns)) {
|
||||
currentByte |= 1;
|
||||
}
|
||||
currentByte <<= 1;
|
||||
if (readModule(numRows - 1, 0, numRows, numColumns)) {
|
||||
currentByte |= 1;
|
||||
}
|
||||
currentByte <<= 1;
|
||||
if (readModule(0, numColumns - 4, numRows, numColumns)) {
|
||||
currentByte |= 1;
|
||||
}
|
||||
currentByte <<= 1;
|
||||
if (readModule(0, numColumns - 3, numRows, numColumns)) {
|
||||
currentByte |= 1;
|
||||
}
|
||||
currentByte <<= 1;
|
||||
if (readModule(0, numColumns - 2, numRows, numColumns)) {
|
||||
currentByte |= 1;
|
||||
}
|
||||
currentByte <<= 1;
|
||||
if (readModule(0, numColumns - 1, numRows, numColumns)) {
|
||||
currentByte |= 1;
|
||||
}
|
||||
currentByte <<= 1;
|
||||
if (readModule(1, numColumns - 1, numRows, numColumns)) {
|
||||
currentByte |= 1;
|
||||
}
|
||||
return currentByte;
|
||||
}
|
||||
|
||||
int BitMatrixParser::readCorner3(int numRows, int numColumns) {
|
||||
int currentByte = 0;
|
||||
if (readModule(numRows - 1, 0, numRows, numColumns)) {
|
||||
currentByte |= 1;
|
||||
}
|
||||
currentByte <<= 1;
|
||||
if (readModule(numRows - 1, numColumns - 1, numRows, numColumns)) {
|
||||
currentByte |= 1;
|
||||
}
|
||||
currentByte <<= 1;
|
||||
if (readModule(0, numColumns - 3, numRows, numColumns)) {
|
||||
currentByte |= 1;
|
||||
}
|
||||
currentByte <<= 1;
|
||||
if (readModule(0, numColumns - 2, numRows, numColumns)) {
|
||||
currentByte |= 1;
|
||||
}
|
||||
currentByte <<= 1;
|
||||
if (readModule(0, numColumns - 1, numRows, numColumns)) {
|
||||
currentByte |= 1;
|
||||
}
|
||||
currentByte <<= 1;
|
||||
if (readModule(1, numColumns - 3, numRows, numColumns)) {
|
||||
currentByte |= 1;
|
||||
}
|
||||
currentByte <<= 1;
|
||||
if (readModule(1, numColumns - 2, numRows, numColumns)) {
|
||||
currentByte |= 1;
|
||||
}
|
||||
currentByte <<= 1;
|
||||
if (readModule(1, numColumns - 1, numRows, numColumns)) {
|
||||
currentByte |= 1;
|
||||
}
|
||||
return currentByte;
|
||||
}
|
||||
|
||||
int BitMatrixParser::readCorner4(int numRows, int numColumns) {
|
||||
int currentByte = 0;
|
||||
if (readModule(numRows - 3, 0, numRows, numColumns)) {
|
||||
currentByte |= 1;
|
||||
}
|
||||
currentByte <<= 1;
|
||||
if (readModule(numRows - 2, 0, numRows, numColumns)) {
|
||||
currentByte |= 1;
|
||||
}
|
||||
currentByte <<= 1;
|
||||
if (readModule(numRows - 1, 0, numRows, numColumns)) {
|
||||
currentByte |= 1;
|
||||
}
|
||||
currentByte <<= 1;
|
||||
if (readModule(0, numColumns - 2, numRows, numColumns)) {
|
||||
currentByte |= 1;
|
||||
}
|
||||
currentByte <<= 1;
|
||||
if (readModule(0, numColumns - 1, numRows, numColumns)) {
|
||||
currentByte |= 1;
|
||||
}
|
||||
currentByte <<= 1;
|
||||
if (readModule(1, numColumns - 1, numRows, numColumns)) {
|
||||
currentByte |= 1;
|
||||
}
|
||||
currentByte <<= 1;
|
||||
if (readModule(2, numColumns - 1, numRows, numColumns)) {
|
||||
currentByte |= 1;
|
||||
}
|
||||
currentByte <<= 1;
|
||||
if (readModule(3, numColumns - 1, numRows, numColumns)) {
|
||||
currentByte |= 1;
|
||||
}
|
||||
return currentByte;
|
||||
}
|
||||
|
||||
Ref<BitMatrix> BitMatrixParser::extractDataRegion(Ref<BitMatrix> bitMatrix) {
|
||||
int symbolSizeRows = parsedVersion_->getSymbolSizeRows();
|
||||
int symbolSizeColumns = parsedVersion_->getSymbolSizeColumns();
|
||||
|
||||
// TODO(bbrown): Make this work with rectangular codes
|
||||
if ((int)bitMatrix->getDimension() != symbolSizeRows) {
|
||||
throw IllegalArgumentException("Dimension of bitMarix must match the version size");
|
||||
}
|
||||
|
||||
int dataRegionSizeRows = parsedVersion_->getDataRegionSizeRows();
|
||||
int dataRegionSizeColumns = parsedVersion_->getDataRegionSizeColumns();
|
||||
|
||||
int numDataRegionsRow = symbolSizeRows / dataRegionSizeRows;
|
||||
int numDataRegionsColumn = symbolSizeColumns / dataRegionSizeColumns;
|
||||
|
||||
int sizeDataRegionRow = numDataRegionsRow * dataRegionSizeRows;
|
||||
//int sizeDataRegionColumn = numDataRegionsColumn * dataRegionSizeColumns;
|
||||
|
||||
// TODO(bbrown): Make this work with rectangular codes
|
||||
Ref<BitMatrix> bitMatrixWithoutAlignment(new BitMatrix(sizeDataRegionRow));
|
||||
for (int dataRegionRow = 0; dataRegionRow < numDataRegionsRow; ++dataRegionRow) {
|
||||
int dataRegionRowOffset = dataRegionRow * dataRegionSizeRows;
|
||||
for (int dataRegionColumn = 0; dataRegionColumn < numDataRegionsColumn; ++dataRegionColumn) {
|
||||
int dataRegionColumnOffset = dataRegionColumn * dataRegionSizeColumns;
|
||||
for (int i = 0; i < dataRegionSizeRows; ++i) {
|
||||
int readRowOffset = dataRegionRow * (dataRegionSizeRows + 2) + 1 + i;
|
||||
int writeRowOffset = dataRegionRowOffset + i;
|
||||
for (int j = 0; j < dataRegionSizeColumns; ++j) {
|
||||
int readColumnOffset = dataRegionColumn * (dataRegionSizeColumns + 2) + 1 + j;
|
||||
if (bitMatrix->get(readColumnOffset, readRowOffset)) {
|
||||
int writeColumnOffset = dataRegionColumnOffset + j;
|
||||
bitMatrixWithoutAlignment->set(writeColumnOffset, writeRowOffset);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return bitMatrixWithoutAlignment;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
#ifndef __BIT_MATRIX_PARSER_DM_H__
|
||||
#define __BIT_MATRIX_PARSER_DM_H__
|
||||
|
||||
/*
|
||||
* BitMatrixParser.h
|
||||
* zxing
|
||||
*
|
||||
* Created by Luiz Silva on 09/02/2010.
|
||||
* Copyright 2010 ZXing authors All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <zxing/ReaderException.h>
|
||||
#include <zxing/common/BitMatrix.h>
|
||||
#include <zxing/common/Counted.h>
|
||||
#include <zxing/common/Array.h>
|
||||
#include <zxing/datamatrix/Version.h>
|
||||
|
||||
namespace zxing {
|
||||
namespace datamatrix {
|
||||
|
||||
class BitMatrixParser : public Counted {
|
||||
private:
|
||||
Ref<BitMatrix> bitMatrix_;
|
||||
Ref<Version> parsedVersion_;
|
||||
Ref<BitMatrix> readBitMatrix_;
|
||||
|
||||
int copyBit(size_t x, size_t y, int versionBits);
|
||||
|
||||
public:
|
||||
BitMatrixParser(Ref<BitMatrix> bitMatrix);
|
||||
Ref<Version> readVersion(Ref<BitMatrix> bitMatrix);
|
||||
ArrayRef<unsigned char> readCodewords();
|
||||
bool readModule(int row, int column, int numRows, int numColumns);
|
||||
|
||||
private:
|
||||
int readUtah(int row, int column, int numRows, int numColumns);
|
||||
int readCorner1(int numRows, int numColumns);
|
||||
int readCorner2(int numRows, int numColumns);
|
||||
int readCorner3(int numRows, int numColumns);
|
||||
int readCorner4(int numRows, int numColumns);
|
||||
Ref<BitMatrix> extractDataRegion(Ref<BitMatrix> bitMatrix);
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif // __BIT_MATRIX_PARSER_DM_H__
|
|
@ -0,0 +1,113 @@
|
|||
/*
|
||||
* DataBlock.cpp
|
||||
* zxing
|
||||
*
|
||||
* Created by Luiz Silva on 09/02/2010.
|
||||
* Copyright 2010 ZXing authors All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <zxing/datamatrix/decoder/DataBlock.h>
|
||||
#include <zxing/common/IllegalArgumentException.h>
|
||||
|
||||
namespace zxing {
|
||||
namespace datamatrix {
|
||||
|
||||
using namespace std;
|
||||
|
||||
DataBlock::DataBlock(int numDataCodewords, ArrayRef<unsigned char> codewords) :
|
||||
numDataCodewords_(numDataCodewords), codewords_(codewords) {
|
||||
}
|
||||
|
||||
int DataBlock::getNumDataCodewords() {
|
||||
return numDataCodewords_;
|
||||
}
|
||||
|
||||
ArrayRef<unsigned char> DataBlock::getCodewords() {
|
||||
return codewords_;
|
||||
}
|
||||
|
||||
std::vector<Ref<DataBlock> > DataBlock::getDataBlocks(ArrayRef<unsigned char> rawCodewords, Version *version) {
|
||||
// Figure out the number and size of data blocks used by this version and
|
||||
// error correction level
|
||||
ECBlocks* ecBlocks = version->getECBlocks();
|
||||
|
||||
// First count the total number of data blocks
|
||||
int totalBlocks = 0;
|
||||
vector<ECB*> ecBlockArray = ecBlocks->getECBlocks();
|
||||
for (size_t i = 0; i < ecBlockArray.size(); i++) {
|
||||
totalBlocks += ecBlockArray[i]->getCount();
|
||||
}
|
||||
|
||||
// Now establish DataBlocks of the appropriate size and number of data codewords
|
||||
std::vector<Ref<DataBlock> > result(totalBlocks);
|
||||
int numResultBlocks = 0;
|
||||
for (size_t j = 0; j < ecBlockArray.size(); j++) {
|
||||
ECB *ecBlock = ecBlockArray[j];
|
||||
for (int i = 0; i < ecBlock->getCount(); i++) {
|
||||
int numDataCodewords = ecBlock->getDataCodewords();
|
||||
int numBlockCodewords = ecBlocks->getECCodewords() + numDataCodewords;
|
||||
ArrayRef<unsigned char> buffer(numBlockCodewords);
|
||||
Ref<DataBlock> blockRef(new DataBlock(numDataCodewords, buffer));
|
||||
result[numResultBlocks++] = blockRef;
|
||||
}
|
||||
}
|
||||
|
||||
// All blocks have the same amount of data, except that the last n
|
||||
// (where n may be 0) have 1 more byte. Figure out where these start.
|
||||
int shorterBlocksTotalCodewords = result[0]->codewords_.size();
|
||||
int longerBlocksStartAt = result.size() - 1;
|
||||
while (longerBlocksStartAt >= 0) {
|
||||
int numCodewords = result[longerBlocksStartAt]->codewords_.size();
|
||||
if (numCodewords == shorterBlocksTotalCodewords) {
|
||||
break;
|
||||
}
|
||||
if (numCodewords != shorterBlocksTotalCodewords + 1) {
|
||||
throw IllegalArgumentException("Data block sizes differ by more than 1");
|
||||
}
|
||||
longerBlocksStartAt--;
|
||||
}
|
||||
longerBlocksStartAt++;
|
||||
|
||||
int shorterBlocksNumDataCodewords = shorterBlocksTotalCodewords - ecBlocks->getECCodewords();
|
||||
// The last elements of result may be 1 element longer;
|
||||
// first fill out as many elements as all of them have
|
||||
int rawCodewordsOffset = 0;
|
||||
for (int i = 0; i < shorterBlocksNumDataCodewords; i++) {
|
||||
for (int j = 0; j < numResultBlocks; j++) {
|
||||
result[j]->codewords_[i] = rawCodewords[rawCodewordsOffset++];
|
||||
}
|
||||
}
|
||||
// Fill out the last data block in the longer ones
|
||||
for (int j = longerBlocksStartAt; j < numResultBlocks; j++) {
|
||||
result[j]->codewords_[shorterBlocksNumDataCodewords] = rawCodewords[rawCodewordsOffset++];
|
||||
}
|
||||
// Now add in error correction blocks
|
||||
int max = result[0]->codewords_.size();
|
||||
for (int i = shorterBlocksNumDataCodewords; i < max; i++) {
|
||||
for (int j = 0; j < numResultBlocks; j++) {
|
||||
int iOffset = j < longerBlocksStartAt ? i : i + 1;
|
||||
result[j]->codewords_[iOffset] = rawCodewords[rawCodewordsOffset++];
|
||||
}
|
||||
}
|
||||
|
||||
if ((size_t)rawCodewordsOffset != rawCodewords.size()) {
|
||||
throw IllegalArgumentException("rawCodewordsOffset != rawCodewords.length");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
#ifndef __DATA_BLOCK_DM_H__
|
||||
#define __DATA_BLOCK_DM_H__
|
||||
|
||||
/*
|
||||
* DataBlock.h
|
||||
* zxing
|
||||
*
|
||||
* Created by Luiz Silva on 09/02/2010.
|
||||
* Copyright 2010 ZXing authors All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <vector>
|
||||
#include <zxing/common/Counted.h>
|
||||
#include <zxing/common/Array.h>
|
||||
#include <zxing/datamatrix/Version.h>
|
||||
|
||||
namespace zxing {
|
||||
namespace datamatrix {
|
||||
|
||||
class DataBlock : public Counted {
|
||||
private:
|
||||
int numDataCodewords_;
|
||||
ArrayRef<unsigned char> codewords_;
|
||||
|
||||
DataBlock(int numDataCodewords, ArrayRef<unsigned char> codewords);
|
||||
|
||||
public:
|
||||
static std::vector<Ref<DataBlock> > getDataBlocks(ArrayRef<unsigned char> rawCodewords, Version *version);
|
||||
|
||||
int getNumDataCodewords();
|
||||
ArrayRef<unsigned char> getCodewords();
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif // __DATA_BLOCK_DM_H__
|
|
@ -0,0 +1,404 @@
|
|||
/*
|
||||
* DecodedBitStreamParser.cpp
|
||||
* zxing
|
||||
*
|
||||
* Created by Luiz Silva on 09/02/2010.
|
||||
* Copyright 2010 ZXing authors All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <zxing/ReaderException.h>
|
||||
#include <zxing/datamatrix/decoder/DecodedBitStreamParser.h>
|
||||
#include <iostream>
|
||||
|
||||
namespace zxing {
|
||||
namespace datamatrix {
|
||||
|
||||
using namespace std;
|
||||
|
||||
const char DecodedBitStreamParser::C40_BASIC_SET_CHARS[] = {
|
||||
'*', '*', '*', ' ', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
|
||||
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
|
||||
'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'
|
||||
};
|
||||
|
||||
const char DecodedBitStreamParser::C40_SHIFT2_SET_CHARS[] = {
|
||||
'!', '"', '#', '$', '%', '&', '\'', '(', ')', '*', '+', ',', '-', '.',
|
||||
'/', ':', ';', '<', '=', '>', '?', '@', '[', '\\', ']', '^', '_'
|
||||
};
|
||||
|
||||
const char DecodedBitStreamParser::TEXT_BASIC_SET_CHARS[] = {
|
||||
'*', '*', '*', ' ', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
|
||||
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
|
||||
'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'
|
||||
};
|
||||
|
||||
const char DecodedBitStreamParser::TEXT_SHIFT3_SET_CHARS[] = {
|
||||
'\'', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
|
||||
'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '{', '|', '}', '~', (char) 127
|
||||
};
|
||||
|
||||
std::string DecodedBitStreamParser::decode(ArrayRef<unsigned char> bytes) {
|
||||
Ref<BitSource> bits(new BitSource(bytes));
|
||||
ostringstream result;
|
||||
ostringstream resultTrailer;
|
||||
// bool trailer = false;
|
||||
int mode = ASCII_ENCODE;
|
||||
do {
|
||||
if (mode == ASCII_ENCODE) {
|
||||
mode = decodeAsciiSegment(bits, result, resultTrailer);
|
||||
} else {
|
||||
switch (mode) {
|
||||
case C40_ENCODE:
|
||||
decodeC40Segment(bits, result);
|
||||
break;
|
||||
case TEXT_ENCODE:
|
||||
decodeTextSegment(bits, result);
|
||||
break;
|
||||
case ANSIX12_ENCODE:
|
||||
decodeAnsiX12Segment(bits, result);
|
||||
break;
|
||||
case EDIFACT_ENCODE:
|
||||
decodeEdifactSegment(bits, result);
|
||||
break;
|
||||
case BASE256_ENCODE:
|
||||
decodeBase256Segment(bits, result);
|
||||
break;
|
||||
default:
|
||||
throw ReaderException("Unsupported mode indicator");
|
||||
}
|
||||
mode = ASCII_ENCODE;
|
||||
}
|
||||
} while (mode != PAD_ENCODE && bits->available() > 0);
|
||||
/* if (trailer) {
|
||||
result << resultTrailer;
|
||||
}
|
||||
*/
|
||||
return result.str();
|
||||
}
|
||||
|
||||
int DecodedBitStreamParser::decodeAsciiSegment(Ref<BitSource> bits, ostringstream & result,
|
||||
ostringstream & resultTrailer) {
|
||||
bool upperShift = false;
|
||||
do {
|
||||
int oneByte = bits->readBits(8);
|
||||
if (oneByte == 0) {
|
||||
throw ReaderException("Not enough bits to decode");
|
||||
} else if (oneByte <= 128) { // ASCII data (ASCII value + 1)
|
||||
oneByte = upperShift ? (oneByte + 128) : oneByte;
|
||||
upperShift = false;
|
||||
result << (char) (oneByte - 1);
|
||||
return ASCII_ENCODE;
|
||||
} else if (oneByte == 129) { // Pad
|
||||
return PAD_ENCODE;
|
||||
} else if (oneByte <= 229) { // 2-digit data 00-99 (Numeric Value + 130)
|
||||
int value = oneByte - 130;
|
||||
if (value < 10) { // padd with '0' for single digit values
|
||||
result << '0';
|
||||
}
|
||||
result << value;
|
||||
} else if (oneByte == 230) { // Latch to C40 encodation
|
||||
return C40_ENCODE;
|
||||
} else if (oneByte == 231) { // Latch to Base 256 encodation
|
||||
return BASE256_ENCODE;
|
||||
} else if (oneByte == 232) { // FNC1
|
||||
//throw ReaderException.getInstance();
|
||||
// Ignore this symbol for now
|
||||
} else if (oneByte == 233) { // Structured Append
|
||||
//throw ReaderException.getInstance();
|
||||
// Ignore this symbol for now
|
||||
} else if (oneByte == 234) { // Reader Programming
|
||||
//throw ReaderException.getInstance();
|
||||
// Ignore this symbol for now
|
||||
} else if (oneByte == 235) { // Upper Shift (shift to Extended ASCII)
|
||||
upperShift = true;
|
||||
} else if (oneByte == 236) { // 05 Macro
|
||||
/* trailer = false;
|
||||
result << "[)>\u001E05\u001D";
|
||||
resultTrailer << "\u001E\u0004";
|
||||
// Ignore this symbol for now
|
||||
*/ } else if (oneByte == 237) { // 06 Macro
|
||||
/* trailer = false;
|
||||
result << "[)>\u001E06\u001D";
|
||||
resultTrailer << "\u001E\u0004";
|
||||
// Ignore this symbol for now
|
||||
*/ } else if (oneByte == 238) { // Latch to ANSI X12 encodation
|
||||
return ANSIX12_ENCODE;
|
||||
} else if (oneByte == 239) { // Latch to Text encodation
|
||||
return TEXT_ENCODE;
|
||||
} else if (oneByte == 240) { // Latch to EDIFACT encodation
|
||||
return EDIFACT_ENCODE;
|
||||
} else if (oneByte == 241) { // ECI Character
|
||||
// TODO(bbrown): I think we need to support ECI
|
||||
//throw ReaderException.getInstance();
|
||||
// Ignore this symbol for now
|
||||
} else if (oneByte >= 242) { // Not to be used in ASCII encodation
|
||||
throw ReaderException("Not to be used in ASCII encodation");
|
||||
}
|
||||
} while (bits->available() > 0);
|
||||
return ASCII_ENCODE;
|
||||
}
|
||||
|
||||
void DecodedBitStreamParser::decodeC40Segment(Ref<BitSource> bits, ostringstream & result) {
|
||||
// Three C40 values are encoded in a 16-bit value as
|
||||
// (1600 * C1) + (40 * C2) + C3 + 1
|
||||
// TODO(bbrown): The Upper Shift with C40 doesn't work in the 4 value scenario all the time
|
||||
bool upperShift = false;
|
||||
|
||||
int* cValues = new int[3];
|
||||
do {
|
||||
// If there is only one byte left then it will be encoded as ASCII
|
||||
if (bits->available() == 8) {
|
||||
return;
|
||||
}
|
||||
int firstByte = bits->readBits(8);
|
||||
if (firstByte == 254) { // Unlatch codeword
|
||||
return;
|
||||
}
|
||||
|
||||
parseTwoBytes(firstByte, bits->readBits(8), cValues);
|
||||
|
||||
int shift = 0;
|
||||
for (int i = 0; i < 3; i++) {
|
||||
int cValue = cValues[i];
|
||||
switch (shift) {
|
||||
case 0:
|
||||
if (cValue < 3) {
|
||||
shift = cValue + 1;
|
||||
} else {
|
||||
if (upperShift) {
|
||||
result << (char) (C40_BASIC_SET_CHARS[cValue] + 128);
|
||||
upperShift = false;
|
||||
} else {
|
||||
result << C40_BASIC_SET_CHARS[cValue];
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
if (upperShift) {
|
||||
result << cValue + 128;
|
||||
upperShift = false;
|
||||
} else {
|
||||
result << cValue;
|
||||
}
|
||||
shift = 0;
|
||||
break;
|
||||
case 2:
|
||||
if (cValue < 27) {
|
||||
if (upperShift) {
|
||||
result << (char) (C40_SHIFT2_SET_CHARS[cValue] + 128);
|
||||
upperShift = false;
|
||||
} else {
|
||||
result << C40_SHIFT2_SET_CHARS[cValue];
|
||||
}
|
||||
} else if (cValue == 27) { // FNC1
|
||||
throw ReaderException("FNC1");
|
||||
} else if (cValue == 30) { // Upper Shift
|
||||
upperShift = true;
|
||||
} else {
|
||||
throw ReaderException("Upper Shift");
|
||||
}
|
||||
shift = 0;
|
||||
break;
|
||||
case 3:
|
||||
if (upperShift) {
|
||||
result << (char) (cValue + 224);
|
||||
upperShift = false;
|
||||
} else {
|
||||
result << (char) (cValue + 96);
|
||||
}
|
||||
shift = 0;
|
||||
break;
|
||||
default:
|
||||
throw ReaderException("");
|
||||
}
|
||||
}
|
||||
} while (bits->available() > 0);
|
||||
}
|
||||
|
||||
void DecodedBitStreamParser::decodeTextSegment(Ref<BitSource> bits, ostringstream & result) {
|
||||
// Three Text values are encoded in a 16-bit value as
|
||||
// (1600 * C1) + (40 * C2) + C3 + 1
|
||||
// TODO(bbrown): The Upper Shift with Text doesn't work in the 4 value scenario all the time
|
||||
bool upperShift = false;
|
||||
|
||||
int* cValues = new int[3];
|
||||
do {
|
||||
// If there is only one byte left then it will be encoded as ASCII
|
||||
if (bits->available() == 8) {
|
||||
return;
|
||||
}
|
||||
int firstByte = bits->readBits(8);
|
||||
if (firstByte == 254) { // Unlatch codeword
|
||||
return;
|
||||
}
|
||||
|
||||
parseTwoBytes(firstByte, bits->readBits(8), cValues);
|
||||
|
||||
int shift = 0;
|
||||
for (int i = 0; i < 3; i++) {
|
||||
int cValue = cValues[i];
|
||||
switch (shift) {
|
||||
case 0:
|
||||
if (cValue < 3) {
|
||||
shift = cValue + 1;
|
||||
} else {
|
||||
if (upperShift) {
|
||||
result << (char) (TEXT_BASIC_SET_CHARS[cValue] + 128);
|
||||
upperShift = false;
|
||||
} else {
|
||||
result << (TEXT_BASIC_SET_CHARS[cValue]);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
if (upperShift) {
|
||||
result << (char) (cValue + 128);
|
||||
upperShift = false;
|
||||
} else {
|
||||
result << (cValue);
|
||||
}
|
||||
shift = 0;
|
||||
break;
|
||||
case 2:
|
||||
// Shift 2 for Text is the same encoding as C40
|
||||
if (cValue < 27) {
|
||||
if (upperShift) {
|
||||
result << (char) (C40_SHIFT2_SET_CHARS[cValue] + 128);
|
||||
upperShift = false;
|
||||
} else {
|
||||
result << (C40_SHIFT2_SET_CHARS[cValue]);
|
||||
}
|
||||
} else if (cValue == 27) { // FNC1
|
||||
throw ReaderException("FNC1");
|
||||
} else if (cValue == 30) { // Upper Shift
|
||||
upperShift = true;
|
||||
} else {
|
||||
throw ReaderException("Upper Shift");
|
||||
}
|
||||
shift = 0;
|
||||
break;
|
||||
case 3:
|
||||
if (upperShift) {
|
||||
result << (char) (TEXT_SHIFT3_SET_CHARS[cValue] + 128);
|
||||
upperShift = false;
|
||||
} else {
|
||||
result << (TEXT_SHIFT3_SET_CHARS[cValue]);
|
||||
}
|
||||
shift = 0;
|
||||
break;
|
||||
default:
|
||||
throw ReaderException("");
|
||||
}
|
||||
}
|
||||
} while (bits->available() > 0);
|
||||
}
|
||||
|
||||
void DecodedBitStreamParser::decodeAnsiX12Segment(Ref<BitSource> bits, ostringstream & result) {
|
||||
// Three ANSI X12 values are encoded in a 16-bit value as
|
||||
// (1600 * C1) + (40 * C2) + C3 + 1
|
||||
|
||||
int* cValues = new int[3];
|
||||
do {
|
||||
// If there is only one byte left then it will be encoded as ASCII
|
||||
if (bits->available() == 8) {
|
||||
return;
|
||||
}
|
||||
int firstByte = bits->readBits(8);
|
||||
if (firstByte == 254) { // Unlatch codeword
|
||||
return;
|
||||
}
|
||||
|
||||
parseTwoBytes(firstByte, bits->readBits(8), cValues);
|
||||
|
||||
for (int i = 0; i < 3; i++) {
|
||||
int cValue = cValues[i];
|
||||
if (cValue == 0) { // X12 segment terminator <CR>
|
||||
result << '\r';
|
||||
} else if (cValue == 1) { // X12 segment separator *
|
||||
result << '*';
|
||||
} else if (cValue == 2) { // X12 sub-element separator >
|
||||
result << '>';
|
||||
} else if (cValue == 3) { // space
|
||||
result << ' ';
|
||||
} else if (cValue < 14) { // 0 - 9
|
||||
result << (char) (cValue + 44);
|
||||
} else if (cValue < 40) { // A - Z
|
||||
result << (char) (cValue + 51);
|
||||
} else {
|
||||
throw ReaderException("");
|
||||
}
|
||||
}
|
||||
} while (bits->available() > 0);
|
||||
}
|
||||
|
||||
void DecodedBitStreamParser::parseTwoBytes(int firstByte, int secondByte, int*& result) {
|
||||
int fullBitValue = (firstByte << 8) + secondByte - 1;
|
||||
int temp = fullBitValue / 1600;
|
||||
result[0] = temp;
|
||||
fullBitValue -= temp * 1600;
|
||||
temp = fullBitValue / 40;
|
||||
result[1] = temp;
|
||||
result[2] = fullBitValue - temp * 40;
|
||||
}
|
||||
|
||||
void DecodedBitStreamParser::decodeEdifactSegment(Ref<BitSource> bits, ostringstream & result) {
|
||||
bool unlatch = false;
|
||||
do {
|
||||
// If there is only two or less bytes left then it will be encoded as ASCII
|
||||
if (bits->available() <= 16) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
int edifactValue = bits->readBits(6);
|
||||
|
||||
// Check for the unlatch character
|
||||
if (edifactValue == 0x2B67) { // 011111
|
||||
unlatch = true;
|
||||
// If we encounter the unlatch code then continue reading because the Codeword triple
|
||||
// is padded with 0's
|
||||
}
|
||||
|
||||
if (!unlatch) {
|
||||
if ((edifactValue & 32) == 0) { // no 1 in the leading (6th) bit
|
||||
edifactValue |= 64; // Add a leading 01 to the 6 bit binary value
|
||||
}
|
||||
result << (edifactValue);
|
||||
}
|
||||
}
|
||||
} while (!unlatch && bits->available() > 0);
|
||||
}
|
||||
|
||||
void DecodedBitStreamParser::decodeBase256Segment(Ref<BitSource> bits, ostringstream & result){//, vector<unsigned char> byteSegments)
|
||||
// Figure out how long the Base 256 Segment is.
|
||||
int d1 = bits->readBits(8);
|
||||
int count;
|
||||
if (d1 == 0) { // Read the remainder of the symbol
|
||||
count = bits->available() / 8;
|
||||
} else if (d1 < 250) {
|
||||
count = d1;
|
||||
} else {
|
||||
count = 250 * (d1 - 249) + bits->readBits(8);
|
||||
}
|
||||
unsigned char* bytes = new unsigned char[count];
|
||||
for (int i = 0; i < count; i++) {
|
||||
bytes[i] = unrandomize255State(bits->readBits(8), i);
|
||||
}
|
||||
//byteSegments.push_back(bytes);
|
||||
result << bytes;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,103 @@
|
|||
#ifndef __DECODED_BIT_STREAM_PARSER_DM_H__
|
||||
#define __DECODED_BIT_STREAM_PARSER_DM_H__
|
||||
|
||||
/*
|
||||
* DecodedBitStreamParser.h
|
||||
* zxing
|
||||
*
|
||||
* Created by Luiz Silva on 09/02/2010.
|
||||
* Copyright 2010 ZXing authors All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <zxing/common/BitSource.h>
|
||||
#include <zxing/common/Counted.h>
|
||||
#include <zxing/common/Array.h>
|
||||
|
||||
|
||||
namespace zxing {
|
||||
namespace datamatrix {
|
||||
|
||||
class DecodedBitStreamParser {
|
||||
private:
|
||||
static const int PAD_ENCODE = 0; // Not really an encoding
|
||||
static const int ASCII_ENCODE = 1;
|
||||
static const int C40_ENCODE = 2;
|
||||
static const int TEXT_ENCODE = 3;
|
||||
static const int ANSIX12_ENCODE = 4;
|
||||
static const int EDIFACT_ENCODE = 5;
|
||||
static const int BASE256_ENCODE = 6;
|
||||
|
||||
/**
|
||||
* See ISO 16022:2006, Annex C Table C.1
|
||||
* The C40 Basic Character Set (*'s used for placeholders for the shift values)
|
||||
*/
|
||||
static const char C40_BASIC_SET_CHARS[];
|
||||
|
||||
static const char C40_SHIFT2_SET_CHARS[];
|
||||
/**
|
||||
* See ISO 16022:2006, Annex C Table C.2
|
||||
* The Text Basic Character Set (*'s used for placeholders for the shift values)
|
||||
*/
|
||||
static const char TEXT_BASIC_SET_CHARS[];
|
||||
|
||||
static const char TEXT_SHIFT3_SET_CHARS[];
|
||||
/**
|
||||
* See ISO 16022:2006, 5.2.3 and Annex C, Table C.2
|
||||
*/
|
||||
int decodeAsciiSegment(Ref<BitSource> bits, std::ostringstream &result, std::ostringstream &resultTrailer);
|
||||
/**
|
||||
* See ISO 16022:2006, 5.2.5 and Annex C, Table C.1
|
||||
*/
|
||||
void decodeC40Segment(Ref<BitSource> bits, std::ostringstream &result);
|
||||
/**
|
||||
* See ISO 16022:2006, 5.2.6 and Annex C, Table C.2
|
||||
*/
|
||||
void decodeTextSegment(Ref<BitSource> bits, std::ostringstream &result);
|
||||
/**
|
||||
* See ISO 16022:2006, 5.2.7
|
||||
*/
|
||||
void decodeAnsiX12Segment(Ref<BitSource> bits, std::ostringstream &result);
|
||||
/**
|
||||
* See ISO 16022:2006, 5.2.8 and Annex C Table C.3
|
||||
*/
|
||||
void decodeEdifactSegment(Ref<BitSource> bits, std::ostringstream &result);
|
||||
/**
|
||||
* See ISO 16022:2006, 5.2.9 and Annex B, B.2
|
||||
*/
|
||||
void decodeBase256Segment(Ref<BitSource> bits, std::ostringstream &result);//,std::vector<unsigned char> byteSegments);
|
||||
|
||||
void parseTwoBytes(int firstByte, int secondByte, int*& result);
|
||||
/**
|
||||
* See ISO 16022:2006, Annex B, B.2
|
||||
*/
|
||||
unsigned char unrandomize255State(int randomizedBase256Codeword,
|
||||
int base256CodewordPosition) {
|
||||
int pseudoRandomNumber = ((149 * base256CodewordPosition) % 255) + 1;
|
||||
int tempVariable = randomizedBase256Codeword - pseudoRandomNumber;
|
||||
return (unsigned char) (tempVariable >= 0 ? tempVariable : (tempVariable + 256));
|
||||
};
|
||||
void append(std::ostream &ost, const unsigned char *bufIn, size_t nIn, const char *src);
|
||||
|
||||
public:
|
||||
DecodedBitStreamParser() { };
|
||||
std::string decode(ArrayRef<unsigned char> bytes);
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif // __DECODED_BIT_STREAM_PARSER_DM_H__
|
|
@ -0,0 +1,96 @@
|
|||
/*
|
||||
* Decoder.cpp
|
||||
* zxing
|
||||
*
|
||||
* Created by Luiz Silva on 09/02/2010.
|
||||
* Copyright 2010 ZXing authors All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <zxing/datamatrix/decoder/Decoder.h>
|
||||
#include <zxing/datamatrix/decoder/BitMatrixParser.h>
|
||||
#include <zxing/datamatrix/decoder/DataBlock.h>
|
||||
#include <zxing/datamatrix/decoder/DecodedBitStreamParser.h>
|
||||
#include <zxing/datamatrix/Version.h>
|
||||
#include <zxing/ReaderException.h>
|
||||
#include <zxing/common/reedsolomon/ReedSolomonException.h>
|
||||
|
||||
namespace zxing {
|
||||
namespace datamatrix {
|
||||
|
||||
using namespace std;
|
||||
|
||||
Decoder::Decoder() :
|
||||
rsDecoder_(GF256::DATA_MATRIX_FIELD) {
|
||||
}
|
||||
|
||||
|
||||
void Decoder::correctErrors(ArrayRef<unsigned char> codewordBytes, int numDataCodewords) {
|
||||
int numCodewords = codewordBytes->size();
|
||||
ArrayRef<int> codewordInts(numCodewords);
|
||||
for (int i = 0; i < numCodewords; i++) {
|
||||
codewordInts[i] = codewordBytes[i] & 0xff;
|
||||
}
|
||||
int numECCodewords = numCodewords - numDataCodewords;
|
||||
|
||||
try {
|
||||
rsDecoder_.decode(codewordInts, numECCodewords);
|
||||
} catch (ReedSolomonException ex) {
|
||||
ReaderException rex(ex.what());
|
||||
throw rex;
|
||||
}
|
||||
|
||||
for (int i = 0; i < numDataCodewords; i++) {
|
||||
codewordBytes[i] = (unsigned char)codewordInts[i];
|
||||
}
|
||||
}
|
||||
|
||||
Ref<DecoderResult> Decoder::decode(Ref<BitMatrix> bits) {
|
||||
// Construct a parser and read version, error-correction level
|
||||
BitMatrixParser parser(bits);
|
||||
Version *version = parser.readVersion(bits);
|
||||
|
||||
// Read codewords
|
||||
ArrayRef<unsigned char> codewords(parser.readCodewords());
|
||||
// Separate into data blocks
|
||||
std::vector<Ref<DataBlock> > dataBlocks = DataBlock::getDataBlocks(codewords, version);
|
||||
|
||||
// Count total number of data bytes
|
||||
int totalBytes = 0;
|
||||
for (unsigned int i = 0; i < dataBlocks.size(); i++) {
|
||||
totalBytes += dataBlocks[i]->getNumDataCodewords();
|
||||
}
|
||||
ArrayRef<unsigned char> resultBytes(totalBytes);
|
||||
int resultOffset = 0;
|
||||
|
||||
// Error-correct and copy data blocks together into a stream of bytes
|
||||
for (unsigned int j = 0; j < dataBlocks.size(); j++) {
|
||||
Ref<DataBlock> dataBlock(dataBlocks[j]);
|
||||
ArrayRef<unsigned char> codewordBytes = dataBlock->getCodewords();
|
||||
int numDataCodewords = dataBlock->getNumDataCodewords();
|
||||
correctErrors(codewordBytes, numDataCodewords);
|
||||
for (int i = 0; i < numDataCodewords; i++) {
|
||||
resultBytes[resultOffset++] = codewordBytes[i];
|
||||
}
|
||||
}
|
||||
|
||||
// Decode the contents of that stream of bytes
|
||||
DecodedBitStreamParser decodedBSParser;
|
||||
Ref<String> text(new String(decodedBSParser.decode(resultBytes)));
|
||||
|
||||
Ref<DecoderResult> result(new DecoderResult(resultBytes, text));
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
#ifndef __DECODER_DM_H__
|
||||
#define __DECODER_DM_H__
|
||||
|
||||
/*
|
||||
* Decoder.h
|
||||
* zxing
|
||||
*
|
||||
* Created by Luiz Silva on 09/02/2010.
|
||||
* Copyright 2010 ZXing authors All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <zxing/common/reedsolomon/ReedSolomonDecoder.h>
|
||||
#include <zxing/common/reedsolomon/GF256.h>
|
||||
#include <zxing/common/Counted.h>
|
||||
#include <zxing/common/Array.h>
|
||||
#include <zxing/common/DecoderResult.h>
|
||||
#include <zxing/common/BitMatrix.h>
|
||||
|
||||
|
||||
namespace zxing {
|
||||
namespace datamatrix {
|
||||
|
||||
class Decoder {
|
||||
private:
|
||||
ReedSolomonDecoder rsDecoder_;
|
||||
|
||||
void correctErrors(ArrayRef<unsigned char> bytes, int numDataCodewords);
|
||||
|
||||
public:
|
||||
Decoder();
|
||||
|
||||
Ref<DecoderResult> decode(Ref<BitMatrix> bits);
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif // __DECODER_DM_H__
|
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
* CornerPoint.cpp
|
||||
* zxing
|
||||
*
|
||||
* Created by Luiz Silva on 09/02/2010.
|
||||
* Copyright 2010 ZXing authors All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <zxing/datamatrix/detector/CornerPoint.h>
|
||||
|
||||
|
||||
namespace zxing {
|
||||
namespace datamatrix {
|
||||
|
||||
using namespace std;
|
||||
|
||||
CornerPoint::CornerPoint(float posX, float posY) :
|
||||
posX_(posX), posY_(posY), counter_(0) {
|
||||
}
|
||||
|
||||
float CornerPoint::getX() const {
|
||||
return posX_;
|
||||
}
|
||||
|
||||
float CornerPoint::getY() const {
|
||||
return posY_;
|
||||
}
|
||||
|
||||
int CornerPoint::getCount() const {
|
||||
return counter_;
|
||||
}
|
||||
|
||||
void CornerPoint::incrementCount() {
|
||||
counter_++;
|
||||
}
|
||||
|
||||
bool CornerPoint::equals(Ref<CornerPoint> other) const {
|
||||
return posX_ == other->getX() && posY_ == other->getY();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
#ifndef __CORNER_FINDER_H__
|
||||
#define __CORNER_FINDER_H__
|
||||
|
||||
/*
|
||||
* CornerPoint.h
|
||||
* zxing
|
||||
*
|
||||
* Created by Luiz Silva on 09/02/2010.
|
||||
* Copyright 2010 ZXing authors All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <zxing/ResultPoint.h>
|
||||
#include <cmath>
|
||||
|
||||
namespace zxing {
|
||||
namespace datamatrix {
|
||||
|
||||
class CornerPoint : public ResultPoint {
|
||||
private:
|
||||
float posX_;
|
||||
float posY_;
|
||||
int counter_;
|
||||
|
||||
public:
|
||||
CornerPoint(float posX, float posY);
|
||||
float getX() const;
|
||||
float getY() const;
|
||||
int getCount() const;
|
||||
void incrementCount();
|
||||
bool equals(Ref<CornerPoint> other) const;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif // __CORNER_FINDER_H__
|
|
@ -0,0 +1,315 @@
|
|||
/*
|
||||
* Detector.cpp
|
||||
* zxing
|
||||
*
|
||||
* Created by Luiz Silva on 09/02/2010.
|
||||
* Copyright 2010 ZXing authors All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <zxing/common/GridSampler.h>
|
||||
#include <zxing/datamatrix/detector/Detector.h>
|
||||
#include <cmath>
|
||||
#include <sstream>
|
||||
#include <cstdlib>
|
||||
|
||||
namespace zxing {
|
||||
namespace datamatrix {
|
||||
|
||||
using namespace std;
|
||||
|
||||
ResultPointsAndTransitions::ResultPointsAndTransitions() : to_(), from_(), transitions_(0) {
|
||||
Ref<CornerPoint> ref(new CornerPoint(0,0));
|
||||
from_ = ref;
|
||||
to_ = ref;
|
||||
}
|
||||
|
||||
ResultPointsAndTransitions::ResultPointsAndTransitions(Ref<CornerPoint> from, Ref<CornerPoint> to, int transitions) :
|
||||
to_(to), from_(from), transitions_(transitions) {
|
||||
}
|
||||
|
||||
Ref<CornerPoint> ResultPointsAndTransitions::getFrom() {
|
||||
return from_;
|
||||
}
|
||||
|
||||
Ref<CornerPoint> ResultPointsAndTransitions::getTo() {
|
||||
return to_;
|
||||
}
|
||||
|
||||
int ResultPointsAndTransitions::getTransitions() {
|
||||
return transitions_;
|
||||
}
|
||||
|
||||
Detector::Detector(Ref<BitMatrix> image) : image_(image) { }
|
||||
|
||||
Ref<BitMatrix> Detector::getImage() {
|
||||
return image_;
|
||||
}
|
||||
|
||||
Ref<DetectorResult> Detector::detect() {
|
||||
Ref<MonochromeRectangleDetector> rectangleDetector_(new MonochromeRectangleDetector(image_));
|
||||
std::vector<Ref<CornerPoint> > cornerPoints = rectangleDetector_->detect();
|
||||
Ref<CornerPoint> pointA = cornerPoints[0];
|
||||
Ref<CornerPoint> pointB = cornerPoints[1];
|
||||
Ref<CornerPoint> pointC = cornerPoints[2];
|
||||
Ref<CornerPoint> pointD = cornerPoints[3];
|
||||
|
||||
// Point A and D are across the diagonal from one another,
|
||||
// as are B and C. Figure out which are the solid black lines
|
||||
// by counting transitions
|
||||
std::vector<Ref<ResultPointsAndTransitions> > transitions(4);
|
||||
transitions[0].reset(transitionsBetween(pointA, pointB));
|
||||
transitions[1].reset(transitionsBetween(pointA, pointC));
|
||||
transitions[2].reset(transitionsBetween(pointB, pointD));
|
||||
transitions[3].reset(transitionsBetween(pointC, pointD));
|
||||
insertionSort(transitions);
|
||||
|
||||
// Sort by number of transitions. First two will be the two solid sides; last two
|
||||
// will be the two alternating black/white sides
|
||||
Ref<ResultPointsAndTransitions> lSideOne(transitions[0]);
|
||||
Ref<ResultPointsAndTransitions> lSideTwo(transitions[1]);
|
||||
|
||||
// Figure out which point is their intersection by tallying up the number of times we see the
|
||||
// endpoints in the four endpoints. One will show up twice.
|
||||
Ref<CornerPoint> maybeTopLeft;
|
||||
Ref<CornerPoint> bottomLeft;
|
||||
Ref<CornerPoint> maybeBottomRight;
|
||||
if (lSideOne->getFrom()->equals(lSideOne->getTo())) {
|
||||
bottomLeft = lSideOne->getFrom();
|
||||
maybeTopLeft = lSideTwo->getFrom();
|
||||
maybeBottomRight = lSideTwo->getTo();
|
||||
}
|
||||
else if (lSideOne->getFrom()->equals(lSideTwo->getFrom())) {
|
||||
bottomLeft = lSideOne->getFrom();
|
||||
maybeTopLeft = lSideOne->getTo();
|
||||
maybeBottomRight = lSideTwo->getTo();
|
||||
}
|
||||
else if (lSideOne->getFrom()->equals(lSideTwo->getTo())) {
|
||||
bottomLeft = lSideOne->getFrom();
|
||||
maybeTopLeft = lSideOne->getTo();
|
||||
maybeBottomRight = lSideTwo->getFrom();
|
||||
}
|
||||
else if (lSideOne->getTo()->equals(lSideTwo->getFrom())) {
|
||||
bottomLeft = lSideOne->getTo();
|
||||
maybeTopLeft = lSideOne->getFrom();
|
||||
maybeBottomRight = lSideTwo->getTo();
|
||||
}
|
||||
else if (lSideOne->getTo()->equals(lSideTwo->getTo())) {
|
||||
bottomLeft = lSideOne->getTo();
|
||||
maybeTopLeft = lSideOne->getFrom();
|
||||
maybeBottomRight = lSideTwo->getFrom();
|
||||
}
|
||||
else {
|
||||
bottomLeft = lSideTwo->getFrom();
|
||||
maybeTopLeft = lSideOne->getTo();
|
||||
maybeBottomRight = lSideOne->getFrom();
|
||||
}
|
||||
|
||||
// Bottom left is correct but top left and bottom right might be switched
|
||||
std::vector<Ref<CornerPoint> > corners(3);
|
||||
corners[0].reset(maybeTopLeft);
|
||||
corners[1].reset(bottomLeft);
|
||||
corners[2].reset(maybeBottomRight);
|
||||
// Use the dot product trick to sort them out
|
||||
orderBestPatterns(corners);
|
||||
|
||||
// Now we know which is which:
|
||||
Ref<CornerPoint> bottomRight(corners[0]);
|
||||
bottomLeft = corners[1];
|
||||
Ref<CornerPoint> topLeft(corners[2]);
|
||||
|
||||
// Which point didn't we find in relation to the "L" sides? that's the top right corner
|
||||
Ref<CornerPoint> topRight;
|
||||
if (!(pointA->equals(bottomRight) || pointA->equals(bottomLeft) || pointA->equals(topLeft))) {
|
||||
topRight = pointA;
|
||||
} else if (!(pointB->equals(bottomRight) || pointB->equals(bottomLeft) || pointB->equals(topLeft))) {
|
||||
topRight = pointB;
|
||||
} else if (!(pointC->equals(bottomRight) || pointC->equals(bottomLeft) || pointC->equals(topLeft))) {
|
||||
topRight = pointC;
|
||||
} else {
|
||||
topRight = pointD;
|
||||
}
|
||||
|
||||
float topRightX = (bottomRight->getX() - bottomLeft->getX()) + topLeft->getX();
|
||||
float topRightY = (bottomRight->getY() - bottomLeft->getY()) + topLeft->getY();
|
||||
Ref<CornerPoint> topR(new CornerPoint(topRightX,topRightY));
|
||||
|
||||
// Next determine the dimension by tracing along the top or right side and counting black/white
|
||||
// transitions. Since we start inside a black module, we should see a number of transitions
|
||||
// equal to 1 less than the code dimension. Well, actually 2 less, because we are going to
|
||||
// end on a black module:
|
||||
// The top right point is actually the corner of a module, which is one of the two black modules
|
||||
// adjacent to the white module at the top right. Tracing to that corner from either the top left
|
||||
// or bottom right should work here. The number of transitions could be higher than it should be
|
||||
// due to noise. So we try both and take the min.
|
||||
int dimension = min(transitionsBetween(topLeft, topRight)->getTransitions(),
|
||||
transitionsBetween(bottomRight, topRight)->getTransitions());
|
||||
if ((dimension & 0x01) == 1) {
|
||||
// it can't be odd, so, round... up?
|
||||
dimension++;
|
||||
}
|
||||
dimension += 2;
|
||||
|
||||
Ref<PerspectiveTransform> transform = createTransform(topLeft, topR, bottomLeft, bottomRight, dimension);
|
||||
Ref<BitMatrix> bits(sampleGrid(image_, dimension, transform));
|
||||
std::vector<Ref<ResultPoint> > points(4);
|
||||
points[0].reset(pointA);
|
||||
points[1].reset(pointB);
|
||||
points[2].reset(pointC);
|
||||
points[3].reset(pointD);
|
||||
Ref<DetectorResult> detectorResult(new DetectorResult(bits, points, transform));
|
||||
return detectorResult;
|
||||
}
|
||||
|
||||
Ref<ResultPointsAndTransitions> Detector::transitionsBetween(Ref<CornerPoint> from, Ref<CornerPoint> to) {
|
||||
// See QR Code Detector, sizeOfBlackWhiteBlackRun()
|
||||
int fromX = (int) from->getX();
|
||||
int fromY = (int) from->getY();
|
||||
int toX = (int) to->getX();
|
||||
int toY = (int) to->getY();
|
||||
bool steep = abs(toY - fromY) > abs(toX - fromX);
|
||||
if (steep) {
|
||||
int temp = fromX;
|
||||
fromX = fromY;
|
||||
fromY = temp;
|
||||
temp = toX;
|
||||
toX = toY;
|
||||
toY = temp;
|
||||
}
|
||||
|
||||
int dx = abs(toX - fromX);
|
||||
int dy = abs(toY - fromY);
|
||||
int error = -dx >> 1;
|
||||
int ystep = fromY < toY ? 1 : -1;
|
||||
int xstep = fromX < toX ? 1 : -1;
|
||||
int transitions = 0;
|
||||
bool inBlack = image_->get(steep ? fromY : fromX, steep ? fromX : fromY);
|
||||
for (int x = fromX, y = fromY; x != toX; x += xstep) {
|
||||
bool isBlack = image_->get(steep ? y : x, steep ? x : y);
|
||||
if (isBlack != inBlack) {
|
||||
transitions++;
|
||||
inBlack = isBlack;
|
||||
}
|
||||
error += dy;
|
||||
if (error > 0) {
|
||||
if (y == toY) {
|
||||
break;
|
||||
}
|
||||
y += ystep;
|
||||
error -= dx;
|
||||
}
|
||||
}
|
||||
Ref<ResultPointsAndTransitions> result(new ResultPointsAndTransitions(from, to, transitions));
|
||||
return result;
|
||||
}
|
||||
|
||||
Ref<PerspectiveTransform> Detector::createTransform(Ref<ResultPoint> topLeft, Ref<ResultPoint> topRight, Ref <
|
||||
ResultPoint > bottomLeft, Ref<ResultPoint> bottomRight, int dimension) {
|
||||
|
||||
Ref<PerspectiveTransform> transform(PerspectiveTransform::quadrilateralToQuadrilateral(
|
||||
0.0f,
|
||||
0.0f,
|
||||
dimension,
|
||||
0.0f,
|
||||
dimension,
|
||||
dimension,
|
||||
0.0f,
|
||||
dimension,
|
||||
topLeft->getX(),
|
||||
topLeft->getY(),
|
||||
topRight->getX(),
|
||||
topRight->getY(),
|
||||
bottomRight->getX(),
|
||||
bottomRight->getY(),
|
||||
bottomLeft->getX(),
|
||||
bottomLeft->getY()));
|
||||
return transform;
|
||||
}
|
||||
|
||||
Ref<BitMatrix> Detector::sampleGrid(Ref<BitMatrix> image, int dimension, Ref<PerspectiveTransform> transform) {
|
||||
GridSampler &sampler = GridSampler::getInstance();
|
||||
return sampler.sampleGrid(image, dimension, transform);
|
||||
}
|
||||
|
||||
void Detector::insertionSort(std::vector<Ref<ResultPointsAndTransitions> > &vector) {
|
||||
int max = vector.size();
|
||||
bool swapped = true;
|
||||
Ref<ResultPointsAndTransitions> value;
|
||||
Ref<ResultPointsAndTransitions> valueB;
|
||||
do {
|
||||
swapped = false;
|
||||
for (int i = 1; i < max; i++) {
|
||||
value = vector[i-1];
|
||||
if (compare(value, (valueB = vector[i])) > 0) {
|
||||
swapped = true;
|
||||
vector[i-1].reset(valueB);
|
||||
vector[i].reset(value);
|
||||
}
|
||||
}
|
||||
} while (swapped);
|
||||
}
|
||||
void Detector::orderBestPatterns(std::vector<Ref<CornerPoint> > &patterns) {
|
||||
// Find distances between pattern centers
|
||||
float zeroOneDistance = distance(patterns[0]->getX(), patterns[1]->getX(),patterns[0]->getY(), patterns[1]->getY());
|
||||
float oneTwoDistance = distance(patterns[1]->getX(), patterns[2]->getX(),patterns[1]->getY(), patterns[2]->getY());
|
||||
float zeroTwoDistance = distance(patterns[0]->getX(), patterns[2]->getX(),patterns[0]->getY(), patterns[2]->getY());
|
||||
|
||||
Ref<CornerPoint> pointA, pointB, pointC;
|
||||
// Assume one closest to other two is B; A and C will just be guesses at first
|
||||
if (oneTwoDistance >= zeroOneDistance && oneTwoDistance >= zeroTwoDistance) {
|
||||
pointB = patterns[0];
|
||||
pointA = patterns[1];
|
||||
pointC = patterns[2];
|
||||
} else if (zeroTwoDistance >= oneTwoDistance && zeroTwoDistance >= zeroOneDistance) {
|
||||
pointB = patterns[1];
|
||||
pointA = patterns[0];
|
||||
pointC = patterns[2];
|
||||
} else {
|
||||
pointB = patterns[2];
|
||||
pointA = patterns[0];
|
||||
pointC = patterns[1];
|
||||
}
|
||||
|
||||
// Use cross product to figure out whether A and C are correct or flipped.
|
||||
// This asks whether BC x BA has a positive z component, which is the arrangement
|
||||
// we want for A, B, C. If it's negative, then we've got it flipped around and
|
||||
// should swap A and C.
|
||||
if (crossProductZ(pointA, pointB, pointC) < 0.0f) {
|
||||
Ref<CornerPoint> temp = pointA;
|
||||
pointA = pointC;
|
||||
pointC = temp;
|
||||
}
|
||||
|
||||
patterns[0] = pointA;
|
||||
patterns[1] = pointB;
|
||||
patterns[2] = pointC;
|
||||
}
|
||||
|
||||
float Detector::distance(float x1, float x2, float y1, float y2) {
|
||||
float xDiff = x1 - x2;
|
||||
float yDiff = y1 - y2;
|
||||
return (float) sqrt((double) (xDiff * xDiff + yDiff * yDiff));
|
||||
}
|
||||
|
||||
int Detector::compare(Ref<ResultPointsAndTransitions> a, Ref<ResultPointsAndTransitions> b) {
|
||||
return a->getTransitions() - b->getTransitions();
|
||||
}
|
||||
|
||||
float Detector::crossProductZ(Ref<ResultPoint> pointA, Ref<ResultPoint> pointB, Ref<ResultPoint> pointC) {
|
||||
float bX = pointB->getX();
|
||||
float bY = pointB->getY();
|
||||
return ((pointC->getX() - bX) * (pointA->getY() - bY)) - ((pointC->getY() - bY) * (pointA->getX() - bX));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,79 @@
|
|||
#ifndef __DETECTOR_H__
|
||||
#define __DETECTOR_H__
|
||||
|
||||
/*
|
||||
* Detector.h
|
||||
* zxing
|
||||
*
|
||||
* Created by Luiz Silva on 09/02/2010.
|
||||
* Copyright 2010 ZXing authors All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
#include <zxing/common/Counted.h>
|
||||
#include <zxing/common/DetectorResult.h>
|
||||
#include <zxing/common/BitMatrix.h>
|
||||
#include <zxing/common/PerspectiveTransform.h>
|
||||
#include <zxing/datamatrix/detector/MonochromeRectangleDetector.h>
|
||||
|
||||
|
||||
namespace zxing {
|
||||
namespace datamatrix {
|
||||
|
||||
class ResultPointsAndTransitions : public Counted {
|
||||
private:
|
||||
Ref<CornerPoint> to_;
|
||||
Ref<CornerPoint> from_;
|
||||
int transitions_;
|
||||
|
||||
public:
|
||||
ResultPointsAndTransitions();
|
||||
ResultPointsAndTransitions(Ref<CornerPoint> from, Ref<CornerPoint> to, int transitions);
|
||||
Ref<CornerPoint> getFrom();
|
||||
Ref<CornerPoint> getTo();
|
||||
int getTransitions();
|
||||
};
|
||||
|
||||
class Detector : public Counted {
|
||||
private:
|
||||
Ref<BitMatrix> image_;
|
||||
|
||||
protected:
|
||||
Ref<BitMatrix> sampleGrid(Ref<BitMatrix> image, int dimension, Ref<PerspectiveTransform> transform);
|
||||
|
||||
void insertionSort(std::vector<Ref<ResultPointsAndTransitions> >& vector);
|
||||
|
||||
Ref<ResultPointsAndTransitions> transitionsBetween(Ref<CornerPoint> from, Ref<CornerPoint> to);
|
||||
int min(int a, int b) { return a > b ? b : a; };
|
||||
|
||||
public:
|
||||
Ref<BitMatrix> getImage();
|
||||
Detector(Ref<BitMatrix> image);
|
||||
|
||||
virtual Ref<PerspectiveTransform> createTransform(Ref<ResultPoint> topLeft, Ref<ResultPoint> topRight, Ref <
|
||||
ResultPoint > bottomLeft, Ref<ResultPoint> bottomRight, int dimension);
|
||||
|
||||
Ref<DetectorResult> detect();
|
||||
void orderBestPatterns(std::vector<Ref<CornerPoint> > &patterns);
|
||||
float distance(float x1, float x2, float y1, float y2);
|
||||
private:
|
||||
int compare(Ref<ResultPointsAndTransitions> a, Ref<ResultPointsAndTransitions> b);
|
||||
float crossProductZ(Ref<ResultPoint> pointA, Ref<ResultPoint> pointB, Ref<ResultPoint> pointC);
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif // __DETECTOR_H__
|
|
@ -0,0 +1,172 @@
|
|||
/*
|
||||
* MonochromeRectangleDetector.cpp
|
||||
* zxing
|
||||
*
|
||||
* Created by Luiz Silva on 09/02/2010.
|
||||
* Copyright 2010 ZXing authors All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <zxing/ReaderException.h>
|
||||
#include <zxing/datamatrix/detector/MonochromeRectangleDetector.h>
|
||||
#include <sstream>
|
||||
|
||||
namespace zxing {
|
||||
namespace datamatrix {
|
||||
|
||||
std::vector<Ref<CornerPoint> > MonochromeRectangleDetector::detect() {
|
||||
int height = image_->getHeight();
|
||||
int width = image_->getWidth();
|
||||
int halfHeight = height >> 1;
|
||||
int halfWidth = width >> 1;
|
||||
int deltaY = max(1, height / (MAX_MODULES << 3));
|
||||
int deltaX = max(1, width / (MAX_MODULES << 3));
|
||||
|
||||
int top = 0;
|
||||
int bottom = height;
|
||||
int left = 0;
|
||||
int right = width;
|
||||
Ref<CornerPoint> pointA(findCornerFromCenter(halfWidth, 0, left, right,
|
||||
halfHeight, -deltaY, top, bottom, halfWidth >> 1));
|
||||
top = (int) pointA->getY() - 1;
|
||||
Ref<CornerPoint> pointB(findCornerFromCenter(halfWidth, -deltaX, left, right,
|
||||
halfHeight, 0, top, bottom, halfHeight >> 1));
|
||||
left = (int) pointB->getX() - 1;
|
||||
Ref<CornerPoint> pointC(findCornerFromCenter(halfWidth, deltaX, left, right,
|
||||
halfHeight, 0, top, bottom, halfHeight >> 1));
|
||||
right = (int) pointC->getX() + 1;
|
||||
Ref<CornerPoint> pointD(findCornerFromCenter(halfWidth, 0, left, right,
|
||||
halfHeight, deltaY, top, bottom, halfWidth >> 1));
|
||||
bottom = (int) pointD->getY() + 1;
|
||||
|
||||
// Go try to find point A again with better information -- might have been off at first.
|
||||
pointA.reset(findCornerFromCenter(halfWidth, 0, left, right,
|
||||
halfHeight, -deltaY, top, bottom, halfWidth >> 2));
|
||||
std::vector<Ref<CornerPoint> > corners(4);
|
||||
|
||||
corners[0].reset(pointA);
|
||||
corners[1].reset(pointB);
|
||||
corners[2].reset(pointC);
|
||||
corners[3].reset(pointD);
|
||||
return corners;
|
||||
}
|
||||
|
||||
Ref<CornerPoint> MonochromeRectangleDetector::findCornerFromCenter(int centerX, int deltaX, int left, int right,
|
||||
int centerY, int deltaY, int top, int bottom, int maxWhiteRun) {
|
||||
Ref<TwoInts> lastRange(NULL);
|
||||
for (int y = centerY, x = centerX;
|
||||
y < bottom && y >= top && x < right && x >= left;
|
||||
y += deltaY, x += deltaX) {
|
||||
Ref<TwoInts> range(NULL);
|
||||
if (deltaX == 0) {
|
||||
// horizontal slices, up and down
|
||||
range = blackWhiteRange(y, maxWhiteRun, left, right, true);
|
||||
} else {
|
||||
// vertical slices, left and right
|
||||
range = blackWhiteRange(x, maxWhiteRun, top, bottom, false);
|
||||
}
|
||||
if (range == NULL) {
|
||||
if (lastRange == NULL) {
|
||||
throw ReaderException("Couldn't find corners (lastRange = NULL) ");
|
||||
} else {
|
||||
// lastRange was found
|
||||
if (deltaX == 0) {
|
||||
int lastY = y - deltaY;
|
||||
if (lastRange->start < centerX) {
|
||||
if (lastRange->end > centerX) {
|
||||
// straddle, choose one or the other based on direction
|
||||
Ref<CornerPoint> result(new CornerPoint(deltaY > 0 ? lastRange->start : lastRange->end, lastY));
|
||||
return result;
|
||||
}
|
||||
Ref<CornerPoint> result(new CornerPoint(lastRange->start, lastY));
|
||||
return result;
|
||||
} else {
|
||||
Ref<CornerPoint> result(new CornerPoint(lastRange->end, lastY));
|
||||
return result;
|
||||
}
|
||||
} else {
|
||||
int lastX = x - deltaX;
|
||||
if (lastRange->start < centerY) {
|
||||
if (lastRange->end > centerY) {
|
||||
Ref<CornerPoint> result(new CornerPoint(lastX, deltaX < 0 ? lastRange->start : lastRange->end));
|
||||
return result;
|
||||
}
|
||||
Ref<CornerPoint> result(new CornerPoint(lastX, lastRange->start));
|
||||
return result;
|
||||
} else {
|
||||
Ref<CornerPoint> result(new CornerPoint(lastX, lastRange->end));
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
lastRange = range;
|
||||
}
|
||||
throw ReaderException("Couldn't find corners");
|
||||
}
|
||||
|
||||
Ref<TwoInts> MonochromeRectangleDetector::blackWhiteRange(int fixedDimension, int maxWhiteRun, int minDim, int maxDim,
|
||||
bool horizontal) {
|
||||
|
||||
int center = (minDim + maxDim) >> 1;
|
||||
|
||||
// Scan left/up first
|
||||
int start = center;
|
||||
while (start >= minDim) {
|
||||
if (horizontal ? image_->get(start, fixedDimension) : image_->get(fixedDimension, start)) {
|
||||
start--;
|
||||
} else {
|
||||
int whiteRunStart = start;
|
||||
do {
|
||||
start--;
|
||||
} while (start >= minDim && !(horizontal ? image_->get(start, fixedDimension) :
|
||||
image_->get(fixedDimension, start)));
|
||||
int whiteRunSize = whiteRunStart - start;
|
||||
if (start < minDim || whiteRunSize > maxWhiteRun) {
|
||||
start = whiteRunStart;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
start++;
|
||||
|
||||
// Then try right/down
|
||||
int end = center;
|
||||
while (end < maxDim) {
|
||||
if (horizontal ? image_->get(end, fixedDimension) : image_->get(fixedDimension, end)) {
|
||||
end++;
|
||||
} else {
|
||||
int whiteRunStart = end;
|
||||
do {
|
||||
end++;
|
||||
} while (end < maxDim && !(horizontal ? image_->get(end, fixedDimension) :
|
||||
image_->get(fixedDimension, end)));
|
||||
int whiteRunSize = end - whiteRunStart;
|
||||
if (end >= maxDim || whiteRunSize > maxWhiteRun) {
|
||||
end = whiteRunStart;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
end--;
|
||||
Ref<TwoInts> result(NULL);
|
||||
if (end > start) {
|
||||
result = new TwoInts;
|
||||
result->start = start;
|
||||
result->end = end;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
#ifndef __MONOCHROMERECTANGLEDETECTOR_H__
|
||||
#define __MONOCHROMERECTANGLEDETECTOR_H__
|
||||
|
||||
/*
|
||||
* MonochromeRectangleDetector.h
|
||||
* zxing
|
||||
*
|
||||
* Created by Luiz Silva on 09/02/2010.
|
||||
* Copyright 2010 ZXing authors All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <vector>
|
||||
#include <zxing/ReaderException.h>
|
||||
#include <zxing/ResultPoint.h>
|
||||
#include <zxing/common/BitMatrix.h>
|
||||
#include <zxing/common/Counted.h>
|
||||
#include <zxing/datamatrix/detector/CornerPoint.h>
|
||||
|
||||
namespace zxing {
|
||||
namespace datamatrix {
|
||||
|
||||
struct TwoInts: public Counted {
|
||||
int start;
|
||||
int end;
|
||||
};
|
||||
|
||||
class MonochromeRectangleDetector : public Counted {
|
||||
private:
|
||||
static const int MAX_MODULES = 32;
|
||||
Ref<BitMatrix> image_;
|
||||
|
||||
public:
|
||||
MonochromeRectangleDetector(Ref<BitMatrix> image) : image_(image) { };
|
||||
|
||||
std::vector<Ref<CornerPoint> > detect();
|
||||
|
||||
private:
|
||||
Ref<CornerPoint> findCornerFromCenter(int centerX, int deltaX, int left, int right,
|
||||
int centerY, int deltaY, int top, int bottom, int maxWhiteRun);
|
||||
|
||||
Ref<TwoInts> blackWhiteRange(int fixedDimension, int maxWhiteRun, int minDim, int maxDim,
|
||||
bool horizontal);
|
||||
|
||||
int max(int a, float b) { return (float) a > b ? a : (int) b;};
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif // __MONOCHROMERECTANGLEDETECTOR_H__
|
|
@ -24,13 +24,14 @@
|
|||
#include <zxing/ReaderException.h>
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
#include <sstream>
|
||||
|
||||
namespace zxing {
|
||||
namespace oned {
|
||||
|
||||
const int CODE_PATTERNS_LENGHT = 107;
|
||||
const int countersLenght = 6;
|
||||
static const int CODE_PATTERNS[CODE_PATTERNS_LENGHT][countersLenght] = {
|
||||
const int CODE_PATTERNS_LENGTH = 107;
|
||||
const int countersLength = 6;
|
||||
static const int CODE_PATTERNS[CODE_PATTERNS_LENGTH][countersLength] = {
|
||||
{2, 1, 2, 2, 2, 2}, /* 0 */
|
||||
{2, 2, 2, 1, 2, 2},
|
||||
{2, 2, 2, 2, 2, 1},
|
||||
|
@ -155,7 +156,7 @@ namespace zxing {
|
|||
}
|
||||
|
||||
int counterPosition = 0;
|
||||
int counters[countersLenght] = {0,0,0,0,0,0};
|
||||
int counters[countersLength] = {0,0,0,0,0,0};
|
||||
int patternStart = rowOffset;
|
||||
bool isWhite = false;
|
||||
int patternLength = sizeof(counters) / sizeof(int);
|
||||
|
@ -166,10 +167,10 @@ namespace zxing {
|
|||
counters[counterPosition]++;
|
||||
} else {
|
||||
if (counterPosition == patternLength - 1) {
|
||||
int bestVariance = MAX_AVG_VARIANCE;
|
||||
unsigned int bestVariance = MAX_AVG_VARIANCE;
|
||||
int bestMatch = -1;
|
||||
for (int startCode = CODE_START_A; startCode <= CODE_START_C; startCode++) {
|
||||
int variance = patternMatchVariance(counters, sizeof(counters)/sizeof(int), CODE_PATTERNS[startCode], MAX_INDIVIDUAL_VARIANCE);
|
||||
unsigned int variance = patternMatchVariance(counters, sizeof(counters)/sizeof(int), CODE_PATTERNS[startCode], MAX_INDIVIDUAL_VARIANCE);
|
||||
if (variance < bestVariance) {
|
||||
bestVariance = variance;
|
||||
bestMatch = startCode;
|
||||
|
@ -204,16 +205,16 @@ namespace zxing {
|
|||
|
||||
int Code128Reader::decodeCode(Ref<BitArray> row, int counters[], int countersCount, int rowOffset){
|
||||
recordPattern(row, rowOffset, counters, countersCount);
|
||||
int bestVariance = MAX_AVG_VARIANCE; // worst variance we'll accept
|
||||
unsigned int bestVariance = MAX_AVG_VARIANCE; // worst variance we'll accept
|
||||
int bestMatch = -1;
|
||||
for (int d = 0; d < CODE_PATTERNS_LENGHT; d++) {
|
||||
int pattern[countersLenght];
|
||||
for (int d = 0; d < CODE_PATTERNS_LENGTH; d++) {
|
||||
int pattern[countersLength];
|
||||
|
||||
for(int ind = 0; ind< countersLenght; ind++){
|
||||
for(int ind = 0; ind< countersLength; ind++){
|
||||
pattern[ind] = CODE_PATTERNS[d][ind];
|
||||
}
|
||||
// memcpy(pattern, CODE_PATTERNS[d], countersLenght);
|
||||
int variance = patternMatchVariance(counters, countersCount, pattern, MAX_INDIVIDUAL_VARIANCE);
|
||||
// memcpy(pattern, CODE_PATTERNS[d], countersLength);
|
||||
unsigned int variance = patternMatchVariance(counters, countersCount, pattern, MAX_INDIVIDUAL_VARIANCE);
|
||||
if (variance < bestVariance) {
|
||||
bestVariance = variance;
|
||||
bestMatch = d;
|
||||
|
@ -243,6 +244,7 @@ namespace zxing {
|
|||
codeSet = CODE_CODE_C;
|
||||
break;
|
||||
default:
|
||||
delete [] startPatternInfo;
|
||||
throw ReaderException("");
|
||||
}
|
||||
|
||||
|
@ -250,11 +252,11 @@ namespace zxing {
|
|||
bool isNextShifted = false;
|
||||
|
||||
std::string tmpResultString;
|
||||
|
||||
std::stringstream tmpResultSStr; // used if its Code 128C
|
||||
|
||||
int lastStart = startPatternInfo[0];
|
||||
int nextStart = startPatternInfo[1];
|
||||
int counters[countersLenght] = {0,0,0,0,0,0};
|
||||
int counters[countersLength] = {0,0,0,0,0,0};
|
||||
|
||||
int lastCode = 0;
|
||||
int code = 0;
|
||||
|
@ -271,7 +273,12 @@ namespace zxing {
|
|||
lastCode = code;
|
||||
|
||||
// Decode another code from image
|
||||
try {
|
||||
code = decodeCode(row, counters, sizeof(counters)/sizeof(int), nextStart);
|
||||
} catch (ReaderException re) {
|
||||
delete [] startPatternInfo;
|
||||
throw re;
|
||||
}
|
||||
|
||||
// Remember whether the last code was printable or not (excluding CODE_STOP)
|
||||
if (code != CODE_STOP) {
|
||||
|
@ -286,8 +293,8 @@ namespace zxing {
|
|||
|
||||
// Advance to where the next code will to start
|
||||
lastStart = nextStart;
|
||||
int _countersLenght = sizeof(counters) / sizeof(int);
|
||||
for (int i = 0; i < _countersLenght; i++) {
|
||||
int _countersLength = sizeof(counters) / sizeof(int);
|
||||
for (int i = 0; i < _countersLength; i++) {
|
||||
nextStart += counters[i];
|
||||
}
|
||||
|
||||
|
@ -296,6 +303,7 @@ namespace zxing {
|
|||
case CODE_START_A:
|
||||
case CODE_START_B:
|
||||
case CODE_START_C:
|
||||
delete [] startPatternInfo;
|
||||
throw ReaderException("");
|
||||
}
|
||||
|
||||
|
@ -366,11 +374,11 @@ namespace zxing {
|
|||
}
|
||||
break;
|
||||
case CODE_CODE_C:
|
||||
// the code read in this case is the number encoded directly
|
||||
if (code < 100) {
|
||||
if (code < 10) {
|
||||
tmpResultString.append(1, '0');
|
||||
}
|
||||
tmpResultString.append(1, code);
|
||||
if (code < 10)
|
||||
tmpResultSStr << '0';
|
||||
tmpResultSStr << code;
|
||||
} else {
|
||||
if (code != CODE_STOP) {
|
||||
lastCharacterWasPrintable = false;
|
||||
|
@ -418,6 +426,7 @@ namespace zxing {
|
|||
nextStart++;
|
||||
}
|
||||
if (!row->isRange(nextStart, fminl(width, nextStart + (nextStart - lastStart) / 2), false)) {
|
||||
delete [] startPatternInfo;
|
||||
throw ReaderException("");
|
||||
}
|
||||
|
||||
|
@ -425,9 +434,13 @@ namespace zxing {
|
|||
checksumTotal -= multiplier * lastCode;
|
||||
// lastCode is the checksum then:
|
||||
if (checksumTotal % 103 != lastCode) {
|
||||
delete [] startPatternInfo;
|
||||
throw ReaderException("");
|
||||
}
|
||||
|
||||
if (codeSet == CODE_CODE_C)
|
||||
tmpResultString.append(tmpResultSStr.str());
|
||||
|
||||
// Need to pull out the check digits from string
|
||||
int resultLength = tmpResultString.length();
|
||||
// Only bother if the result had at least one character, and if the checksum digit happened to
|
||||
|
@ -444,6 +457,7 @@ namespace zxing {
|
|||
// String resultString(tmpResultString);
|
||||
|
||||
if (tmpResultString.length() == 0) {
|
||||
delete [] startPatternInfo;
|
||||
// Almost surely a false positive
|
||||
throw ReaderException("");
|
||||
}
|
||||
|
|
|
@ -27,7 +27,7 @@ namespace zxing {
|
|||
class Code128Reader : public OneDReader {
|
||||
|
||||
private:
|
||||
static const int MAX_AVG_VARIANCE = (int) (PATTERN_MATCH_RESULT_SCALE_FACTOR * 0.25f);
|
||||
static const unsigned int MAX_AVG_VARIANCE = (unsigned int) (PATTERN_MATCH_RESULT_SCALE_FACTOR * 0.25f);
|
||||
static const int MAX_INDIVIDUAL_VARIANCE = (int) (PATTERN_MATCH_RESULT_SCALE_FACTOR * 0.7f);
|
||||
|
||||
static const int CODE_SHIFT = 98;
|
||||
|
|
|
@ -26,315 +26,333 @@
|
|||
#include <limits.h>
|
||||
|
||||
namespace zxing {
|
||||
namespace oned {
|
||||
|
||||
static const char* ALPHABET = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ-. *$/+%";
|
||||
|
||||
|
||||
/**
|
||||
* These represent the encodings of characters, as patterns of wide and narrow bars.
|
||||
* The 9 least-significant bits of each int correspond to the pattern of wide and narrow,
|
||||
* with 1s representing "wide" and 0s representing narrow.
|
||||
*/
|
||||
const int CHARACTER_ENCODINGS_LEN = 44;
|
||||
static int CHARACTER_ENCODINGS[CHARACTER_ENCODINGS_LEN] = {
|
||||
0x034, 0x121, 0x061, 0x160, 0x031, 0x130, 0x070, 0x025, 0x124, 0x064, // 0-9
|
||||
0x109, 0x049, 0x148, 0x019, 0x118, 0x058, 0x00D, 0x10C, 0x04C, 0x01C, // A-J
|
||||
0x103, 0x043, 0x142, 0x013, 0x112, 0x052, 0x007, 0x106, 0x046, 0x016, // K-T
|
||||
0x181, 0x0C1, 0x1C0, 0x091, 0x190, 0x0D0, 0x085, 0x184, 0x0C4, 0x094, // U-*
|
||||
0x0A8, 0x0A2, 0x08A, 0x02A // $-%
|
||||
};
|
||||
|
||||
static int ASTERISK_ENCODING = 0x094;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Creates a reader that assumes all encoded data is data, and does not treat the final
|
||||
* character as a check digit. It will not decoded "extended Code 39" sequences.
|
||||
*/
|
||||
Code39Reader::Code39Reader(){
|
||||
ALPHABET_STRING = new std::string("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ-. *$/+%");
|
||||
usingCheckDigit = false;
|
||||
extendedMode = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a reader that can be configured to check the last character as a check digit.
|
||||
* It will not decoded "extended Code 39" sequences.
|
||||
*
|
||||
* @param usingCheckDigit if true, treat the last data character as a check digit, not
|
||||
* data, and verify that the checksum passes.
|
||||
*/
|
||||
Code39Reader::Code39Reader(bool usingCheckDigit_){
|
||||
ALPHABET_STRING = new std::string("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ-. *$/+%");
|
||||
usingCheckDigit = usingCheckDigit_;
|
||||
extendedMode = false;
|
||||
}
|
||||
|
||||
namespace oned {
|
||||
|
||||
|
||||
Ref<Result> Code39Reader::decodeRow(int rowNumber, Ref<BitArray> row){
|
||||
int* 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 {
|
||||
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;
|
||||
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) {
|
||||
delete resultString;
|
||||
resultString = decodeExtended(tmpResultString);
|
||||
}
|
||||
|
||||
if (tmpResultString.length() == 0) {
|
||||
// Almost surely a false positive
|
||||
throw ReaderException("");
|
||||
}
|
||||
|
||||
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 width = row->getSize();
|
||||
int rowOffset = 0;
|
||||
while (rowOffset < width) {
|
||||
if (row->get(rowOffset)) {
|
||||
break;
|
||||
}
|
||||
rowOffset++;
|
||||
}
|
||||
|
||||
int counterPosition = 0;
|
||||
int countersLen = 9;
|
||||
int* counters = new int[countersLen];
|
||||
for (int i=0; i<countersLen; i++) {
|
||||
counters[i] = 0;
|
||||
}
|
||||
int patternStart = rowOffset;
|
||||
bool isWhite = false;
|
||||
int patternLength = countersLen;
|
||||
|
||||
for (int i = rowOffset; i < width; i++) {
|
||||
bool pixel = row->get(i);
|
||||
if (pixel ^ isWhite) {
|
||||
counters[counterPosition]++;
|
||||
} else {
|
||||
if (counterPosition == patternLength - 1) {
|
||||
if (toNarrowWidePattern(counters, countersLen) == ASTERISK_ENCODING) {
|
||||
// Look for whitespace before start pattern, >= 50% of width of start pattern
|
||||
if (row->isRange(fmaxl(0, patternStart - (i - patternStart) / 2), patternStart, false)) {
|
||||
int* resultValue = new int[2];
|
||||
resultValue[0] = patternStart;
|
||||
resultValue[1] = i;
|
||||
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("");
|
||||
}
|
||||
|
||||
// For efficiency, returns -1 on failure. Not throwing here saved as many as 700 exceptions
|
||||
// per image when using some of our blackbox images.
|
||||
int Code39Reader::toNarrowWidePattern(int counters[], int countersLen){
|
||||
int numCounters = countersLen;
|
||||
int maxNarrowCounter = 0;
|
||||
int wideCounters;
|
||||
do {
|
||||
int minCounter = INT_MAX;
|
||||
for (int i = 0; i < numCounters; i++) {
|
||||
int counter = counters[i];
|
||||
if (counter < minCounter && counter > maxNarrowCounter) {
|
||||
minCounter = counter;
|
||||
}
|
||||
}
|
||||
maxNarrowCounter = minCounter;
|
||||
wideCounters = 0;
|
||||
int totalWideCountersWidth = 0;
|
||||
int pattern = 0;
|
||||
for (int i = 0; i < numCounters; i++) {
|
||||
int counter = counters[i];
|
||||
if (counters[i] > maxNarrowCounter) {
|
||||
pattern |= 1 << (numCounters - 1 - i);
|
||||
wideCounters++;
|
||||
totalWideCountersWidth += counter;
|
||||
}
|
||||
}
|
||||
if (wideCounters == 3) {
|
||||
// Found 3 wide counters, but are they close enough in width?
|
||||
// We can perform a cheap, conservative check to see if any individual
|
||||
// counter is more than 1.5 times the average:
|
||||
for (int i = 0; i < numCounters && wideCounters > 0; i++) {
|
||||
int counter = counters[i];
|
||||
if (counters[i] > maxNarrowCounter) {
|
||||
wideCounters--;
|
||||
// totalWideCountersWidth = 3 * average, so this checks if counter >= 3/2 * average
|
||||
if ((counter << 1) >= totalWideCountersWidth) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return pattern;
|
||||
}
|
||||
} while (wideCounters > 3);
|
||||
return -1;
|
||||
}
|
||||
|
||||
char Code39Reader::patternToChar(int pattern){
|
||||
for (int i = 0; i < CHARACTER_ENCODINGS_LEN; i++) {
|
||||
if (CHARACTER_ENCODINGS[i] == pattern) {
|
||||
return ALPHABET[i];
|
||||
}
|
||||
}
|
||||
throw ReaderException("");
|
||||
}
|
||||
|
||||
Ref<String> Code39Reader::decodeExtended(std::string encoded){
|
||||
int length = encoded.length();
|
||||
std::string tmpDecoded;
|
||||
for (int i = 0; i < length; i++) {
|
||||
char c = encoded[i];
|
||||
if (c == '+' || c == '$' || c == '%' || c == '/') {
|
||||
char next = encoded[i + 1];
|
||||
char decodedChar = '\0';
|
||||
switch (c) {
|
||||
case '+':
|
||||
// +A to +Z map to a to z
|
||||
if (next >= 'A' && next <= 'Z') {
|
||||
decodedChar = (char) (next + 32);
|
||||
} else {
|
||||
throw ReaderException("");
|
||||
}
|
||||
break;
|
||||
case '$':
|
||||
// $A to $Z map to control codes SH to SB
|
||||
if (next >= 'A' && next <= 'Z') {
|
||||
decodedChar = (char) (next - 64);
|
||||
} else {
|
||||
throw ReaderException("");
|
||||
}
|
||||
break;
|
||||
case '%':
|
||||
// %A to %E map to control codes ESC to US
|
||||
if (next >= 'A' && next <= 'E') {
|
||||
decodedChar = (char) (next - 38);
|
||||
} else if (next >= 'F' && next <= 'W') {
|
||||
decodedChar = (char) (next - 11);
|
||||
} else {
|
||||
throw ReaderException("");
|
||||
}
|
||||
break;
|
||||
case '/':
|
||||
// /A to /O map to ! to , and /Z maps to :
|
||||
if (next >= 'A' && next <= 'O') {
|
||||
decodedChar = (char) (next - 32);
|
||||
} else if (next == 'Z') {
|
||||
decodedChar = ':';
|
||||
} else {
|
||||
throw ReaderException("");
|
||||
}
|
||||
break;
|
||||
}
|
||||
tmpDecoded.append(1, decodedChar);
|
||||
// bump up i again since we read two characters
|
||||
i++;
|
||||
} else {
|
||||
tmpDecoded.append(1, c);
|
||||
}
|
||||
}
|
||||
Ref<String> decoded(new String(tmpDecoded));
|
||||
return decoded;
|
||||
}
|
||||
|
||||
static const char* ALPHABET = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ-. *$/+%";
|
||||
|
||||
Code39Reader::~Code39Reader(){
|
||||
delete ALPHABET_STRING;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
/**
|
||||
* These represent the encodings of characters, as patterns of wide and narrow
|
||||
* bars.
|
||||
* The 9 least-significant bits of each int correspond to the pattern of wide
|
||||
* and narrow, with 1s representing "wide" and 0s representing narrow.
|
||||
*/
|
||||
const int CHARACTER_ENCODINGS_LEN = 44;
|
||||
static int CHARACTER_ENCODINGS[CHARACTER_ENCODINGS_LEN] = {
|
||||
0x034, 0x121, 0x061, 0x160, 0x031, 0x130, 0x070, 0x025, 0x124, 0x064, // 0-9
|
||||
0x109, 0x049, 0x148, 0x019, 0x118, 0x058, 0x00D, 0x10C, 0x04C, 0x01C, // A-J
|
||||
0x103, 0x043, 0x142, 0x013, 0x112, 0x052, 0x007, 0x106, 0x046, 0x016, // K-T
|
||||
0x181, 0x0C1, 0x1C0, 0x091, 0x190, 0x0D0, 0x085, 0x184, 0x0C4, 0x094, // U-*
|
||||
0x0A8, 0x0A2, 0x08A, 0x02A // $-%
|
||||
};
|
||||
|
||||
static int ASTERISK_ENCODING = 0x094;
|
||||
static const char* ALPHABET_STRING =
|
||||
"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ-. *$/+%";
|
||||
|
||||
|
||||
/**
|
||||
* Creates a reader that assumes all encoded data is data, and does not treat
|
||||
* the final character as a check digit. It will not decoded "extended
|
||||
* Code 39" sequences.
|
||||
*/
|
||||
Code39Reader::Code39Reader() : alphabet_string(ALPHABET_STRING),
|
||||
usingCheckDigit(false),
|
||||
extendedMode(false) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a reader that can be configured to check the last character as a
|
||||
* check digit. It will not decoded "extended Code 39" sequences.
|
||||
*
|
||||
* @param usingCheckDigit if true, treat the last data character as a check
|
||||
* digit, not data, and verify that the checksum passes.
|
||||
*/
|
||||
Code39Reader::Code39Reader(bool usingCheckDigit_) :
|
||||
alphabet_string(ALPHABET_STRING),
|
||||
usingCheckDigit(usingCheckDigit_),
|
||||
extendedMode(false) {
|
||||
}
|
||||
|
||||
|
||||
|
||||
Ref<Result> Code39Reader::decodeRow(int rowNumber, Ref<BitArray> row){
|
||||
int* 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");
|
||||
}
|
||||
|
||||
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) {
|
||||
delete resultString;
|
||||
resultString = decodeExtended(tmpResultString);
|
||||
}
|
||||
|
||||
if (tmpResultString.length() == 0) {
|
||||
delete [] start;
|
||||
// Almost surely a false positive
|
||||
throw ReaderException("");
|
||||
}
|
||||
|
||||
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 width = row->getSize();
|
||||
int rowOffset = 0;
|
||||
while (rowOffset < width) {
|
||||
if (row->get(rowOffset)) {
|
||||
break;
|
||||
}
|
||||
rowOffset++;
|
||||
}
|
||||
|
||||
int counterPosition = 0;
|
||||
int countersLen = 9;
|
||||
int* counters = new int[countersLen];
|
||||
for (int i=0; i<countersLen; i++) {
|
||||
counters[i] = 0;
|
||||
}
|
||||
int patternStart = rowOffset;
|
||||
bool isWhite = false;
|
||||
int patternLength = countersLen;
|
||||
|
||||
for (int i = rowOffset; i < width; i++) {
|
||||
bool pixel = row->get(i);
|
||||
if (pixel ^ isWhite) {
|
||||
counters[counterPosition]++;
|
||||
} else {
|
||||
if (counterPosition == patternLength - 1) {
|
||||
if (toNarrowWidePattern(counters, countersLen) == ASTERISK_ENCODING) {
|
||||
// Look for whitespace before start pattern, >= 50% of width of
|
||||
// start pattern.
|
||||
long double longPatternOffset =
|
||||
fmaxl(0, patternStart - (i - patternStart) / 2);
|
||||
if (row->isRange(longPatternOffset, patternStart, false)) {
|
||||
int* resultValue = new int[2];
|
||||
resultValue[0] = patternStart;
|
||||
resultValue[1] = i;
|
||||
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;
|
||||
}
|
||||
}
|
||||
// IS begin
|
||||
delete [] counters;
|
||||
// IS end
|
||||
throw ReaderException("");
|
||||
}
|
||||
|
||||
// For efficiency, returns -1 on failure. Not throwing here saved as many as
|
||||
// 700 exceptions per image when using some of our blackbox images.
|
||||
int Code39Reader::toNarrowWidePattern(int counters[], int countersLen){
|
||||
int numCounters = countersLen;
|
||||
int maxNarrowCounter = 0;
|
||||
int wideCounters;
|
||||
do {
|
||||
int minCounter = INT_MAX;
|
||||
for (int i = 0; i < numCounters; i++) {
|
||||
int counter = counters[i];
|
||||
if (counter < minCounter && counter > maxNarrowCounter) {
|
||||
minCounter = counter;
|
||||
}
|
||||
}
|
||||
maxNarrowCounter = minCounter;
|
||||
wideCounters = 0;
|
||||
int totalWideCountersWidth = 0;
|
||||
int pattern = 0;
|
||||
for (int i = 0; i < numCounters; i++) {
|
||||
int counter = counters[i];
|
||||
if (counters[i] > maxNarrowCounter) {
|
||||
pattern |= 1 << (numCounters - 1 - i);
|
||||
wideCounters++;
|
||||
totalWideCountersWidth += counter;
|
||||
}
|
||||
}
|
||||
if (wideCounters == 3) {
|
||||
// Found 3 wide counters, but are they close enough in width?
|
||||
// We can perform a cheap, conservative check to see if any individual
|
||||
// counter is more than 1.5 times the average:
|
||||
for (int i = 0; i < numCounters && wideCounters > 0; i++) {
|
||||
int counter = counters[i];
|
||||
if (counters[i] > maxNarrowCounter) {
|
||||
wideCounters--;
|
||||
// totalWideCountersWidth = 3 * average, so this checks if
|
||||
// counter >= 3/2 * average.
|
||||
if ((counter << 1) >= totalWideCountersWidth) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return pattern;
|
||||
}
|
||||
} while (wideCounters > 3);
|
||||
return -1;
|
||||
}
|
||||
|
||||
char Code39Reader::patternToChar(int pattern){
|
||||
for (int i = 0; i < CHARACTER_ENCODINGS_LEN; i++) {
|
||||
if (CHARACTER_ENCODINGS[i] == pattern) {
|
||||
return ALPHABET[i];
|
||||
}
|
||||
}
|
||||
throw ReaderException("");
|
||||
}
|
||||
|
||||
Ref<String> Code39Reader::decodeExtended(std::string encoded){
|
||||
int length = encoded.length();
|
||||
std::string tmpDecoded;
|
||||
for (int i = 0; i < length; i++) {
|
||||
char c = encoded[i];
|
||||
if (c == '+' || c == '$' || c == '%' || c == '/') {
|
||||
char next = encoded[i + 1];
|
||||
char decodedChar = '\0';
|
||||
switch (c) {
|
||||
case '+':
|
||||
// +A to +Z map to a to z
|
||||
if (next >= 'A' && next <= 'Z') {
|
||||
decodedChar = (char) (next + 32);
|
||||
} else {
|
||||
throw ReaderException("");
|
||||
}
|
||||
break;
|
||||
case '$':
|
||||
// $A to $Z map to control codes SH to SB
|
||||
if (next >= 'A' && next <= 'Z') {
|
||||
decodedChar = (char) (next - 64);
|
||||
} else {
|
||||
throw ReaderException("");
|
||||
}
|
||||
break;
|
||||
case '%':
|
||||
// %A to %E map to control codes ESC to US
|
||||
if (next >= 'A' && next <= 'E') {
|
||||
decodedChar = (char) (next - 38);
|
||||
} else if (next >= 'F' && next <= 'W') {
|
||||
decodedChar = (char) (next - 11);
|
||||
} else {
|
||||
throw ReaderException("");
|
||||
}
|
||||
break;
|
||||
case '/':
|
||||
// /A to /O map to ! to , and /Z maps to :
|
||||
if (next >= 'A' && next <= 'O') {
|
||||
decodedChar = (char) (next - 32);
|
||||
} else if (next == 'Z') {
|
||||
decodedChar = ':';
|
||||
} else {
|
||||
throw ReaderException("");
|
||||
}
|
||||
break;
|
||||
}
|
||||
tmpDecoded.append(1, decodedChar);
|
||||
// bump up i again since we read two characters
|
||||
i++;
|
||||
} else {
|
||||
tmpDecoded.append(1, c);
|
||||
}
|
||||
}
|
||||
Ref<String> decoded(new String(tmpDecoded));
|
||||
return decoded;
|
||||
}
|
||||
} // namespace oned
|
||||
} // namespace zxing
|
||||
|
||||
|
|
|
@ -33,7 +33,7 @@ namespace zxing {
|
|||
class Code39Reader : public OneDReader {
|
||||
|
||||
private:
|
||||
std::string* ALPHABET_STRING;
|
||||
std::string alphabet_string;
|
||||
|
||||
bool usingCheckDigit;
|
||||
bool extendedMode;
|
||||
|
@ -49,9 +49,7 @@ namespace zxing {
|
|||
Code39Reader(bool usingCheckDigit_);
|
||||
|
||||
Ref<Result> decodeRow(int rowNumber, Ref<BitArray> row);
|
||||
|
||||
~Code39Reader();
|
||||
};
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -27,20 +27,11 @@ namespace zxing {
|
|||
static const int FIRST_DIGIT_ENCODINGS[10] = {0x00, 0x0B, 0x0D, 0xE, 0x13, 0x19, 0x1C, 0x15, 0x16, 0x1A};
|
||||
|
||||
|
||||
EAN13Reader::EAN13Reader(){
|
||||
decodeMiddleCounters = new int[4];
|
||||
for (int i=0; i<4; i++) {
|
||||
decodeMiddleCounters[i] = 0;
|
||||
}
|
||||
}
|
||||
EAN13Reader::EAN13Reader() { }
|
||||
|
||||
int EAN13Reader::decodeMiddle(Ref<BitArray> row, int startRange[], int startRangeLen, std::string& resultString){
|
||||
int countersLen = 4;
|
||||
int* counters = decodeMiddleCounters;
|
||||
counters[0] = 0;
|
||||
counters[1] = 0;
|
||||
counters[2] = 0;
|
||||
counters[3] = 0;
|
||||
const int countersLen = 4;
|
||||
int counters[countersLen] = { 0, 0, 0, 0 };
|
||||
|
||||
|
||||
int end = row->getSize();
|
||||
|
@ -88,8 +79,5 @@ namespace zxing {
|
|||
BarcodeFormat EAN13Reader::getBarcodeFormat(){
|
||||
return BarcodeFormat_EAN_13;
|
||||
}
|
||||
EAN13Reader::~EAN13Reader(){
|
||||
delete [] decodeMiddleCounters;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,7 +26,6 @@ namespace zxing {
|
|||
class EAN13Reader : public UPCEANReader {
|
||||
|
||||
private:
|
||||
int* decodeMiddleCounters;
|
||||
static void determineFirstDigit(std::string& resultString, int lgPatternFound); //throws ReaderException
|
||||
|
||||
public:
|
||||
|
@ -35,7 +34,6 @@ namespace zxing {
|
|||
int decodeMiddle(Ref<BitArray> row, int startRange[], int startRangeLen, std::string& resultString); //throws ReaderException
|
||||
|
||||
BarcodeFormat getBarcodeFormat();
|
||||
~EAN13Reader();
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue