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:
ftylitak 2010-07-14 09:32:32 +00:00
parent 5a36cea5af
commit 31b5627fee
141 changed files with 6266 additions and 1433 deletions

View file

@ -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);

View file

@ -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

View file

@ -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_;
}

View file

@ -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_ */

View file

@ -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_;
}

View file

@ -33,6 +33,7 @@ namespace zxing {
Ref<BitMatrix> bits_;
Ref<BitArray> array_bits_;
Ref<Binarizer> binarizer_;
int cached_y_;
public:
BinaryBitmap(Ref<Binarizer> binarizer);

View file

@ -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];

View file

@ -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();
};
}

View file

@ -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];
}
}
}

View file

@ -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();
};
}

View file

@ -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;
}
}

View file

@ -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

View file

@ -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,

View file

@ -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

View 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() {
}
}
}

View 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__

View 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();
}
}
}

View 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__

View 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;
}
}
}

View file

@ -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__

View 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;
}
}
}

View 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__

View file

@ -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;
}
}
}

View file

@ -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__

View 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;
}
}
}

View 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__

View 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();
}
}
}

View 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__

View 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));
}
}
}

View 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__

View file

@ -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;
}
}
}

View file

@ -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__

View file

@ -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

View file

@ -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;

View file

@ -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;
}
}
}

View file

@ -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;

View file

@ -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.

View file

@ -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;

View file

@ -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();
};

View file

@ -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;

View file

@ -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

View file

@ -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>

View file

@ -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

View file

@ -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

View file

@ -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_;
}

View file

@ -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_ */

View file

@ -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_;
}

View file

@ -33,6 +33,7 @@ namespace zxing {
Ref<BitMatrix> bits_;
Ref<BitArray> array_bits_;
Ref<Binarizer> binarizer_;
int cached_y_;
public:
BinaryBitmap(Ref<Binarizer> binarizer);

View file

@ -16,7 +16,7 @@ Exception::Exception(const char *msg) :
}
const char* Exception::what() const throw() {
return message;
return message.c_str();
}
Exception::~Exception() throw() {

View file

@ -28,7 +28,7 @@ namespace zxing {
class Exception : public std::exception {
private:
const char * message;
std::string message;
public:
Exception(const char *msg);

View file

@ -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();
};

View file

@ -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];
}
}
}

View file

@ -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();
};
}
}

View file

@ -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();
};
}

View file

@ -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_;
}

View file

@ -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);
};

View file

@ -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;
};
}

View file

@ -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_;
}
};

View file

@ -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;
}
}

View file

@ -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();
};

View file

@ -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 " : " ");

View file

@ -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&);
};
}

View file

@ -172,10 +172,10 @@ public:
T& operator*() {
return *object_;
}
T* operator->() {
T* operator->() const {
return object_;
}
operator T*() {
operator T*() const {
return object_;
}

View file

@ -20,6 +20,7 @@
#include <zxing/common/EdgeDetector.h>
#include <algorithm>
#include <cmath>
using namespace std;

View file

@ -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

View file

@ -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);
};
}

View file

@ -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();

View file

@ -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();
};
}

View file

@ -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";

View file

@ -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);
};
}

View file

@ -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_

View file

@ -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_;
}

View file

@ -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);
};

View file

@ -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

View file

@ -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_;

View 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() {
}
}
}

View 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__

View 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();
}
}
}

View 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__

View 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;
}
}
}

View file

@ -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__

View 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;
}
}
}

View 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__

View file

@ -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;
}
}
}

View file

@ -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__

View 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;
}
}
}

View 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__

View 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();
}
}
}

View 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__

View 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));
}
}
}

View 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__

View file

@ -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;
}
}
}

View file

@ -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__

View file

@ -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("");
}

View file

@ -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;

View file

@ -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

View file

@ -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();
};
};
}
}

View file

@ -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;
}
}
}

View file

@ -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