diff --git a/symbian/QQrDecoder/QQrDecoder.cpp b/symbian/QQrDecoder/QQrDecoder.cpp index a20ad1fa4..7732394e6 100644 --- a/symbian/QQrDecoder/QQrDecoder.cpp +++ b/symbian/QQrDecoder/QQrDecoder.cpp @@ -29,7 +29,8 @@ ****************************************************************************/ #include "QQrDecoder.h" -#include +//#include +#include #include #include @@ -41,7 +42,7 @@ #include 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); diff --git a/symbian/QQrDecoder/QQrDecoder.pro b/symbian/QQrDecoder/QQrDecoder.pro index 6ebb452c5..3da4ea73d 100644 --- a/symbian/QQrDecoder/QQrDecoder.pro +++ b/symbian/QQrDecoder/QQrDecoder.pro @@ -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 diff --git a/symbian/QQrDecoder/QQrDecoder_template.sisx b/symbian/QQrDecoder/QQrDecoder_template.sisx index 55046912c..b60f46ffe 100644 Binary files a/symbian/QQrDecoder/QQrDecoder_template.sisx and b/symbian/QQrDecoder/QQrDecoder_template.sisx differ diff --git a/symbian/QQrDecoder/zxing/Binarizer.cpp b/symbian/QQrDecoder/zxing/Binarizer.cpp index adaab0556..190138291 100644 --- a/symbian/QQrDecoder/zxing/Binarizer.cpp +++ b/symbian/QQrDecoder/zxing/Binarizer.cpp @@ -23,15 +23,17 @@ namespace zxing { - Binarizer::Binarizer(Ref source) : source_(source), array_(NULL), matrix_(NULL) { + Binarizer::Binarizer(Ref source) : source_(source), array_(NULL), matrix_(NULL), cached_y_(-1) { } Binarizer::~Binarizer() { } Ref Binarizer::getBlackRow(int y, Ref row){ - if (array_ == NULL) + if (array_ == NULL && cached_y_ != y) { array_ = estimateBlackRow(y, row); + cached_y_ = y; + } return array_; } diff --git a/symbian/QQrDecoder/zxing/Binarizer.h b/symbian/QQrDecoder/zxing/Binarizer.h index ea1240c0b..694018d72 100644 --- a/symbian/QQrDecoder/zxing/Binarizer.h +++ b/symbian/QQrDecoder/zxing/Binarizer.h @@ -28,24 +28,25 @@ #include namespace zxing { - - class Binarizer : public Counted { - private: - Ref source_; - Ref matrix_; - Ref array_; - - public: - Binarizer(Ref source); - virtual ~Binarizer(); - - virtual Ref estimateBlackRow(int y, Ref row)=0; - Ref getBlackRow(int y, Ref row); - - virtual Ref estimateBlackMatrix() = 0; - Ref getBlackMatrix(); - Ref getSource(); - }; - + +class Binarizer : public Counted { + private: + Ref source_; + Ref array_; + Ref matrix_; + int cached_y_; + + public: + Binarizer(Ref source); + virtual ~Binarizer(); + + virtual Ref estimateBlackRow(int y, Ref row)=0; + Ref getBlackRow(int y, Ref row); + + virtual Ref estimateBlackMatrix() = 0; + Ref getBlackMatrix(); + Ref getSource(); +}; + } #endif /* BINARIZER_H_ */ diff --git a/symbian/QQrDecoder/zxing/BinaryBitmap.cpp b/symbian/QQrDecoder/zxing/BinaryBitmap.cpp index c8fea36e4..ff79b55d5 100644 --- a/symbian/QQrDecoder/zxing/BinaryBitmap.cpp +++ b/symbian/QQrDecoder/zxing/BinaryBitmap.cpp @@ -23,7 +23,7 @@ namespace zxing { - BinaryBitmap::BinaryBitmap(Ref binarizer) : bits_(NULL), array_bits_(NULL), binarizer_(binarizer) { + BinaryBitmap::BinaryBitmap(Ref binarizer) : bits_(NULL), array_bits_(NULL), binarizer_(binarizer), cached_y_(-1) { } @@ -31,8 +31,9 @@ namespace zxing { } Ref BinaryBitmap::getBlackRow(int y, Ref row) { - if (array_bits_ == NULL) { + if (array_bits_ == NULL && cached_y_ != y) { array_bits_ = binarizer_->getBlackRow(y, row); + cached_y_ = y; } return array_bits_; } diff --git a/symbian/QQrDecoder/zxing/BinaryBitmap.h b/symbian/QQrDecoder/zxing/BinaryBitmap.h index ecd9a8549..ddea910c1 100644 --- a/symbian/QQrDecoder/zxing/BinaryBitmap.h +++ b/symbian/QQrDecoder/zxing/BinaryBitmap.h @@ -33,6 +33,7 @@ namespace zxing { Ref bits_; Ref array_bits_; Ref binarizer_; + int cached_y_; public: BinaryBitmap(Ref binarizer); diff --git a/symbian/QQrDecoder/zxing/LuminanceSource.cpp b/symbian/QQrDecoder/zxing/LuminanceSource.cpp index d7af3756b..6c8ef1e6e 100644 --- a/symbian/QQrDecoder/zxing/LuminanceSource.cpp +++ b/symbian/QQrDecoder/zxing/LuminanceSource.cpp @@ -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]; diff --git a/symbian/QQrDecoder/zxing/LuminanceSource.h b/symbian/QQrDecoder/zxing/LuminanceSource.h index fcc65883f..d39f06f38 100644 --- a/symbian/QQrDecoder/zxing/LuminanceSource.h +++ b/symbian/QQrDecoder/zxing/LuminanceSource.h @@ -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(); }; } diff --git a/symbian/QQrDecoder/zxing/MultiFormatReader.cpp b/symbian/QQrDecoder/zxing/MultiFormatReader.cpp index 169283ff2..bacb3cd89 100644 --- a/symbian/QQrDecoder/zxing/MultiFormatReader.cpp +++ b/symbian/QQrDecoder/zxing/MultiFormatReader.cpp @@ -19,7 +19,7 @@ * limitations under the License. */ -#include "MultiFormatReader.h" +#include #include //#include #include @@ -27,23 +27,27 @@ #include namespace zxing { - MultiFormatReader::MultiFormatReader() : readers() { - readers.push_back(Ref(new zxing::qrcode::QRCodeReader())); - //readers.push_back(Ref(new zxing::datamatrix::DataMatrixReader())); - readers.push_back(Ref(new zxing::oned::MultiFormatUPCEANReader())); - readers.push_back(Ref(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 MultiFormatReader::decode(Ref image){ - int size = readers.size(); - for (int i = 0; i < size; i++) { - Ref 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]; + } + } } diff --git a/symbian/QQrDecoder/zxing/MultiFormatReader.h b/symbian/QQrDecoder/zxing/MultiFormatReader.h index 4cbe61bb6..f88ebc979 100644 --- a/symbian/QQrDecoder/zxing/MultiFormatReader.h +++ b/symbian/QQrDecoder/zxing/MultiFormatReader.h @@ -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 >readers; + std::vectorreaders; public: MultiFormatReader(); Ref decode(Ref image); + ~MultiFormatReader(); }; } diff --git a/symbian/QQrDecoder/zxing/common/BitArray.cpp b/symbian/QQrDecoder/zxing/common/BitArray.cpp index 9355d0153..6ba7fd22f 100644 --- a/symbian/QQrDecoder/zxing/common/BitArray.cpp +++ b/symbian/QQrDecoder/zxing/common/BitArray.cpp @@ -107,10 +107,12 @@ vector& BitArray::getBitArray() { return bits_; } void BitArray::reverse() { - unsigned int allBits = numeric_limits::max(); - size_t max = bits_.size(); - for (size_t i = 0; i < max; i++) { - bits_[i] = bits_[i] ^ allBits; + std::vector 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; } } diff --git a/symbian/QQrDecoder/zxing/common/GlobalHistogramBinarizer.cpp b/symbian/QQrDecoder/zxing/common/GlobalHistogramBinarizer.cpp index 61615d326..8b99611eb 100644 --- a/symbian/QQrDecoder/zxing/common/GlobalHistogramBinarizer.cpp +++ b/symbian/QQrDecoder/zxing/common/GlobalHistogramBinarizer.cpp @@ -24,154 +24,160 @@ #include 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 source) : - Binarizer(source) { - - } - - GlobalHistogramBinarizer::~GlobalHistogramBinarizer() { - } - - - Ref GlobalHistogramBinarizer::estimateBlackRow(int y, Ref row){ - vector 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 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 GlobalHistogramBinarizer::estimateBlackMatrix() { - // Faster than working with the reference - LuminanceSource& source = *getSource(); - int width = source.getWidth(); - int height = source.getHeight(); - vector 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 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 &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 source) : + Binarizer(source) { + } + +GlobalHistogramBinarizer::~GlobalHistogramBinarizer() { +} + + +Ref GlobalHistogramBinarizer::estimateBlackRow(int y, + Ref row){ + vector histogram(LUMINANCE_BUCKETS, 0); + LuminanceSource& source = *getSource(); + int width = source.getWidth(); + if (row == NULL || static_cast(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 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 GlobalHistogramBinarizer::estimateBlackMatrix() { + // Faster than working with the reference + LuminanceSource& source = *getSource(); + int width = source.getWidth(); + int height = source.getHeight(); + vector 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 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 &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 + diff --git a/symbian/QQrDecoder/zxing/common/PerspectiveTransform.cpp b/symbian/QQrDecoder/zxing/common/PerspectiveTransform.cpp index 16d132774..5b4ae2e8b 100644 --- a/symbian/QQrDecoder/zxing/common/PerspectiveTransform.cpp +++ b/symbian/QQrDecoder/zxing/common/PerspectiveTransform.cpp @@ -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::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, diff --git a/symbian/QQrDecoder/zxing/common/reedsolomon/GF256.cpp b/symbian/QQrDecoder/zxing/common/reedsolomon/GF256.cpp index 35fc69232..51b621e8e 100644 --- a/symbian/QQrDecoder/zxing/common/reedsolomon/GF256.cpp +++ b/symbian/QQrDecoder/zxing/common/reedsolomon/GF256.cpp @@ -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 diff --git a/symbian/QQrDecoder/zxing/datamatrix/DataMatrixReader.cpp b/symbian/QQrDecoder/zxing/datamatrix/DataMatrixReader.cpp new file mode 100644 index 000000000..8b00161ef --- /dev/null +++ b/symbian/QQrDecoder/zxing/datamatrix/DataMatrixReader.cpp @@ -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 +#include +#include + +namespace zxing { +namespace datamatrix { + +using namespace std; + +DataMatrixReader::DataMatrixReader() : + decoder_() { +} + +Ref DataMatrixReader::decode(Ref 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(detector.detect()); +#ifdef DEBUG + cout << "(2) detected, have detectorResult " << detectorResult.object_ << "\n" << flush; +#endif + + std::vector > 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(decoder_.decode(detectorResult->getBits())); +#ifdef DEBUG + cout << "(4) decoded, have decoderResult " << decoderResult.object_ << "\n" << flush; +#endif + + Ref 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() { +} + +} +} diff --git a/symbian/QQrDecoder/zxing/datamatrix/DataMatrixReader.h b/symbian/QQrDecoder/zxing/datamatrix/DataMatrixReader.h new file mode 100644 index 000000000..4d621c8d9 --- /dev/null +++ b/symbian/QQrDecoder/zxing/datamatrix/DataMatrixReader.h @@ -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 +#include + +namespace zxing { +namespace datamatrix { + +class DataMatrixReader : public Reader { +private: + Decoder decoder_; + +public: + DataMatrixReader(); + virtual Ref decode(Ref image); + virtual ~DataMatrixReader(); + +}; + +} +} + +#endif // __DATA_MATRIX_READER_H__ diff --git a/symbian/QQrDecoder/zxing/datamatrix/Version.cpp b/symbian/QQrDecoder/zxing/datamatrix/Version.cpp new file mode 100644 index 000000000..e48d88ef9 --- /dev/null +++ b/symbian/QQrDecoder/zxing/datamatrix/Version.cpp @@ -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 +#include +#include + +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& ECBlocks::getECBlocks() { + return ecBlocks_; +} + +ECBlocks::~ECBlocks() { + for (size_t i = 0; i < ecBlocks_.size(); i++) { + delete ecBlocks_[i]; + } +} + +vector > 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 &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::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(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(new Version(1, 10, 10, 8, 8, + new ECBlocks(5, new ECB(1, 3))))); + VERSIONS.push_back(Ref(new Version(2, 12, 12, 10, 10, + new ECBlocks(7, new ECB(1, 5))))); + VERSIONS.push_back(Ref(new Version(3, 14, 14, 12, 12, + new ECBlocks(10, new ECB(1, 8))))); + VERSIONS.push_back(Ref(new Version(4, 16, 16, 14, 14, + new ECBlocks(12, new ECB(1, 12))))); + VERSIONS.push_back(Ref(new Version(5, 18, 18, 16, 16, + new ECBlocks(14, new ECB(1, 18))))); + VERSIONS.push_back(Ref(new Version(6, 20, 20, 18, 18, + new ECBlocks(18, new ECB(1, 22))))); + VERSIONS.push_back(Ref(new Version(7, 22, 22, 20, 20, + new ECBlocks(20, new ECB(1, 30))))); + VERSIONS.push_back(Ref(new Version(8, 24, 24, 22, 22, + new ECBlocks(24, new ECB(1, 36))))); + VERSIONS.push_back(Ref(new Version(9, 26, 26, 24, 24, + new ECBlocks(28, new ECB(1, 44))))); + VERSIONS.push_back(Ref(new Version(10, 32, 32, 14, 14, + new ECBlocks(36, new ECB(1, 62))))); + VERSIONS.push_back(Ref(new Version(11, 36, 36, 16, 16, + new ECBlocks(42, new ECB(1, 86))))); + VERSIONS.push_back(Ref(new Version(12, 40, 40, 18, 18, + new ECBlocks(48, new ECB(1, 114))))); + VERSIONS.push_back(Ref(new Version(13, 44, 44, 20, 20, + new ECBlocks(56, new ECB(1, 144))))); + VERSIONS.push_back(Ref(new Version(14, 48, 48, 22, 22, + new ECBlocks(68, new ECB(1, 174))))); + VERSIONS.push_back(Ref(new Version(15, 52, 52, 24, 24, + new ECBlocks(42, new ECB(2, 102))))); + VERSIONS.push_back(Ref(new Version(16, 64, 64, 14, 14, + new ECBlocks(56, new ECB(2, 140))))); + VERSIONS.push_back(Ref(new Version(17, 72, 72, 16, 16, + new ECBlocks(36, new ECB(4, 92))))); + VERSIONS.push_back(Ref(new Version(18, 80, 80, 18, 18, + new ECBlocks(48, new ECB(4, 114))))); + VERSIONS.push_back(Ref(new Version(19, 88, 88, 20, 20, + new ECBlocks(56, new ECB(4, 144))))); + VERSIONS.push_back(Ref(new Version(20, 96, 96, 22, 22, + new ECBlocks(68, new ECB(4, 174))))); + VERSIONS.push_back(Ref(new Version(21, 104, 104, 24, 24, + new ECBlocks(56, new ECB(6, 136))))); + VERSIONS.push_back(Ref(new Version(22, 120, 120, 18, 18, + new ECBlocks(68, new ECB(6, 175))))); + VERSIONS.push_back(Ref(new Version(23, 132, 132, 20, 20, + new ECBlocks(62, new ECB(8, 163))))); + VERSIONS.push_back(Ref(new Version(24, 144, 144, 22, 22, + new ECBlocks(62, new ECB(8, 156), new ECB(2, 155))))); + VERSIONS.push_back(Ref(new Version(25, 8, 18, 6, 16, + new ECBlocks(7, new ECB(1, 5))))); + VERSIONS.push_back(Ref(new Version(26, 8, 32, 6, 14, + new ECBlocks(11, new ECB(1, 10))))); + VERSIONS.push_back(Ref(new Version(27, 12, 26, 10, 24, + new ECBlocks(14, new ECB(1, 16))))); + VERSIONS.push_back(Ref(new Version(28, 12, 36, 10, 16, + new ECBlocks(18, new ECB(1, 22))))); + VERSIONS.push_back(Ref(new Version(29, 16, 36, 10, 16, + new ECBlocks(24, new ECB(1, 32))))); + VERSIONS.push_back(Ref(new Version(30, 16, 48, 14, 22, + new ECBlocks(28, new ECB(1, 49))))); + return VERSIONS.size(); +} +} +} diff --git a/symbian/QQrDecoder/zxing/datamatrix/Version.h b/symbian/QQrDecoder/zxing/datamatrix/Version.h new file mode 100644 index 000000000..d8523fe23 --- /dev/null +++ b/symbian/QQrDecoder/zxing/datamatrix/Version.h @@ -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 +#include +#include +#include + +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 ecBlocks_; +public: + ECBlocks(int ecCodewords, ECB *ecBlocks); + ECBlocks(int ecCodewords, ECB *ecBlocks1, ECB *ecBlocks2); + int getECCodewords(); + std::vector& 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 > VERSIONS; + + ~Version(); + int getVersionNumber(); + int getSymbolSizeRows(); + int getSymbolSizeColumns(); + int getDataRegionSizeRows(); + int getDataRegionSizeColumns(); + int getTotalCodewords(); + ECBlocks* getECBlocks(); + static int buildVersions(); + Ref getVersionForDimensions(int numRows, int numColumns); + +private: + Version(const Version&); + Version & operator=(const Version&); +}; +} +} + +#endif // __VERSION_H__ diff --git a/symbian/QQrDecoder/zxing/datamatrix/decoder/BitMatrixParser.cpp b/symbian/QQrDecoder/zxing/datamatrix/decoder/BitMatrixParser.cpp new file mode 100644 index 000000000..eb5c06f48 --- /dev/null +++ b/symbian/QQrDecoder/zxing/datamatrix/decoder/BitMatrixParser.cpp @@ -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 +#include + +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_(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 BitMatrixParser::readVersion(Ref 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 = parsedVersion_->getVersionForDimensions(numRows, numColumns); + if (version != 0) { + return version; + } + throw ReaderException("Couldn't decode version"); +} + +ArrayRef BitMatrixParser::readCodewords() { + ArrayRef 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 BitMatrixParser::extractDataRegion(Ref 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 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; +} + +} +} diff --git a/symbian/QQrDecoder/zxing/datamatrix/decoder/BitMatrixParser.h b/symbian/QQrDecoder/zxing/datamatrix/decoder/BitMatrixParser.h new file mode 100644 index 000000000..30123d59c --- /dev/null +++ b/symbian/QQrDecoder/zxing/datamatrix/decoder/BitMatrixParser.h @@ -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 +#include +#include +#include +#include + +namespace zxing { +namespace datamatrix { + +class BitMatrixParser : public Counted { +private: + Ref bitMatrix_; + Ref parsedVersion_; + Ref readBitMatrix_; + + int copyBit(size_t x, size_t y, int versionBits); + +public: + BitMatrixParser(Ref bitMatrix); + Ref readVersion(Ref bitMatrix); + ArrayRef 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 extractDataRegion(Ref bitMatrix); +}; + +} +} + +#endif // __BIT_MATRIX_PARSER_DM_H__ diff --git a/symbian/QQrDecoder/zxing/datamatrix/decoder/DataBlock.cpp b/symbian/QQrDecoder/zxing/datamatrix/decoder/DataBlock.cpp new file mode 100644 index 000000000..c87d5f309 --- /dev/null +++ b/symbian/QQrDecoder/zxing/datamatrix/decoder/DataBlock.cpp @@ -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 +#include + +namespace zxing { +namespace datamatrix { + +using namespace std; + +DataBlock::DataBlock(int numDataCodewords, ArrayRef codewords) : + numDataCodewords_(numDataCodewords), codewords_(codewords) { +} + +int DataBlock::getNumDataCodewords() { + return numDataCodewords_; +} + +ArrayRef DataBlock::getCodewords() { + return codewords_; +} + +std::vector > DataBlock::getDataBlocks(ArrayRef 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 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 > 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 buffer(numBlockCodewords); + Ref 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; +} + +} +} diff --git a/symbian/QQrDecoder/zxing/datamatrix/decoder/DataBlock.h b/symbian/QQrDecoder/zxing/datamatrix/decoder/DataBlock.h new file mode 100644 index 000000000..7fc72f655 --- /dev/null +++ b/symbian/QQrDecoder/zxing/datamatrix/decoder/DataBlock.h @@ -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 +#include +#include +#include + +namespace zxing { +namespace datamatrix { + +class DataBlock : public Counted { +private: + int numDataCodewords_; + ArrayRef codewords_; + + DataBlock(int numDataCodewords, ArrayRef codewords); + +public: + static std::vector > getDataBlocks(ArrayRef rawCodewords, Version *version); + + int getNumDataCodewords(); + ArrayRef getCodewords(); +}; + +} +} + +#endif // __DATA_BLOCK_DM_H__ diff --git a/symbian/QQrDecoder/zxing/datamatrix/decoder/DecodedBitStreamParser.cpp b/symbian/QQrDecoder/zxing/datamatrix/decoder/DecodedBitStreamParser.cpp new file mode 100644 index 000000000..9aa2f684c --- /dev/null +++ b/symbian/QQrDecoder/zxing/datamatrix/decoder/DecodedBitStreamParser.cpp @@ -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 +#include +#include + +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 bytes) { + Ref 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 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 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 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 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 + 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 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 bits, ostringstream & result){//, vector 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; +} +} +} + diff --git a/symbian/QQrDecoder/zxing/datamatrix/decoder/DecodedBitStreamParser.h b/symbian/QQrDecoder/zxing/datamatrix/decoder/DecodedBitStreamParser.h new file mode 100644 index 000000000..6a0b26030 --- /dev/null +++ b/symbian/QQrDecoder/zxing/datamatrix/decoder/DecodedBitStreamParser.h @@ -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 +#include +#include +#include +#include + + +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 bits, std::ostringstream &result, std::ostringstream &resultTrailer); + /** + * See ISO 16022:2006, 5.2.5 and Annex C, Table C.1 + */ + void decodeC40Segment(Ref bits, std::ostringstream &result); + /** + * See ISO 16022:2006, 5.2.6 and Annex C, Table C.2 + */ + void decodeTextSegment(Ref bits, std::ostringstream &result); + /** + * See ISO 16022:2006, 5.2.7 + */ + void decodeAnsiX12Segment(Ref bits, std::ostringstream &result); + /** + * See ISO 16022:2006, 5.2.8 and Annex C Table C.3 + */ + void decodeEdifactSegment(Ref bits, std::ostringstream &result); + /** + * See ISO 16022:2006, 5.2.9 and Annex B, B.2 + */ + void decodeBase256Segment(Ref bits, std::ostringstream &result);//,std::vector 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 bytes); +}; + +} +} + +#endif // __DECODED_BIT_STREAM_PARSER_DM_H__ diff --git a/symbian/QQrDecoder/zxing/datamatrix/decoder/Decoder.cpp b/symbian/QQrDecoder/zxing/datamatrix/decoder/Decoder.cpp new file mode 100644 index 000000000..72172dc41 --- /dev/null +++ b/symbian/QQrDecoder/zxing/datamatrix/decoder/Decoder.cpp @@ -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 +#include +#include +#include +#include +#include +#include + +namespace zxing { +namespace datamatrix { + +using namespace std; + +Decoder::Decoder() : + rsDecoder_(GF256::DATA_MATRIX_FIELD) { +} + + +void Decoder::correctErrors(ArrayRef codewordBytes, int numDataCodewords) { + int numCodewords = codewordBytes->size(); + ArrayRef 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 Decoder::decode(Ref bits) { + // Construct a parser and read version, error-correction level + BitMatrixParser parser(bits); + Version *version = parser.readVersion(bits); + + // Read codewords + ArrayRef codewords(parser.readCodewords()); + // Separate into data blocks + std::vector > 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 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(dataBlocks[j]); + ArrayRef 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 text(new String(decodedBSParser.decode(resultBytes))); + + Ref result(new DecoderResult(resultBytes, text)); + return result; +} +} +} diff --git a/symbian/QQrDecoder/zxing/datamatrix/decoder/Decoder.h b/symbian/QQrDecoder/zxing/datamatrix/decoder/Decoder.h new file mode 100644 index 000000000..65fdf740c --- /dev/null +++ b/symbian/QQrDecoder/zxing/datamatrix/decoder/Decoder.h @@ -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 +#include +#include +#include +#include +#include + + +namespace zxing { +namespace datamatrix { + +class Decoder { +private: + ReedSolomonDecoder rsDecoder_; + + void correctErrors(ArrayRef bytes, int numDataCodewords); + +public: + Decoder(); + + Ref decode(Ref bits); +}; + +} +} + +#endif // __DECODER_DM_H__ diff --git a/symbian/QQrDecoder/zxing/datamatrix/detector/CornerPoint.cpp b/symbian/QQrDecoder/zxing/datamatrix/detector/CornerPoint.cpp new file mode 100644 index 000000000..8222f6b27 --- /dev/null +++ b/symbian/QQrDecoder/zxing/datamatrix/detector/CornerPoint.cpp @@ -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 + + +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 other) const { + return posX_ == other->getX() && posY_ == other->getY(); + } + + } +} diff --git a/symbian/QQrDecoder/zxing/datamatrix/detector/CornerPoint.h b/symbian/QQrDecoder/zxing/datamatrix/detector/CornerPoint.h new file mode 100644 index 000000000..a44d72b38 --- /dev/null +++ b/symbian/QQrDecoder/zxing/datamatrix/detector/CornerPoint.h @@ -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 +#include + +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 other) const; + }; + } +} + +#endif // __CORNER_FINDER_H__ diff --git a/symbian/QQrDecoder/zxing/datamatrix/detector/Detector.cpp b/symbian/QQrDecoder/zxing/datamatrix/detector/Detector.cpp new file mode 100644 index 000000000..54b1a1165 --- /dev/null +++ b/symbian/QQrDecoder/zxing/datamatrix/detector/Detector.cpp @@ -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 +#include +#include +#include +#include + +namespace zxing { +namespace datamatrix { + +using namespace std; + +ResultPointsAndTransitions::ResultPointsAndTransitions() : to_(), from_(), transitions_(0) { + Ref ref(new CornerPoint(0,0)); + from_ = ref; + to_ = ref; +} + +ResultPointsAndTransitions::ResultPointsAndTransitions(Ref from, Ref to, int transitions) : + to_(to), from_(from), transitions_(transitions) { +} + +Ref ResultPointsAndTransitions::getFrom() { + return from_; +} + +Ref ResultPointsAndTransitions::getTo() { + return to_; +} + +int ResultPointsAndTransitions::getTransitions() { + return transitions_; +} + +Detector::Detector(Ref image) : image_(image) { } + +Ref Detector::getImage() { + return image_; +} + +Ref Detector::detect() { + Ref rectangleDetector_(new MonochromeRectangleDetector(image_)); + std::vector > cornerPoints = rectangleDetector_->detect(); + Ref pointA = cornerPoints[0]; + Ref pointB = cornerPoints[1]; + Ref pointC = cornerPoints[2]; + Ref 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 > 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 lSideOne(transitions[0]); + Ref 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 maybeTopLeft; + Ref bottomLeft; + Ref 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 > 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 bottomRight(corners[0]); + bottomLeft = corners[1]; + Ref topLeft(corners[2]); + + // Which point didn't we find in relation to the "L" sides? that's the top right corner + Ref 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 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 transform = createTransform(topLeft, topR, bottomLeft, bottomRight, dimension); + Ref bits(sampleGrid(image_, dimension, transform)); + std::vector > points(4); + points[0].reset(pointA); + points[1].reset(pointB); + points[2].reset(pointC); + points[3].reset(pointD); + Ref detectorResult(new DetectorResult(bits, points, transform)); + return detectorResult; +} + +Ref Detector::transitionsBetween(Ref from, Ref 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 result(new ResultPointsAndTransitions(from, to, transitions)); + return result; + } + +Ref Detector::createTransform(Ref topLeft, Ref topRight, Ref < + ResultPoint > bottomLeft, Ref bottomRight, int dimension) { + + Ref 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 Detector::sampleGrid(Ref image, int dimension, Ref transform) { + GridSampler &sampler = GridSampler::getInstance(); + return sampler.sampleGrid(image, dimension, transform); +} + +void Detector::insertionSort(std::vector > &vector) { + int max = vector.size(); + bool swapped = true; + Ref value; + Ref 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 > &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 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 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 a, Ref b) { + return a->getTransitions() - b->getTransitions(); + } + +float Detector::crossProductZ(Ref pointA, Ref pointB, Ref pointC) { + float bX = pointB->getX(); + float bY = pointB->getY(); + return ((pointC->getX() - bX) * (pointA->getY() - bY)) - ((pointC->getY() - bY) * (pointA->getX() - bX)); + } +} +} diff --git a/symbian/QQrDecoder/zxing/datamatrix/detector/Detector.h b/symbian/QQrDecoder/zxing/datamatrix/detector/Detector.h new file mode 100644 index 000000000..96f58f502 --- /dev/null +++ b/symbian/QQrDecoder/zxing/datamatrix/detector/Detector.h @@ -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 +#include +#include +#include +#include + + +namespace zxing { +namespace datamatrix { + +class ResultPointsAndTransitions : public Counted { +private: + Ref to_; + Ref from_; + int transitions_; + +public: + ResultPointsAndTransitions(); + ResultPointsAndTransitions(Ref from, Ref to, int transitions); + Ref getFrom(); + Ref getTo(); + int getTransitions(); +}; + +class Detector : public Counted { +private: + Ref image_; + +protected: + Ref sampleGrid(Ref image, int dimension, Ref transform); + + void insertionSort(std::vector >& vector); + + Ref transitionsBetween(Ref from, Ref to); + int min(int a, int b) { return a > b ? b : a; }; + +public: + Ref getImage(); + Detector(Ref image); + + virtual Ref createTransform(Ref topLeft, Ref topRight, Ref < + ResultPoint > bottomLeft, Ref bottomRight, int dimension); + + Ref detect(); + void orderBestPatterns(std::vector > &patterns); + float distance(float x1, float x2, float y1, float y2); +private: + int compare(Ref a, Ref b); + float crossProductZ(Ref pointA, Ref pointB, Ref pointC); +}; + +} +} + +#endif // __DETECTOR_H__ diff --git a/symbian/QQrDecoder/zxing/datamatrix/detector/MonochromeRectangleDetector.cpp b/symbian/QQrDecoder/zxing/datamatrix/detector/MonochromeRectangleDetector.cpp new file mode 100644 index 000000000..d2bc01471 --- /dev/null +++ b/symbian/QQrDecoder/zxing/datamatrix/detector/MonochromeRectangleDetector.cpp @@ -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 +#include +#include + +namespace zxing { +namespace datamatrix { + +std::vector > 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 pointA(findCornerFromCenter(halfWidth, 0, left, right, + halfHeight, -deltaY, top, bottom, halfWidth >> 1)); + top = (int) pointA->getY() - 1; + Ref pointB(findCornerFromCenter(halfWidth, -deltaX, left, right, + halfHeight, 0, top, bottom, halfHeight >> 1)); + left = (int) pointB->getX() - 1; + Ref pointC(findCornerFromCenter(halfWidth, deltaX, left, right, + halfHeight, 0, top, bottom, halfHeight >> 1)); + right = (int) pointC->getX() + 1; + Ref 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 > corners(4); + + corners[0].reset(pointA); + corners[1].reset(pointB); + corners[2].reset(pointC); + corners[3].reset(pointD); + return corners; + } + +Ref MonochromeRectangleDetector::findCornerFromCenter(int centerX, int deltaX, int left, int right, + int centerY, int deltaY, int top, int bottom, int maxWhiteRun) { + Ref lastRange(NULL); + for (int y = centerY, x = centerX; + y < bottom && y >= top && x < right && x >= left; + y += deltaY, x += deltaX) { + Ref 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 result(new CornerPoint(deltaY > 0 ? lastRange->start : lastRange->end, lastY)); + return result; + } + Ref result(new CornerPoint(lastRange->start, lastY)); + return result; + } else { + Ref result(new CornerPoint(lastRange->end, lastY)); + return result; + } + } else { + int lastX = x - deltaX; + if (lastRange->start < centerY) { + if (lastRange->end > centerY) { + Ref result(new CornerPoint(lastX, deltaX < 0 ? lastRange->start : lastRange->end)); + return result; + } + Ref result(new CornerPoint(lastX, lastRange->start)); + return result; + } else { + Ref result(new CornerPoint(lastX, lastRange->end)); + return result; + } + } + } + } + lastRange = range; + } + throw ReaderException("Couldn't find corners"); + } + +Ref 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 result(NULL); + if (end > start) { + result = new TwoInts; + result->start = start; + result->end = end; + } + return result; + } +} +} diff --git a/symbian/QQrDecoder/zxing/datamatrix/detector/MonochromeRectangleDetector.h b/symbian/QQrDecoder/zxing/datamatrix/detector/MonochromeRectangleDetector.h new file mode 100644 index 000000000..45799a5be --- /dev/null +++ b/symbian/QQrDecoder/zxing/datamatrix/detector/MonochromeRectangleDetector.h @@ -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 +#include +#include +#include +#include +#include + +namespace zxing { +namespace datamatrix { + +struct TwoInts: public Counted { + int start; + int end; +}; + +class MonochromeRectangleDetector : public Counted { +private: + static const int MAX_MODULES = 32; + Ref image_; + +public: + MonochromeRectangleDetector(Ref image) : image_(image) { }; + + std::vector > detect(); + +private: + Ref findCornerFromCenter(int centerX, int deltaX, int left, int right, + int centerY, int deltaY, int top, int bottom, int maxWhiteRun); + + Ref 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__ diff --git a/symbian/QQrDecoder/zxing/oned/Code128Reader.cpp b/symbian/QQrDecoder/zxing/oned/Code128Reader.cpp index 6f638d562..36ab5dc55 100644 --- a/symbian/QQrDecoder/zxing/oned/Code128Reader.cpp +++ b/symbian/QQrDecoder/zxing/oned/Code128Reader.cpp @@ -24,6 +24,7 @@ #include #include #include +#include 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 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 diff --git a/symbian/QQrDecoder/zxing/oned/Code128Reader.h b/symbian/QQrDecoder/zxing/oned/Code128Reader.h index ad191aa0d..2b6752eec 100644 --- a/symbian/QQrDecoder/zxing/oned/Code128Reader.h +++ b/symbian/QQrDecoder/zxing/oned/Code128Reader.h @@ -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; diff --git a/symbian/QQrDecoder/zxing/oned/Code39Reader.cpp b/symbian/QQrDecoder/zxing/oned/Code39Reader.cpp index 92e63b5bd..337f23728 100644 --- a/symbian/QQrDecoder/zxing/oned/Code39Reader.cpp +++ b/symbian/QQrDecoder/zxing/oned/Code39Reader.cpp @@ -26,321 +26,333 @@ #include 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 Code39Reader::decodeRow(int rowNumber, Ref 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; iget(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 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 > resultPoints(2); + Ref resultPoint1( + new OneDResultPoint(left, (float) rowNumber)); + Ref resultPoint2( + new OneDResultPoint(right, (float) rowNumber)); + resultPoints[0] = resultPoint1; + resultPoints[1] = resultPoint2; + + ArrayRef resultBytes(1); + + delete [] start; + + Ref res(new Result( + resultString, resultBytes, resultPoints, BarcodeFormat_CODE_39)); + return res; + } + + int* Code39Reader::findAsteriskPattern(Ref 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; iget(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 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 decoded(new String(tmpDecoded)); + return decoded; + } +} // namespace oned +} // namespace zxing - - Ref Code39Reader::decodeRow(int rowNumber, Ref 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; iget(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 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 > resultPoints(2); - Ref resultPoint1(new OneDResultPoint(left, (float) rowNumber)); - Ref resultPoint2(new OneDResultPoint(right, (float) rowNumber)); - resultPoints[0] = resultPoint1; - resultPoints[1] = resultPoint2; - - ArrayRef resultBytes(1); - - delete [] start; - - Ref res(new Result(resultString, resultBytes, resultPoints, BarcodeFormat_CODE_39)); - return res; - } - - int* Code39Reader::findAsteriskPattern(Ref 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; iget(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 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 decoded(new String(tmpDecoded)); - return decoded; - } - } -} diff --git a/symbian/QQrDecoder/zxing/oned/ITFReader.cpp b/symbian/QQrDecoder/zxing/oned/ITFReader.cpp index 51a712f58..44643269a 100644 --- a/symbian/QQrDecoder/zxing/oned/ITFReader.cpp +++ b/symbian/QQrDecoder/zxing/oned/ITFReader.cpp @@ -237,7 +237,7 @@ namespace zxing { * @throws ReaderException if the quiet zone cannot be found, a ReaderException is thrown. */ void ITFReader::validateQuietZone(Ref 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 +#include #include #include @@ -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 > points(result->getResultPoints()); + if (points.size() == 2) { + Ref pointZero(new OneDResultPoint(width - points[0]->getX() - 1, points[0]->getY())); + points[0] = pointZero; + + Ref 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; diff --git a/symbian/QQrDecoder/zxing/oned/OneDReader.h b/symbian/QQrDecoder/zxing/oned/OneDReader.h index 92a7e779b..bb3b64979 100644 --- a/symbian/QQrDecoder/zxing/oned/OneDReader.h +++ b/symbian/QQrDecoder/zxing/oned/OneDReader.h @@ -38,7 +38,7 @@ namespace zxing { virtual Ref decode(Ref image); virtual Ref decodeRow(int rowNumber, Ref 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 row, int start, int counters[], int countersCount); virtual ~OneDReader(); }; diff --git a/symbian/QQrDecoder/zxing/oned/UPCEANReader.cpp b/symbian/QQrDecoder/zxing/oned/UPCEANReader.cpp index b5923bf98..e0154c533 100644 --- a/symbian/QQrDecoder/zxing/oned/UPCEANReader.cpp +++ b/symbian/QQrDecoder/zxing/oned/UPCEANReader.cpp @@ -239,7 +239,7 @@ namespace zxing { // int UPCEANReader::decodeDigit(Ref row, int counters[], int countersLen, int rowOffset, int** patterns/*[][]*/, int paterns1Len, int paterns2Len) int UPCEANReader::decodeDigit(Ref 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; diff --git a/symbian/QQrDecoder/zxing/oned/UPCEANReader.h b/symbian/QQrDecoder/zxing/oned/UPCEANReader.h index d673dc971..6ee218623 100644 --- a/symbian/QQrDecoder/zxing/oned/UPCEANReader.h +++ b/symbian/QQrDecoder/zxing/oned/UPCEANReader.h @@ -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 row); //throws ReaderException diff --git a/symbian/ZXingBarcodeReader/.cproject b/symbian/ZXingBarcodeReader/.cproject index 26abcfb0c..a64dacd29 100644 --- a/symbian/ZXingBarcodeReader/.cproject +++ b/symbian/ZXingBarcodeReader/.cproject @@ -4,8 +4,8 @@ - - + + @@ -21,18 +21,18 @@ + + - + - + - - - - + + @@ -49,18 +49,18 @@ + + - + - - - + - - + + @@ -77,18 +77,18 @@ + + - + - - - + - - + + @@ -105,19 +105,19 @@ - - - - - - - + + + + + + + - - + + @@ -134,14 +134,14 @@ + + - + - - - + diff --git a/symbian/ZXingBarcodeReader/group/ABLD.BAT b/symbian/ZXingBarcodeReader/group/ABLD.BAT index f77106118..ca1586ab6 100644 --- a/symbian/ZXingBarcodeReader/group/ABLD.BAT +++ b/symbian/ZXingBarcodeReader/group/ABLD.BAT @@ -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 diff --git a/symbian/ZXingBarcodeReader/group/ZXingBarcodeReader.mmp b/symbian/ZXingBarcodeReader/group/ZXingBarcodeReader.mmp index 4d384e049..e395db5b1 100644 --- a/symbian/ZXingBarcodeReader/group/ZXingBarcodeReader.mmp +++ b/symbian/ZXingBarcodeReader/group/ZXingBarcodeReader.mmp @@ -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 diff --git a/symbian/ZXingBarcodeReader/group/zxing/Binarizer.cpp b/symbian/ZXingBarcodeReader/group/zxing/Binarizer.cpp index 5f6e746bc..190138291 100644 --- a/symbian/ZXingBarcodeReader/group/zxing/Binarizer.cpp +++ b/symbian/ZXingBarcodeReader/group/zxing/Binarizer.cpp @@ -23,15 +23,17 @@ namespace zxing { - Binarizer::Binarizer(Ref source) : source_(source) { + Binarizer::Binarizer(Ref source) : source_(source), array_(NULL), matrix_(NULL), cached_y_(-1) { } Binarizer::~Binarizer() { } Ref Binarizer::getBlackRow(int y, Ref row){ - if (array_ == NULL) + if (array_ == NULL && cached_y_ != y) { array_ = estimateBlackRow(y, row); + cached_y_ = y; + } return array_; } diff --git a/symbian/ZXingBarcodeReader/group/zxing/Binarizer.h b/symbian/ZXingBarcodeReader/group/zxing/Binarizer.h index ea1240c0b..694018d72 100644 --- a/symbian/ZXingBarcodeReader/group/zxing/Binarizer.h +++ b/symbian/ZXingBarcodeReader/group/zxing/Binarizer.h @@ -28,24 +28,25 @@ #include namespace zxing { - - class Binarizer : public Counted { - private: - Ref source_; - Ref matrix_; - Ref array_; - - public: - Binarizer(Ref source); - virtual ~Binarizer(); - - virtual Ref estimateBlackRow(int y, Ref row)=0; - Ref getBlackRow(int y, Ref row); - - virtual Ref estimateBlackMatrix() = 0; - Ref getBlackMatrix(); - Ref getSource(); - }; - + +class Binarizer : public Counted { + private: + Ref source_; + Ref array_; + Ref matrix_; + int cached_y_; + + public: + Binarizer(Ref source); + virtual ~Binarizer(); + + virtual Ref estimateBlackRow(int y, Ref row)=0; + Ref getBlackRow(int y, Ref row); + + virtual Ref estimateBlackMatrix() = 0; + Ref getBlackMatrix(); + Ref getSource(); +}; + } #endif /* BINARIZER_H_ */ diff --git a/symbian/ZXingBarcodeReader/group/zxing/BinaryBitmap.cpp b/symbian/ZXingBarcodeReader/group/zxing/BinaryBitmap.cpp index 1e692a9f5..ff79b55d5 100644 --- a/symbian/ZXingBarcodeReader/group/zxing/BinaryBitmap.cpp +++ b/symbian/ZXingBarcodeReader/group/zxing/BinaryBitmap.cpp @@ -23,7 +23,7 @@ namespace zxing { - BinaryBitmap::BinaryBitmap(Ref binarizer) : bits_(NULL), binarizer_(binarizer) { + BinaryBitmap::BinaryBitmap(Ref binarizer) : bits_(NULL), array_bits_(NULL), binarizer_(binarizer), cached_y_(-1) { } @@ -31,8 +31,9 @@ namespace zxing { } Ref BinaryBitmap::getBlackRow(int y, Ref row) { - if (array_bits_ == NULL) { + if (array_bits_ == NULL && cached_y_ != y) { array_bits_ = binarizer_->getBlackRow(y, row); + cached_y_ = y; } return array_bits_; } diff --git a/symbian/ZXingBarcodeReader/group/zxing/BinaryBitmap.h b/symbian/ZXingBarcodeReader/group/zxing/BinaryBitmap.h index ecd9a8549..ddea910c1 100644 --- a/symbian/ZXingBarcodeReader/group/zxing/BinaryBitmap.h +++ b/symbian/ZXingBarcodeReader/group/zxing/BinaryBitmap.h @@ -33,6 +33,7 @@ namespace zxing { Ref bits_; Ref array_bits_; Ref binarizer_; + int cached_y_; public: BinaryBitmap(Ref binarizer); diff --git a/symbian/ZXingBarcodeReader/group/zxing/Exception.cpp b/symbian/ZXingBarcodeReader/group/zxing/Exception.cpp index 47143c964..d20b6e3c1 100644 --- a/symbian/ZXingBarcodeReader/group/zxing/Exception.cpp +++ b/symbian/ZXingBarcodeReader/group/zxing/Exception.cpp @@ -16,7 +16,7 @@ Exception::Exception(const char *msg) : } const char* Exception::what() const throw() { - return message; + return message.c_str(); } Exception::~Exception() throw() { diff --git a/symbian/ZXingBarcodeReader/group/zxing/Exception.h b/symbian/ZXingBarcodeReader/group/zxing/Exception.h index 7502c5cb6..ac4026e66 100644 --- a/symbian/ZXingBarcodeReader/group/zxing/Exception.h +++ b/symbian/ZXingBarcodeReader/group/zxing/Exception.h @@ -28,7 +28,7 @@ namespace zxing { class Exception : public std::exception { private: - const char * message; + std::string message; public: Exception(const char *msg); diff --git a/symbian/ZXingBarcodeReader/group/zxing/LuminanceSource.h b/symbian/ZXingBarcodeReader/group/zxing/LuminanceSource.h index e23621ef9..d39f06f38 100644 --- a/symbian/ZXingBarcodeReader/group/zxing/LuminanceSource.h +++ b/symbian/ZXingBarcodeReader/group/zxing/LuminanceSource.h @@ -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(); }; diff --git a/symbian/ZXingBarcodeReader/group/zxing/MultiFormatReader.cpp b/symbian/ZXingBarcodeReader/group/zxing/MultiFormatReader.cpp index fd3d8d2f5..bacb3cd89 100644 --- a/symbian/ZXingBarcodeReader/group/zxing/MultiFormatReader.cpp +++ b/symbian/ZXingBarcodeReader/group/zxing/MultiFormatReader.cpp @@ -19,7 +19,7 @@ * limitations under the License. */ -#include "MultiFormatReader.h" +#include #include //#include #include @@ -27,28 +27,27 @@ #include namespace zxing { - MultiFormatReader::MultiFormatReader(){ - readers = new std::vector(); - - 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 MultiFormatReader::decode(Ref 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]; + } } } diff --git a/symbian/ZXingBarcodeReader/group/zxing/MultiFormatReader.h b/symbian/ZXingBarcodeReader/group/zxing/MultiFormatReader.h index 9fca54f6c..f88ebc979 100644 --- a/symbian/ZXingBarcodeReader/group/zxing/MultiFormatReader.h +++ b/symbian/ZXingBarcodeReader/group/zxing/MultiFormatReader.h @@ -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* readers; + std::vectorreaders; public: MultiFormatReader(); Ref decode(Ref image); - + ~MultiFormatReader(); }; -} \ No newline at end of file +} diff --git a/symbian/ZXingBarcodeReader/group/zxing/Reader.h b/symbian/ZXingBarcodeReader/group/zxing/Reader.h index 3de270f95..d7844a9ae 100644 --- a/symbian/ZXingBarcodeReader/group/zxing/Reader.h +++ b/symbian/ZXingBarcodeReader/group/zxing/Reader.h @@ -21,16 +21,17 @@ * limitations under the License. */ -#include #include #include namespace zxing { -class Reader { -public: - virtual Ref decode(Ref image) = 0; - virtual ~Reader(); + class Reader : public Counted { + protected: + Reader() {} + public: + virtual Ref decode(Ref image) = 0; + virtual ~Reader(); }; } diff --git a/symbian/ZXingBarcodeReader/group/zxing/Result.cpp b/symbian/ZXingBarcodeReader/group/zxing/Result.cpp index f87ef8844..6ea658272 100644 --- a/symbian/ZXingBarcodeReader/group/zxing/Result.cpp +++ b/symbian/ZXingBarcodeReader/group/zxing/Result.cpp @@ -39,11 +39,11 @@ ArrayRef Result::getRawBytes() { return rawBytes_; } -std::vector > Result::getResultPoints() { +const std::vector >& Result::getResultPoints() const { return resultPoints_; } -BarcodeFormat Result::getBarcodeFormat() { +BarcodeFormat Result::getBarcodeFormat() const { return format_; } diff --git a/symbian/ZXingBarcodeReader/group/zxing/Result.h b/symbian/ZXingBarcodeReader/group/zxing/Result.h index 710d8d5a6..c9fcf43b5 100644 --- a/symbian/ZXingBarcodeReader/group/zxing/Result.h +++ b/symbian/ZXingBarcodeReader/group/zxing/Result.h @@ -44,8 +44,8 @@ public: ~Result(); Ref getText(); ArrayRef getRawBytes(); - std::vector > getResultPoints(); - BarcodeFormat getBarcodeFormat(); + const std::vector >& getResultPoints() const; + BarcodeFormat getBarcodeFormat() const; friend std::ostream& operator<<(std::ostream &out, Result& result); }; diff --git a/symbian/ZXingBarcodeReader/group/zxing/ResultPoint.h b/symbian/ZXingBarcodeReader/group/zxing/ResultPoint.h index 6118cc0dc..33dff7039 100644 --- a/symbian/ZXingBarcodeReader/group/zxing/ResultPoint.h +++ b/symbian/ZXingBarcodeReader/group/zxing/ResultPoint.h @@ -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; }; } diff --git a/symbian/ZXingBarcodeReader/group/zxing/common/Array.h b/symbian/ZXingBarcodeReader/group/zxing/common/Array.h index 39b178607..9b8226904 100644 --- a/symbian/ZXingBarcodeReader/group/zxing/common/Array.h +++ b/symbian/ZXingBarcodeReader/group/zxing/common/Array.h @@ -21,8 +21,7 @@ * limitations under the License. */ -#include -#include +#include #ifdef DEBUG_COUNTING #include @@ -37,17 +36,17 @@ namespace zxing { template class Array : public Counted { protected: public: - std::valarray values_; + std::vector 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 &v) : + Array(std::vector &v) : Counted(), values_(v) { } Array(Array &other) : @@ -68,7 +67,7 @@ public: #endif return *this; } - Array& operator=(const std::valarray &array) { + Array& operator=(const std::vector &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 values() const { + std::vector values() const { return values_; } - std::valarray& values() { + std::vector& values() { return values_; } }; diff --git a/symbian/ZXingBarcodeReader/group/zxing/common/BitArray.cpp b/symbian/ZXingBarcodeReader/group/zxing/common/BitArray.cpp index 26e686930..6ba7fd22f 100644 --- a/symbian/ZXingBarcodeReader/group/zxing/common/BitArray.cpp +++ b/symbian/ZXingBarcodeReader/group/zxing/common/BitArray.cpp @@ -20,6 +20,7 @@ #include #include +#include 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& BitArray::getBitArray() { +vector& BitArray::getBitArray() { return bits_; } void BitArray::reverse() { - unsigned int allBits = numeric_limits::max(); - size_t max = bits_.size(); - for (size_t i = 0; i < max; i++) { - bits_[i] = bits_[i] ^ allBits; + std::vector 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; } } diff --git a/symbian/ZXingBarcodeReader/group/zxing/common/BitArray.h b/symbian/ZXingBarcodeReader/group/zxing/common/BitArray.h index 1e8828e96..d3b6f661f 100644 --- a/symbian/ZXingBarcodeReader/group/zxing/common/BitArray.h +++ b/symbian/ZXingBarcodeReader/group/zxing/common/BitArray.h @@ -23,8 +23,7 @@ #include #include -#include -#include +#include #include namespace zxing { @@ -32,7 +31,7 @@ namespace zxing { class BitArray : public Counted { private: size_t size_; - std::valarray bits_; + std::vector 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& getBitArray(); + std::vector& getBitArray(); void reverse(); }; diff --git a/symbian/ZXingBarcodeReader/group/zxing/common/BitMatrix.cpp b/symbian/ZXingBarcodeReader/group/zxing/common/BitMatrix.cpp index 9256c4097..8c137f2a7 100644 --- a/symbian/ZXingBarcodeReader/group/zxing/common/BitMatrix.cpp +++ b/symbian/ZXingBarcodeReader/group/zxing/common/BitMatrix.cpp @@ -24,7 +24,6 @@ #include #include #include -#include namespace zxing { using namespace std; @@ -40,7 +39,7 @@ unsigned int logDigits(unsigned digits) { } -const unsigned int bitsPerWord = std::numeric_limits::digits; +const unsigned int bitsPerWord = numeric_limits::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 " : " "); diff --git a/symbian/ZXingBarcodeReader/group/zxing/common/BitMatrix.h b/symbian/ZXingBarcodeReader/group/zxing/common/BitMatrix.h index e8f8f847e..91d785e97 100644 --- a/symbian/ZXingBarcodeReader/group/zxing/common/BitMatrix.h +++ b/symbian/ZXingBarcodeReader/group/zxing/common/BitMatrix.h @@ -22,7 +22,6 @@ */ #include -#include #include 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&); }; } diff --git a/symbian/ZXingBarcodeReader/group/zxing/common/Counted.h b/symbian/ZXingBarcodeReader/group/zxing/common/Counted.h index dd0f84552..4f2b369c5 100644 --- a/symbian/ZXingBarcodeReader/group/zxing/common/Counted.h +++ b/symbian/ZXingBarcodeReader/group/zxing/common/Counted.h @@ -172,10 +172,10 @@ public: T& operator*() { return *object_; } - T* operator->() { + T* operator->() const { return object_; } - operator T*() { + operator T*() const { return object_; } diff --git a/symbian/ZXingBarcodeReader/group/zxing/common/EdgeDetector.cpp b/symbian/ZXingBarcodeReader/group/zxing/common/EdgeDetector.cpp index 3f0b403cc..70ac8c5de 100644 --- a/symbian/ZXingBarcodeReader/group/zxing/common/EdgeDetector.cpp +++ b/symbian/ZXingBarcodeReader/group/zxing/common/EdgeDetector.cpp @@ -20,6 +20,7 @@ #include #include +#include using namespace std; diff --git a/symbian/ZXingBarcodeReader/group/zxing/common/GlobalHistogramBinarizer.cpp b/symbian/ZXingBarcodeReader/group/zxing/common/GlobalHistogramBinarizer.cpp index 8767dbd34..8b99611eb 100644 --- a/symbian/ZXingBarcodeReader/group/zxing/common/GlobalHistogramBinarizer.cpp +++ b/symbian/ZXingBarcodeReader/group/zxing/common/GlobalHistogramBinarizer.cpp @@ -24,154 +24,160 @@ #include 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 source) : - Binarizer(source) { - - } - - GlobalHistogramBinarizer::~GlobalHistogramBinarizer() { - } - - - Ref GlobalHistogramBinarizer::estimateBlackRow(int y, Ref row){ - valarray 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 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 GlobalHistogramBinarizer::estimateBlackMatrix() { - // Faster than working with the reference - LuminanceSource& source = *getSource(); - int width = source.getWidth(); - int height = source.getHeight(); - valarray 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 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 &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 source) : + Binarizer(source) { + } + +GlobalHistogramBinarizer::~GlobalHistogramBinarizer() { +} + + +Ref GlobalHistogramBinarizer::estimateBlackRow(int y, + Ref row){ + vector histogram(LUMINANCE_BUCKETS, 0); + LuminanceSource& source = *getSource(); + int width = source.getWidth(); + if (row == NULL || static_cast(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 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 GlobalHistogramBinarizer::estimateBlackMatrix() { + // Faster than working with the reference + LuminanceSource& source = *getSource(); + int width = source.getWidth(); + int height = source.getHeight(); + vector 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 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 &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 + diff --git a/symbian/ZXingBarcodeReader/group/zxing/common/GlobalHistogramBinarizer.h b/symbian/ZXingBarcodeReader/group/zxing/common/GlobalHistogramBinarizer.h index 6735c5b9f..42956e944 100644 --- a/symbian/ZXingBarcodeReader/group/zxing/common/GlobalHistogramBinarizer.h +++ b/symbian/ZXingBarcodeReader/group/zxing/common/GlobalHistogramBinarizer.h @@ -22,7 +22,7 @@ #ifndef GLOBALHISTOGRAMBINARIZER_H_ #define GLOBALHISTOGRAMBINARIZER_H_ -#include +#include #include #include #include @@ -36,7 +36,7 @@ namespace zxing { virtual Ref estimateBlackRow(int y, Ref row); virtual Ref estimateBlackMatrix(); - static int estimate(std::valarray &histogram); + static int estimate(std::vector &histogram); }; } diff --git a/symbian/ZXingBarcodeReader/group/zxing/common/GridSampler.cpp b/symbian/ZXingBarcodeReader/group/zxing/common/GridSampler.cpp index 06bb602c1..03a240ebb 100644 --- a/symbian/ZXingBarcodeReader/group/zxing/common/GridSampler.cpp +++ b/symbian/ZXingBarcodeReader/group/zxing/common/GridSampler.cpp @@ -34,7 +34,7 @@ GridSampler::GridSampler() { Ref GridSampler::sampleGrid(Ref image, int dimension, Ref transform) { Ref bits(new BitMatrix(dimension)); - valarray points((const float)0.0f, dimension << 1); + vector 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 GridSampler::sampleGrid(Ref image, int dimension, floa } -void GridSampler::checkAndNudgePoints(Ref image, valarray &points) { +void GridSampler::checkAndNudgePoints(Ref image, vector &points) { int width = image->getWidth(); int height = image->getHeight(); diff --git a/symbian/ZXingBarcodeReader/group/zxing/common/GridSampler.h b/symbian/ZXingBarcodeReader/group/zxing/common/GridSampler.h index 3dd577dcb..a7ad8b991 100644 --- a/symbian/ZXingBarcodeReader/group/zxing/common/GridSampler.h +++ b/symbian/ZXingBarcodeReader/group/zxing/common/GridSampler.h @@ -36,7 +36,7 @@ public: Ref sampleGrid(Ref 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 image, std::valarray &points); + static void checkAndNudgePoints(Ref image, std::vector &points); static GridSampler &getInstance(); }; } diff --git a/symbian/ZXingBarcodeReader/group/zxing/common/PerspectiveTransform.cpp b/symbian/ZXingBarcodeReader/group/zxing/common/PerspectiveTransform.cpp index 44d9ddcb0..5b4ae2e8b 100644 --- a/symbian/ZXingBarcodeReader/group/zxing/common/PerspectiveTransform.cpp +++ b/symbian/ZXingBarcodeReader/group/zxing/common/PerspectiveTransform.cpp @@ -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::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::times(Ref return result; } -void PerspectiveTransform::transformPoints(valarray &points) { +void PerspectiveTransform::transformPoints(vector &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 &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"; diff --git a/symbian/ZXingBarcodeReader/group/zxing/common/PerspectiveTransform.h b/symbian/ZXingBarcodeReader/group/zxing/common/PerspectiveTransform.h index 581f92880..b32263270 100644 --- a/symbian/ZXingBarcodeReader/group/zxing/common/PerspectiveTransform.h +++ b/symbian/ZXingBarcodeReader/group/zxing/common/PerspectiveTransform.h @@ -22,7 +22,7 @@ */ #include -#include +#include namespace zxing { class PerspectiveTransform : public Counted { @@ -41,9 +41,9 @@ public: float x3, float y3); Ref buildAdjoint(); Ref times(Ref other); - void transformPoints(std::valarray &points); + void transformPoints(std::vector &points); - friend std::ostream& operator<<(std::ostream& out, PerspectiveTransform &pt); + friend std::ostream& operator<<(std::ostream& out, const PerspectiveTransform &pt); }; } diff --git a/symbian/ZXingBarcodeReader/group/zxing/common/Point.h b/symbian/ZXingBarcodeReader/group/zxing/common/Point.h index a391042fe..ea2705221 100644 --- a/symbian/ZXingBarcodeReader/group/zxing/common/Point.h +++ b/symbian/ZXingBarcodeReader/group/zxing/common/Point.h @@ -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_ diff --git a/symbian/ZXingBarcodeReader/group/zxing/common/Str.cpp b/symbian/ZXingBarcodeReader/group/zxing/common/Str.cpp index e2122dc3a..6259f9477 100644 --- a/symbian/ZXingBarcodeReader/group/zxing/common/Str.cpp +++ b/symbian/ZXingBarcodeReader/group/zxing/common/Str.cpp @@ -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_; } diff --git a/symbian/ZXingBarcodeReader/group/zxing/common/Str.h b/symbian/ZXingBarcodeReader/group/zxing/common/Str.h index 255a05531..09ff2bb0a 100644 --- a/symbian/ZXingBarcodeReader/group/zxing/common/Str.h +++ b/symbian/ZXingBarcodeReader/group/zxing/common/Str.h @@ -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); }; diff --git a/symbian/ZXingBarcodeReader/group/zxing/common/reedsolomon/GF256.cpp b/symbian/ZXingBarcodeReader/group/zxing/common/reedsolomon/GF256.cpp index 8add88934..51b621e8e 100644 --- a/symbian/ZXingBarcodeReader/group/zxing/common/reedsolomon/GF256.cpp +++ b/symbian/ZXingBarcodeReader/group/zxing/common/reedsolomon/GF256.cpp @@ -18,7 +18,6 @@ * limitations under the License. */ -#include #include #include #include @@ -42,7 +41,7 @@ static inline Ref 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 diff --git a/symbian/ZXingBarcodeReader/group/zxing/common/reedsolomon/GF256.h b/symbian/ZXingBarcodeReader/group/zxing/common/reedsolomon/GF256.h index 0930f63bf..070a0fdcf 100644 --- a/symbian/ZXingBarcodeReader/group/zxing/common/reedsolomon/GF256.h +++ b/symbian/ZXingBarcodeReader/group/zxing/common/reedsolomon/GF256.h @@ -22,7 +22,7 @@ */ #include -#include +#include #include namespace zxing { @@ -42,8 +42,8 @@ class GF256 { * @author christian.brunschen@gmail.com (Christian Brunschen) */ private: - std::valarray exp_; - std::valarray log_; + std::vector exp_; + std::vector log_; Ref zero_; Ref one_; diff --git a/symbian/ZXingBarcodeReader/group/zxing/datamatrix/DataMatrixReader.cpp b/symbian/ZXingBarcodeReader/group/zxing/datamatrix/DataMatrixReader.cpp new file mode 100644 index 000000000..8b00161ef --- /dev/null +++ b/symbian/ZXingBarcodeReader/group/zxing/datamatrix/DataMatrixReader.cpp @@ -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 +#include +#include + +namespace zxing { +namespace datamatrix { + +using namespace std; + +DataMatrixReader::DataMatrixReader() : + decoder_() { +} + +Ref DataMatrixReader::decode(Ref 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(detector.detect()); +#ifdef DEBUG + cout << "(2) detected, have detectorResult " << detectorResult.object_ << "\n" << flush; +#endif + + std::vector > 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(decoder_.decode(detectorResult->getBits())); +#ifdef DEBUG + cout << "(4) decoded, have decoderResult " << decoderResult.object_ << "\n" << flush; +#endif + + Ref 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() { +} + +} +} diff --git a/symbian/ZXingBarcodeReader/group/zxing/datamatrix/DataMatrixReader.h b/symbian/ZXingBarcodeReader/group/zxing/datamatrix/DataMatrixReader.h new file mode 100644 index 000000000..4d621c8d9 --- /dev/null +++ b/symbian/ZXingBarcodeReader/group/zxing/datamatrix/DataMatrixReader.h @@ -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 +#include + +namespace zxing { +namespace datamatrix { + +class DataMatrixReader : public Reader { +private: + Decoder decoder_; + +public: + DataMatrixReader(); + virtual Ref decode(Ref image); + virtual ~DataMatrixReader(); + +}; + +} +} + +#endif // __DATA_MATRIX_READER_H__ diff --git a/symbian/ZXingBarcodeReader/group/zxing/datamatrix/Version.cpp b/symbian/ZXingBarcodeReader/group/zxing/datamatrix/Version.cpp new file mode 100644 index 000000000..e48d88ef9 --- /dev/null +++ b/symbian/ZXingBarcodeReader/group/zxing/datamatrix/Version.cpp @@ -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 +#include +#include + +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& ECBlocks::getECBlocks() { + return ecBlocks_; +} + +ECBlocks::~ECBlocks() { + for (size_t i = 0; i < ecBlocks_.size(); i++) { + delete ecBlocks_[i]; + } +} + +vector > 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 &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::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(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(new Version(1, 10, 10, 8, 8, + new ECBlocks(5, new ECB(1, 3))))); + VERSIONS.push_back(Ref(new Version(2, 12, 12, 10, 10, + new ECBlocks(7, new ECB(1, 5))))); + VERSIONS.push_back(Ref(new Version(3, 14, 14, 12, 12, + new ECBlocks(10, new ECB(1, 8))))); + VERSIONS.push_back(Ref(new Version(4, 16, 16, 14, 14, + new ECBlocks(12, new ECB(1, 12))))); + VERSIONS.push_back(Ref(new Version(5, 18, 18, 16, 16, + new ECBlocks(14, new ECB(1, 18))))); + VERSIONS.push_back(Ref(new Version(6, 20, 20, 18, 18, + new ECBlocks(18, new ECB(1, 22))))); + VERSIONS.push_back(Ref(new Version(7, 22, 22, 20, 20, + new ECBlocks(20, new ECB(1, 30))))); + VERSIONS.push_back(Ref(new Version(8, 24, 24, 22, 22, + new ECBlocks(24, new ECB(1, 36))))); + VERSIONS.push_back(Ref(new Version(9, 26, 26, 24, 24, + new ECBlocks(28, new ECB(1, 44))))); + VERSIONS.push_back(Ref(new Version(10, 32, 32, 14, 14, + new ECBlocks(36, new ECB(1, 62))))); + VERSIONS.push_back(Ref(new Version(11, 36, 36, 16, 16, + new ECBlocks(42, new ECB(1, 86))))); + VERSIONS.push_back(Ref(new Version(12, 40, 40, 18, 18, + new ECBlocks(48, new ECB(1, 114))))); + VERSIONS.push_back(Ref(new Version(13, 44, 44, 20, 20, + new ECBlocks(56, new ECB(1, 144))))); + VERSIONS.push_back(Ref(new Version(14, 48, 48, 22, 22, + new ECBlocks(68, new ECB(1, 174))))); + VERSIONS.push_back(Ref(new Version(15, 52, 52, 24, 24, + new ECBlocks(42, new ECB(2, 102))))); + VERSIONS.push_back(Ref(new Version(16, 64, 64, 14, 14, + new ECBlocks(56, new ECB(2, 140))))); + VERSIONS.push_back(Ref(new Version(17, 72, 72, 16, 16, + new ECBlocks(36, new ECB(4, 92))))); + VERSIONS.push_back(Ref(new Version(18, 80, 80, 18, 18, + new ECBlocks(48, new ECB(4, 114))))); + VERSIONS.push_back(Ref(new Version(19, 88, 88, 20, 20, + new ECBlocks(56, new ECB(4, 144))))); + VERSIONS.push_back(Ref(new Version(20, 96, 96, 22, 22, + new ECBlocks(68, new ECB(4, 174))))); + VERSIONS.push_back(Ref(new Version(21, 104, 104, 24, 24, + new ECBlocks(56, new ECB(6, 136))))); + VERSIONS.push_back(Ref(new Version(22, 120, 120, 18, 18, + new ECBlocks(68, new ECB(6, 175))))); + VERSIONS.push_back(Ref(new Version(23, 132, 132, 20, 20, + new ECBlocks(62, new ECB(8, 163))))); + VERSIONS.push_back(Ref(new Version(24, 144, 144, 22, 22, + new ECBlocks(62, new ECB(8, 156), new ECB(2, 155))))); + VERSIONS.push_back(Ref(new Version(25, 8, 18, 6, 16, + new ECBlocks(7, new ECB(1, 5))))); + VERSIONS.push_back(Ref(new Version(26, 8, 32, 6, 14, + new ECBlocks(11, new ECB(1, 10))))); + VERSIONS.push_back(Ref(new Version(27, 12, 26, 10, 24, + new ECBlocks(14, new ECB(1, 16))))); + VERSIONS.push_back(Ref(new Version(28, 12, 36, 10, 16, + new ECBlocks(18, new ECB(1, 22))))); + VERSIONS.push_back(Ref(new Version(29, 16, 36, 10, 16, + new ECBlocks(24, new ECB(1, 32))))); + VERSIONS.push_back(Ref(new Version(30, 16, 48, 14, 22, + new ECBlocks(28, new ECB(1, 49))))); + return VERSIONS.size(); +} +} +} diff --git a/symbian/ZXingBarcodeReader/group/zxing/datamatrix/Version.h b/symbian/ZXingBarcodeReader/group/zxing/datamatrix/Version.h new file mode 100644 index 000000000..d8523fe23 --- /dev/null +++ b/symbian/ZXingBarcodeReader/group/zxing/datamatrix/Version.h @@ -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 +#include +#include +#include + +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 ecBlocks_; +public: + ECBlocks(int ecCodewords, ECB *ecBlocks); + ECBlocks(int ecCodewords, ECB *ecBlocks1, ECB *ecBlocks2); + int getECCodewords(); + std::vector& 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 > VERSIONS; + + ~Version(); + int getVersionNumber(); + int getSymbolSizeRows(); + int getSymbolSizeColumns(); + int getDataRegionSizeRows(); + int getDataRegionSizeColumns(); + int getTotalCodewords(); + ECBlocks* getECBlocks(); + static int buildVersions(); + Ref getVersionForDimensions(int numRows, int numColumns); + +private: + Version(const Version&); + Version & operator=(const Version&); +}; +} +} + +#endif // __VERSION_H__ diff --git a/symbian/ZXingBarcodeReader/group/zxing/datamatrix/decoder/BitMatrixParser.cpp b/symbian/ZXingBarcodeReader/group/zxing/datamatrix/decoder/BitMatrixParser.cpp new file mode 100644 index 000000000..eb5c06f48 --- /dev/null +++ b/symbian/ZXingBarcodeReader/group/zxing/datamatrix/decoder/BitMatrixParser.cpp @@ -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 +#include + +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_(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 BitMatrixParser::readVersion(Ref 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 = parsedVersion_->getVersionForDimensions(numRows, numColumns); + if (version != 0) { + return version; + } + throw ReaderException("Couldn't decode version"); +} + +ArrayRef BitMatrixParser::readCodewords() { + ArrayRef 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 BitMatrixParser::extractDataRegion(Ref 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 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; +} + +} +} diff --git a/symbian/ZXingBarcodeReader/group/zxing/datamatrix/decoder/BitMatrixParser.h b/symbian/ZXingBarcodeReader/group/zxing/datamatrix/decoder/BitMatrixParser.h new file mode 100644 index 000000000..30123d59c --- /dev/null +++ b/symbian/ZXingBarcodeReader/group/zxing/datamatrix/decoder/BitMatrixParser.h @@ -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 +#include +#include +#include +#include + +namespace zxing { +namespace datamatrix { + +class BitMatrixParser : public Counted { +private: + Ref bitMatrix_; + Ref parsedVersion_; + Ref readBitMatrix_; + + int copyBit(size_t x, size_t y, int versionBits); + +public: + BitMatrixParser(Ref bitMatrix); + Ref readVersion(Ref bitMatrix); + ArrayRef 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 extractDataRegion(Ref bitMatrix); +}; + +} +} + +#endif // __BIT_MATRIX_PARSER_DM_H__ diff --git a/symbian/ZXingBarcodeReader/group/zxing/datamatrix/decoder/DataBlock.cpp b/symbian/ZXingBarcodeReader/group/zxing/datamatrix/decoder/DataBlock.cpp new file mode 100644 index 000000000..c87d5f309 --- /dev/null +++ b/symbian/ZXingBarcodeReader/group/zxing/datamatrix/decoder/DataBlock.cpp @@ -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 +#include + +namespace zxing { +namespace datamatrix { + +using namespace std; + +DataBlock::DataBlock(int numDataCodewords, ArrayRef codewords) : + numDataCodewords_(numDataCodewords), codewords_(codewords) { +} + +int DataBlock::getNumDataCodewords() { + return numDataCodewords_; +} + +ArrayRef DataBlock::getCodewords() { + return codewords_; +} + +std::vector > DataBlock::getDataBlocks(ArrayRef 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 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 > 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 buffer(numBlockCodewords); + Ref 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; +} + +} +} diff --git a/symbian/ZXingBarcodeReader/group/zxing/datamatrix/decoder/DataBlock.h b/symbian/ZXingBarcodeReader/group/zxing/datamatrix/decoder/DataBlock.h new file mode 100644 index 000000000..7fc72f655 --- /dev/null +++ b/symbian/ZXingBarcodeReader/group/zxing/datamatrix/decoder/DataBlock.h @@ -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 +#include +#include +#include + +namespace zxing { +namespace datamatrix { + +class DataBlock : public Counted { +private: + int numDataCodewords_; + ArrayRef codewords_; + + DataBlock(int numDataCodewords, ArrayRef codewords); + +public: + static std::vector > getDataBlocks(ArrayRef rawCodewords, Version *version); + + int getNumDataCodewords(); + ArrayRef getCodewords(); +}; + +} +} + +#endif // __DATA_BLOCK_DM_H__ diff --git a/symbian/ZXingBarcodeReader/group/zxing/datamatrix/decoder/DecodedBitStreamParser.cpp b/symbian/ZXingBarcodeReader/group/zxing/datamatrix/decoder/DecodedBitStreamParser.cpp new file mode 100644 index 000000000..9aa2f684c --- /dev/null +++ b/symbian/ZXingBarcodeReader/group/zxing/datamatrix/decoder/DecodedBitStreamParser.cpp @@ -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 +#include +#include + +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 bytes) { + Ref 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 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 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 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 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 + 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 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 bits, ostringstream & result){//, vector 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; +} +} +} + diff --git a/symbian/ZXingBarcodeReader/group/zxing/datamatrix/decoder/DecodedBitStreamParser.h b/symbian/ZXingBarcodeReader/group/zxing/datamatrix/decoder/DecodedBitStreamParser.h new file mode 100644 index 000000000..6a0b26030 --- /dev/null +++ b/symbian/ZXingBarcodeReader/group/zxing/datamatrix/decoder/DecodedBitStreamParser.h @@ -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 +#include +#include +#include +#include + + +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 bits, std::ostringstream &result, std::ostringstream &resultTrailer); + /** + * See ISO 16022:2006, 5.2.5 and Annex C, Table C.1 + */ + void decodeC40Segment(Ref bits, std::ostringstream &result); + /** + * See ISO 16022:2006, 5.2.6 and Annex C, Table C.2 + */ + void decodeTextSegment(Ref bits, std::ostringstream &result); + /** + * See ISO 16022:2006, 5.2.7 + */ + void decodeAnsiX12Segment(Ref bits, std::ostringstream &result); + /** + * See ISO 16022:2006, 5.2.8 and Annex C Table C.3 + */ + void decodeEdifactSegment(Ref bits, std::ostringstream &result); + /** + * See ISO 16022:2006, 5.2.9 and Annex B, B.2 + */ + void decodeBase256Segment(Ref bits, std::ostringstream &result);//,std::vector 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 bytes); +}; + +} +} + +#endif // __DECODED_BIT_STREAM_PARSER_DM_H__ diff --git a/symbian/ZXingBarcodeReader/group/zxing/datamatrix/decoder/Decoder.cpp b/symbian/ZXingBarcodeReader/group/zxing/datamatrix/decoder/Decoder.cpp new file mode 100644 index 000000000..72172dc41 --- /dev/null +++ b/symbian/ZXingBarcodeReader/group/zxing/datamatrix/decoder/Decoder.cpp @@ -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 +#include +#include +#include +#include +#include +#include + +namespace zxing { +namespace datamatrix { + +using namespace std; + +Decoder::Decoder() : + rsDecoder_(GF256::DATA_MATRIX_FIELD) { +} + + +void Decoder::correctErrors(ArrayRef codewordBytes, int numDataCodewords) { + int numCodewords = codewordBytes->size(); + ArrayRef 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 Decoder::decode(Ref bits) { + // Construct a parser and read version, error-correction level + BitMatrixParser parser(bits); + Version *version = parser.readVersion(bits); + + // Read codewords + ArrayRef codewords(parser.readCodewords()); + // Separate into data blocks + std::vector > 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 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(dataBlocks[j]); + ArrayRef 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 text(new String(decodedBSParser.decode(resultBytes))); + + Ref result(new DecoderResult(resultBytes, text)); + return result; +} +} +} diff --git a/symbian/ZXingBarcodeReader/group/zxing/datamatrix/decoder/Decoder.h b/symbian/ZXingBarcodeReader/group/zxing/datamatrix/decoder/Decoder.h new file mode 100644 index 000000000..65fdf740c --- /dev/null +++ b/symbian/ZXingBarcodeReader/group/zxing/datamatrix/decoder/Decoder.h @@ -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 +#include +#include +#include +#include +#include + + +namespace zxing { +namespace datamatrix { + +class Decoder { +private: + ReedSolomonDecoder rsDecoder_; + + void correctErrors(ArrayRef bytes, int numDataCodewords); + +public: + Decoder(); + + Ref decode(Ref bits); +}; + +} +} + +#endif // __DECODER_DM_H__ diff --git a/symbian/ZXingBarcodeReader/group/zxing/datamatrix/detector/CornerPoint.cpp b/symbian/ZXingBarcodeReader/group/zxing/datamatrix/detector/CornerPoint.cpp new file mode 100644 index 000000000..8222f6b27 --- /dev/null +++ b/symbian/ZXingBarcodeReader/group/zxing/datamatrix/detector/CornerPoint.cpp @@ -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 + + +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 other) const { + return posX_ == other->getX() && posY_ == other->getY(); + } + + } +} diff --git a/symbian/ZXingBarcodeReader/group/zxing/datamatrix/detector/CornerPoint.h b/symbian/ZXingBarcodeReader/group/zxing/datamatrix/detector/CornerPoint.h new file mode 100644 index 000000000..a44d72b38 --- /dev/null +++ b/symbian/ZXingBarcodeReader/group/zxing/datamatrix/detector/CornerPoint.h @@ -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 +#include + +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 other) const; + }; + } +} + +#endif // __CORNER_FINDER_H__ diff --git a/symbian/ZXingBarcodeReader/group/zxing/datamatrix/detector/Detector.cpp b/symbian/ZXingBarcodeReader/group/zxing/datamatrix/detector/Detector.cpp new file mode 100644 index 000000000..54b1a1165 --- /dev/null +++ b/symbian/ZXingBarcodeReader/group/zxing/datamatrix/detector/Detector.cpp @@ -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 +#include +#include +#include +#include + +namespace zxing { +namespace datamatrix { + +using namespace std; + +ResultPointsAndTransitions::ResultPointsAndTransitions() : to_(), from_(), transitions_(0) { + Ref ref(new CornerPoint(0,0)); + from_ = ref; + to_ = ref; +} + +ResultPointsAndTransitions::ResultPointsAndTransitions(Ref from, Ref to, int transitions) : + to_(to), from_(from), transitions_(transitions) { +} + +Ref ResultPointsAndTransitions::getFrom() { + return from_; +} + +Ref ResultPointsAndTransitions::getTo() { + return to_; +} + +int ResultPointsAndTransitions::getTransitions() { + return transitions_; +} + +Detector::Detector(Ref image) : image_(image) { } + +Ref Detector::getImage() { + return image_; +} + +Ref Detector::detect() { + Ref rectangleDetector_(new MonochromeRectangleDetector(image_)); + std::vector > cornerPoints = rectangleDetector_->detect(); + Ref pointA = cornerPoints[0]; + Ref pointB = cornerPoints[1]; + Ref pointC = cornerPoints[2]; + Ref 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 > 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 lSideOne(transitions[0]); + Ref 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 maybeTopLeft; + Ref bottomLeft; + Ref 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 > 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 bottomRight(corners[0]); + bottomLeft = corners[1]; + Ref topLeft(corners[2]); + + // Which point didn't we find in relation to the "L" sides? that's the top right corner + Ref 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 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 transform = createTransform(topLeft, topR, bottomLeft, bottomRight, dimension); + Ref bits(sampleGrid(image_, dimension, transform)); + std::vector > points(4); + points[0].reset(pointA); + points[1].reset(pointB); + points[2].reset(pointC); + points[3].reset(pointD); + Ref detectorResult(new DetectorResult(bits, points, transform)); + return detectorResult; +} + +Ref Detector::transitionsBetween(Ref from, Ref 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 result(new ResultPointsAndTransitions(from, to, transitions)); + return result; + } + +Ref Detector::createTransform(Ref topLeft, Ref topRight, Ref < + ResultPoint > bottomLeft, Ref bottomRight, int dimension) { + + Ref 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 Detector::sampleGrid(Ref image, int dimension, Ref transform) { + GridSampler &sampler = GridSampler::getInstance(); + return sampler.sampleGrid(image, dimension, transform); +} + +void Detector::insertionSort(std::vector > &vector) { + int max = vector.size(); + bool swapped = true; + Ref value; + Ref 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 > &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 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 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 a, Ref b) { + return a->getTransitions() - b->getTransitions(); + } + +float Detector::crossProductZ(Ref pointA, Ref pointB, Ref pointC) { + float bX = pointB->getX(); + float bY = pointB->getY(); + return ((pointC->getX() - bX) * (pointA->getY() - bY)) - ((pointC->getY() - bY) * (pointA->getX() - bX)); + } +} +} diff --git a/symbian/ZXingBarcodeReader/group/zxing/datamatrix/detector/Detector.h b/symbian/ZXingBarcodeReader/group/zxing/datamatrix/detector/Detector.h new file mode 100644 index 000000000..96f58f502 --- /dev/null +++ b/symbian/ZXingBarcodeReader/group/zxing/datamatrix/detector/Detector.h @@ -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 +#include +#include +#include +#include + + +namespace zxing { +namespace datamatrix { + +class ResultPointsAndTransitions : public Counted { +private: + Ref to_; + Ref from_; + int transitions_; + +public: + ResultPointsAndTransitions(); + ResultPointsAndTransitions(Ref from, Ref to, int transitions); + Ref getFrom(); + Ref getTo(); + int getTransitions(); +}; + +class Detector : public Counted { +private: + Ref image_; + +protected: + Ref sampleGrid(Ref image, int dimension, Ref transform); + + void insertionSort(std::vector >& vector); + + Ref transitionsBetween(Ref from, Ref to); + int min(int a, int b) { return a > b ? b : a; }; + +public: + Ref getImage(); + Detector(Ref image); + + virtual Ref createTransform(Ref topLeft, Ref topRight, Ref < + ResultPoint > bottomLeft, Ref bottomRight, int dimension); + + Ref detect(); + void orderBestPatterns(std::vector > &patterns); + float distance(float x1, float x2, float y1, float y2); +private: + int compare(Ref a, Ref b); + float crossProductZ(Ref pointA, Ref pointB, Ref pointC); +}; + +} +} + +#endif // __DETECTOR_H__ diff --git a/symbian/ZXingBarcodeReader/group/zxing/datamatrix/detector/MonochromeRectangleDetector.cpp b/symbian/ZXingBarcodeReader/group/zxing/datamatrix/detector/MonochromeRectangleDetector.cpp new file mode 100644 index 000000000..d2bc01471 --- /dev/null +++ b/symbian/ZXingBarcodeReader/group/zxing/datamatrix/detector/MonochromeRectangleDetector.cpp @@ -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 +#include +#include + +namespace zxing { +namespace datamatrix { + +std::vector > 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 pointA(findCornerFromCenter(halfWidth, 0, left, right, + halfHeight, -deltaY, top, bottom, halfWidth >> 1)); + top = (int) pointA->getY() - 1; + Ref pointB(findCornerFromCenter(halfWidth, -deltaX, left, right, + halfHeight, 0, top, bottom, halfHeight >> 1)); + left = (int) pointB->getX() - 1; + Ref pointC(findCornerFromCenter(halfWidth, deltaX, left, right, + halfHeight, 0, top, bottom, halfHeight >> 1)); + right = (int) pointC->getX() + 1; + Ref 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 > corners(4); + + corners[0].reset(pointA); + corners[1].reset(pointB); + corners[2].reset(pointC); + corners[3].reset(pointD); + return corners; + } + +Ref MonochromeRectangleDetector::findCornerFromCenter(int centerX, int deltaX, int left, int right, + int centerY, int deltaY, int top, int bottom, int maxWhiteRun) { + Ref lastRange(NULL); + for (int y = centerY, x = centerX; + y < bottom && y >= top && x < right && x >= left; + y += deltaY, x += deltaX) { + Ref 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 result(new CornerPoint(deltaY > 0 ? lastRange->start : lastRange->end, lastY)); + return result; + } + Ref result(new CornerPoint(lastRange->start, lastY)); + return result; + } else { + Ref result(new CornerPoint(lastRange->end, lastY)); + return result; + } + } else { + int lastX = x - deltaX; + if (lastRange->start < centerY) { + if (lastRange->end > centerY) { + Ref result(new CornerPoint(lastX, deltaX < 0 ? lastRange->start : lastRange->end)); + return result; + } + Ref result(new CornerPoint(lastX, lastRange->start)); + return result; + } else { + Ref result(new CornerPoint(lastX, lastRange->end)); + return result; + } + } + } + } + lastRange = range; + } + throw ReaderException("Couldn't find corners"); + } + +Ref 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 result(NULL); + if (end > start) { + result = new TwoInts; + result->start = start; + result->end = end; + } + return result; + } +} +} diff --git a/symbian/ZXingBarcodeReader/group/zxing/datamatrix/detector/MonochromeRectangleDetector.h b/symbian/ZXingBarcodeReader/group/zxing/datamatrix/detector/MonochromeRectangleDetector.h new file mode 100644 index 000000000..45799a5be --- /dev/null +++ b/symbian/ZXingBarcodeReader/group/zxing/datamatrix/detector/MonochromeRectangleDetector.h @@ -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 +#include +#include +#include +#include +#include + +namespace zxing { +namespace datamatrix { + +struct TwoInts: public Counted { + int start; + int end; +}; + +class MonochromeRectangleDetector : public Counted { +private: + static const int MAX_MODULES = 32; + Ref image_; + +public: + MonochromeRectangleDetector(Ref image) : image_(image) { }; + + std::vector > detect(); + +private: + Ref findCornerFromCenter(int centerX, int deltaX, int left, int right, + int centerY, int deltaY, int top, int bottom, int maxWhiteRun); + + Ref 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__ diff --git a/symbian/ZXingBarcodeReader/group/zxing/oned/Code128Reader.cpp b/symbian/ZXingBarcodeReader/group/zxing/oned/Code128Reader.cpp index 943a57481..36ab5dc55 100644 --- a/symbian/ZXingBarcodeReader/group/zxing/oned/Code128Reader.cpp +++ b/symbian/ZXingBarcodeReader/group/zxing/oned/Code128Reader.cpp @@ -24,13 +24,14 @@ #include #include #include +#include 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 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(""); } diff --git a/symbian/ZXingBarcodeReader/group/zxing/oned/Code128Reader.h b/symbian/ZXingBarcodeReader/group/zxing/oned/Code128Reader.h index ad191aa0d..2b6752eec 100644 --- a/symbian/ZXingBarcodeReader/group/zxing/oned/Code128Reader.h +++ b/symbian/ZXingBarcodeReader/group/zxing/oned/Code128Reader.h @@ -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; diff --git a/symbian/ZXingBarcodeReader/group/zxing/oned/Code39Reader.cpp b/symbian/ZXingBarcodeReader/group/zxing/oned/Code39Reader.cpp index cb03dd9ac..337f23728 100644 --- a/symbian/ZXingBarcodeReader/group/zxing/oned/Code39Reader.cpp +++ b/symbian/ZXingBarcodeReader/group/zxing/oned/Code39Reader.cpp @@ -26,315 +26,333 @@ #include 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 Code39Reader::decodeRow(int rowNumber, Ref 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; iget(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 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 > resultPoints(2); - Ref resultPoint1(new OneDResultPoint(left, (float) rowNumber)); - Ref resultPoint2(new OneDResultPoint(right, (float) rowNumber)); - resultPoints[0] = resultPoint1; - resultPoints[1] = resultPoint2; - - ArrayRef resultBytes(1); - - delete [] start; - - Ref res(new Result(resultString, resultBytes, resultPoints, BarcodeFormat_CODE_39)); - return res; - } - - int* Code39Reader::findAsteriskPattern(Ref 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; iget(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 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 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 Code39Reader::decodeRow(int rowNumber, Ref 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; iget(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 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 > resultPoints(2); + Ref resultPoint1( + new OneDResultPoint(left, (float) rowNumber)); + Ref resultPoint2( + new OneDResultPoint(right, (float) rowNumber)); + resultPoints[0] = resultPoint1; + resultPoints[1] = resultPoint2; + + ArrayRef resultBytes(1); + + delete [] start; + + Ref res(new Result( + resultString, resultBytes, resultPoints, BarcodeFormat_CODE_39)); + return res; + } + + int* Code39Reader::findAsteriskPattern(Ref 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; iget(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 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 decoded(new String(tmpDecoded)); + return decoded; + } +} // namespace oned +} // namespace zxing + diff --git a/symbian/ZXingBarcodeReader/group/zxing/oned/Code39Reader.h b/symbian/ZXingBarcodeReader/group/zxing/oned/Code39Reader.h index 1846761a6..cc7148c77 100644 --- a/symbian/ZXingBarcodeReader/group/zxing/oned/Code39Reader.h +++ b/symbian/ZXingBarcodeReader/group/zxing/oned/Code39Reader.h @@ -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 decodeRow(int rowNumber, Ref row); - - ~Code39Reader(); - }; + }; } } diff --git a/symbian/ZXingBarcodeReader/group/zxing/oned/EAN13Reader.cpp b/symbian/ZXingBarcodeReader/group/zxing/oned/EAN13Reader.cpp index 0e3de9731..dab360b84 100644 --- a/symbian/ZXingBarcodeReader/group/zxing/oned/EAN13Reader.cpp +++ b/symbian/ZXingBarcodeReader/group/zxing/oned/EAN13Reader.cpp @@ -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 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; - } } } diff --git a/symbian/ZXingBarcodeReader/group/zxing/oned/EAN13Reader.h b/symbian/ZXingBarcodeReader/group/zxing/oned/EAN13Reader.h index 8ef6fe38b..540d32695 100644 --- a/symbian/ZXingBarcodeReader/group/zxing/oned/EAN13Reader.h +++ b/symbian/ZXingBarcodeReader/group/zxing/oned/EAN13Reader.h @@ -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 row, int startRange[], int startRangeLen, std::string& resultString); //throws ReaderException BarcodeFormat getBarcodeFormat(); - ~EAN13Reader(); }; } -} \ No newline at end of file +} diff --git a/symbian/ZXingBarcodeReader/group/zxing/oned/EAN8Reader.cpp b/symbian/ZXingBarcodeReader/group/zxing/oned/EAN8Reader.cpp index 52d09fe99..e3c0e2a7e 100644 --- a/symbian/ZXingBarcodeReader/group/zxing/oned/EAN8Reader.cpp +++ b/symbian/ZXingBarcodeReader/group/zxing/oned/EAN8Reader.cpp @@ -24,21 +24,11 @@ namespace zxing { namespace oned { - EAN8Reader::EAN8Reader(){ - decodeMiddleCounters = new int[4]; - for (int i=0; i<4; i++) { - decodeMiddleCounters[i] = 0; - } - } + EAN8Reader::EAN8Reader(){ } int EAN8Reader::decodeMiddle(Ref 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(); int rowOffset = startRange[1]; @@ -68,8 +58,5 @@ namespace zxing { BarcodeFormat EAN8Reader::getBarcodeFormat(){ return BarcodeFormat_EAN_8; } - EAN8Reader::~EAN8Reader(){ - delete [] decodeMiddleCounters; - } } -} \ No newline at end of file +} diff --git a/symbian/ZXingBarcodeReader/group/zxing/oned/EAN8Reader.h b/symbian/ZXingBarcodeReader/group/zxing/oned/EAN8Reader.h index 3e4f3d67e..481944c4f 100644 --- a/symbian/ZXingBarcodeReader/group/zxing/oned/EAN8Reader.h +++ b/symbian/ZXingBarcodeReader/group/zxing/oned/EAN8Reader.h @@ -25,16 +25,12 @@ namespace zxing { namespace oned { class EAN8Reader : public UPCEANReader { - private: - int* decodeMiddleCounters; - public: EAN8Reader(); int decodeMiddle(Ref row, int startRange[], int startRangeLen, std::string& resultString); //throws ReaderException BarcodeFormat getBarcodeFormat(); - ~EAN8Reader(); }; } -} \ No newline at end of file +} diff --git a/symbian/ZXingBarcodeReader/group/zxing/oned/ITFReader.cpp b/symbian/ZXingBarcodeReader/group/zxing/oned/ITFReader.cpp index e38ab2160..44643269a 100644 --- a/symbian/ZXingBarcodeReader/group/zxing/oned/ITFReader.cpp +++ b/symbian/ZXingBarcodeReader/group/zxing/oned/ITFReader.cpp @@ -62,18 +62,29 @@ namespace zxing { }; - ITFReader::ITFReader(){ - narrowLineWidth = -1; + ITFReader::ITFReader() : narrowLineWidth(-1) { } Ref ITFReader::decodeRow(int rowNumber, Ref row){ // Find out where the Middle section (payload) starts & ends int* startRange = decodeStart(row); - int* endRange = decodeEnd(row); + int* endRange; + try { + endRange = decodeEnd(row); + } catch (Exception e) { + delete [] startRange; + throw e; + } std::string tmpResult; + try { decodeMiddle(row, startRange[1], endRange[0], tmpResult); + } catch (zxing::ReaderException re) { + delete [] startRange; + delete [] endRange; + throw re; + } // To avoid false positives with 2D barcodes (and other patterns), make // an assumption that the decoded string must be 6, 10 or 14 digits. @@ -83,7 +94,9 @@ namespace zxing { lengthOK = true; } if (!lengthOK) { - throw ReaderException("not enought characters count"); + delete [] startRange; + delete [] endRange; + throw ReaderException("not enough characters count"); } Ref resultString(new String(tmpResult)); @@ -116,13 +129,13 @@ namespace zxing { // Therefore, need to scan 10 lines and then // split these into two arrays int counterDigitPairLen = 10; - int* counterDigitPair = new int[counterDigitPairLen]; + int counterDigitPair[counterDigitPairLen]; for (int i=0; i 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--) { @@ -278,7 +288,7 @@ namespace zxing { // TODO: This is very similar to implementation in UPCEANReader. Consider if they can be // merged to a single method. int patternLength = patternLen; - int* counters = new int[patternLength]; + int counters[patternLength]; for (int i=0; i(); - readers->push_back(new MultiFormatUPCEANReader()); - readers->push_back(new Code39Reader()); - readers->push_back(new Code128Reader()); - readers->push_back(new ITFReader()); + MultiFormatOneDReader::MultiFormatOneDReader() : readers() { + readers.push_back(Ref(new MultiFormatUPCEANReader())); + readers.push_back(Ref(new Code39Reader())); + readers.push_back(Ref(new Code128Reader())); + readers.push_back(Ref(new ITFReader())); } Ref MultiFormatOneDReader::decodeRow(int rowNumber, Ref row){ - int size = readers->size(); + int size = readers.size(); for (int i = 0; i < size; i++) { - OneDReader* reader = (*readers)[i]; + OneDReader* reader = readers[i]; try { return reader->decodeRow(rowNumber, row); } catch (ReaderException re) { @@ -48,8 +47,5 @@ namespace zxing { } throw ReaderException("No code detected"); } - MultiFormatOneDReader::~MultiFormatOneDReader(){ - delete readers; - } } -} \ No newline at end of file +} diff --git a/symbian/ZXingBarcodeReader/group/zxing/oned/MultiFormatOneDReader.h b/symbian/ZXingBarcodeReader/group/zxing/oned/MultiFormatOneDReader.h index 9fcc6fbb2..0e5ab530d 100644 --- a/symbian/ZXingBarcodeReader/group/zxing/oned/MultiFormatOneDReader.h +++ b/symbian/ZXingBarcodeReader/group/zxing/oned/MultiFormatOneDReader.h @@ -27,13 +27,11 @@ namespace zxing { class MultiFormatOneDReader : public OneDReader { private: - std::vector* readers; + std::vector > readers; public: MultiFormatOneDReader(); - Ref decodeRow(int rowNumber, Ref row); - - ~MultiFormatOneDReader(); + Ref decodeRow(int rowNumber, Ref row); }; } -} \ No newline at end of file +} diff --git a/symbian/ZXingBarcodeReader/group/zxing/oned/MultiFormatUPCEANReader.cpp b/symbian/ZXingBarcodeReader/group/zxing/oned/MultiFormatUPCEANReader.cpp index 61011f0ff..24aa5e6f4 100644 --- a/symbian/ZXingBarcodeReader/group/zxing/oned/MultiFormatUPCEANReader.cpp +++ b/symbian/ZXingBarcodeReader/group/zxing/oned/MultiFormatUPCEANReader.cpp @@ -30,19 +30,18 @@ namespace zxing { namespace oned { - MultiFormatUPCEANReader::MultiFormatUPCEANReader(){ - readers = new std::vector(); - readers->push_back(new EAN13Reader()); + MultiFormatUPCEANReader::MultiFormatUPCEANReader() : readers() { + readers.push_back(Ref(new EAN13Reader())); // UPC-A is covered by EAN-13 - readers->push_back(new EAN8Reader()); - readers->push_back(new UPCEReader()); + readers.push_back(Ref(new EAN8Reader())); + readers.push_back(Ref(new UPCEReader())); } Ref MultiFormatUPCEANReader::decodeRow(int rowNumber, Ref row){ // Compute this location once and reuse it on multiple implementations - int size = readers->size(); + int size = readers.size(); for (int i = 0; i < size; i++) { - OneDReader* reader = (*readers)[i]; + Ref reader = readers[i]; Ref result; try { result = reader->decodeRow(rowNumber, row);//decodeRow(rowNumber, row, startGuardPattern); @@ -60,7 +59,7 @@ namespace zxing { // UPC-A. So we special case it here, and convert an EAN-13 result to a UPC-A // result if appropriate. if (result->getBarcodeFormat() == BarcodeFormat_EAN_13) { - std::string& text = (result->getText())->getText(); + const std::string& text = (result->getText())->getText(); if (text[0] == '0') { Ref resultString(new String(text.substr(1))); Ref res(new Result(resultString, result->getRawBytes(), result->getResultPoints(), BarcodeFormat_UPC_A)); @@ -71,9 +70,5 @@ namespace zxing { } throw ReaderException("No EAN code detected"); } - - MultiFormatUPCEANReader::~MultiFormatUPCEANReader(){ - delete readers; - } } -} \ No newline at end of file +} diff --git a/symbian/ZXingBarcodeReader/group/zxing/oned/MultiFormatUPCEANReader.h b/symbian/ZXingBarcodeReader/group/zxing/oned/MultiFormatUPCEANReader.h index 706f9c431..2c5b196bf 100644 --- a/symbian/ZXingBarcodeReader/group/zxing/oned/MultiFormatUPCEANReader.h +++ b/symbian/ZXingBarcodeReader/group/zxing/oned/MultiFormatUPCEANReader.h @@ -29,13 +29,11 @@ namespace zxing { class MultiFormatUPCEANReader : public OneDReader { private: - std::vector* readers; + std::vector > readers; public: MultiFormatUPCEANReader(); Ref decodeRow(int rowNumber, Ref row); - - ~MultiFormatUPCEANReader(); - }; + }; } -} \ No newline at end of file +} diff --git a/symbian/ZXingBarcodeReader/group/zxing/oned/OneDReader.cpp b/symbian/ZXingBarcodeReader/group/zxing/oned/OneDReader.cpp index 21526f57f..d3e491691 100644 --- a/symbian/ZXingBarcodeReader/group/zxing/oned/OneDReader.cpp +++ b/symbian/ZXingBarcodeReader/group/zxing/oned/OneDReader.cpp @@ -20,6 +20,7 @@ #include "OneDReader.h" #include +#include #include #include @@ -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 > points(result->getResultPoints()); + if (points.size() == 2) { + Ref pointZero(new OneDResultPoint(width - points[0]->getX() - 1, points[0]->getY())); + points[0] = pointZero; + + Ref 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; @@ -191,4 +202,4 @@ namespace zxing { OneDReader::~OneDReader() { } } -} \ No newline at end of file +} diff --git a/symbian/ZXingBarcodeReader/group/zxing/oned/OneDReader.h b/symbian/ZXingBarcodeReader/group/zxing/oned/OneDReader.h index a029f9cb1..bb3b64979 100644 --- a/symbian/ZXingBarcodeReader/group/zxing/oned/OneDReader.h +++ b/symbian/ZXingBarcodeReader/group/zxing/oned/OneDReader.h @@ -38,9 +38,9 @@ namespace zxing { virtual Ref decode(Ref image); virtual Ref decodeRow(int rowNumber, Ref 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 row, int start, int counters[], int countersCount); virtual ~OneDReader(); }; } -} \ No newline at end of file +} diff --git a/symbian/ZXingBarcodeReader/group/zxing/oned/OneDResultPoint.cpp b/symbian/ZXingBarcodeReader/group/zxing/oned/OneDResultPoint.cpp index 272319dbf..0ac8dc3ca 100644 --- a/symbian/ZXingBarcodeReader/group/zxing/oned/OneDResultPoint.cpp +++ b/symbian/ZXingBarcodeReader/group/zxing/oned/OneDResultPoint.cpp @@ -23,17 +23,15 @@ namespace zxing { namespace oned { - using namespace std; - OneDResultPoint::OneDResultPoint(float posX, float posY) : posX_(posX), posY_(posY){ } - float OneDResultPoint::getX() { + float OneDResultPoint::getX() const { return posX_; } - float OneDResultPoint::getY() { + float OneDResultPoint::getY() const { return posY_; } } -} \ No newline at end of file +} diff --git a/symbian/ZXingBarcodeReader/group/zxing/oned/OneDResultPoint.h b/symbian/ZXingBarcodeReader/group/zxing/oned/OneDResultPoint.h index 1b07b772c..18f1614b9 100644 --- a/symbian/ZXingBarcodeReader/group/zxing/oned/OneDResultPoint.h +++ b/symbian/ZXingBarcodeReader/group/zxing/oned/OneDResultPoint.h @@ -30,8 +30,8 @@ namespace zxing { public: OneDResultPoint(float posX, float posY); - float getX(); - float getY(); + float getX() const; + float getY() const; }; } } diff --git a/symbian/ZXingBarcodeReader/group/zxing/oned/UPCAReader.cpp b/symbian/ZXingBarcodeReader/group/zxing/oned/UPCAReader.cpp index e46c2b76f..cb2fcb5e3 100644 --- a/symbian/ZXingBarcodeReader/group/zxing/oned/UPCAReader.cpp +++ b/symbian/ZXingBarcodeReader/group/zxing/oned/UPCAReader.cpp @@ -19,31 +19,29 @@ */ #include "UPCAReader.h" -#include #include namespace zxing { namespace oned { - UPCAReader::UPCAReader(){ - ean13Reader = new EAN13Reader(); + UPCAReader::UPCAReader() : ean13Reader() { } Ref UPCAReader::decodeRow(int rowNumber, Ref row){ - return maybeReturnResult(ean13Reader->decodeRow(rowNumber, row)); + return maybeReturnResult(ean13Reader.decodeRow(rowNumber, row)); } Ref UPCAReader::decodeRow(int rowNumber, Ref row, int startGuardRange[]){ - return maybeReturnResult(ean13Reader->decodeRow(rowNumber, row, startGuardRange)); + return maybeReturnResult(ean13Reader.decodeRow(rowNumber, row, startGuardRange)); } Ref UPCAReader::decode(Ref image){ - return maybeReturnResult(ean13Reader->decode(image)); + return maybeReturnResult(ean13Reader.decode(image)); } int UPCAReader::decodeMiddle(Ref row, int startRange[], int startRangeLen, std::string& resultString){ - return ean13Reader->decodeMiddle(row, startRange, startRangeLen, resultString); + return ean13Reader.decodeMiddle(row, startRange, startRangeLen, resultString); } Ref UPCAReader::maybeReturnResult(Ref result){ - std::string& text = (result->getText())->getText(); + const std::string& text = (result->getText())->getText(); if (text[0] == '0') { Ref resultString(new String(text.substr(1))); Ref res(new Result(resultString, result->getRawBytes(), result->getResultPoints(), BarcodeFormat_UPC_A)); @@ -57,8 +55,5 @@ namespace zxing { BarcodeFormat UPCAReader::getBarcodeFormat(){ return BarcodeFormat_UPC_A; } - UPCAReader::~UPCAReader(){ - delete ean13Reader; - } } -} \ No newline at end of file +} diff --git a/symbian/ZXingBarcodeReader/group/zxing/oned/UPCAReader.h b/symbian/ZXingBarcodeReader/group/zxing/oned/UPCAReader.h index 217184b84..85422072c 100644 --- a/symbian/ZXingBarcodeReader/group/zxing/oned/UPCAReader.h +++ b/symbian/ZXingBarcodeReader/group/zxing/oned/UPCAReader.h @@ -18,15 +18,14 @@ * limitations under the License. */ -#include -#include +#include namespace zxing { namespace oned { class UPCAReader : public UPCEANReader { private: - UPCEANReader* ean13Reader; + EAN13Reader ean13Reader; static Ref maybeReturnResult(Ref result); //throws ReaderException public: @@ -39,7 +38,6 @@ namespace zxing { Ref decode(Ref image); BarcodeFormat getBarcodeFormat(); - ~UPCAReader(); }; } -} \ No newline at end of file +} diff --git a/symbian/ZXingBarcodeReader/group/zxing/oned/UPCEANReader.cpp b/symbian/ZXingBarcodeReader/group/zxing/oned/UPCEANReader.cpp index 5345cad9b..e0154c533 100644 --- a/symbian/ZXingBarcodeReader/group/zxing/oned/UPCEANReader.cpp +++ b/symbian/ZXingBarcodeReader/group/zxing/oned/UPCEANReader.cpp @@ -100,7 +100,16 @@ namespace zxing { std::string tmpResultString; std::string& tmpResultStringRef = tmpResultString; - int endStart = decodeMiddle(row, startGuardRange, 2 /*reference findGuardPattern*/ , tmpResultStringRef); + int endStart; + try { + endStart = decodeMiddle(row, startGuardRange, 2 /*reference findGuardPattern*/ , tmpResultStringRef); + } catch (ReaderException re) { + if (startGuardRange!=NULL) { + delete [] startGuardRange; + startGuardRange = NULL; + } + throw re; + } int* endRange = decodeEnd(row, endStart); @@ -114,6 +123,14 @@ namespace zxing { // } if (!checkChecksum(tmpResultString)) { + if (startGuardRange!=NULL) { + delete [] startGuardRange; + startGuardRange = NULL; + } + if (endRange!=NULL) { + delete [] endRange; + endRange = NULL; + } throw ReaderException("Checksum fail."); } @@ -159,6 +176,9 @@ namespace zxing { if (quietStart >= 0) { foundStart = row->isRange(quietStart, start, false); } + if (!foundStart) { + delete [] startRange; + } } return startRange; } @@ -217,13 +237,13 @@ namespace zxing { } // int UPCEANReader::decodeDigit(Ref row, int counters[], int countersLen, int rowOffset, int** patterns/*[][]*/, int paterns1Len, int paterns2Len) - int UPCEANReader::decodeDigit(Ref row, int counters[], int countersLen, int rowOffset, UPC_EAN_PATTERNS paternType){ + int UPCEANReader::decodeDigit(Ref 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; - switch (paternType) { + switch (patternType) { case UPC_EAN_PATTERNS_L_PATTERNS: max = L_PATTERNS_LEN; for (int i = 0; i < max; i++) { @@ -232,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; @@ -247,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; diff --git a/symbian/ZXingBarcodeReader/group/zxing/oned/UPCEANReader.h b/symbian/ZXingBarcodeReader/group/zxing/oned/UPCEANReader.h index 8f825c26c..6ee218623 100644 --- a/symbian/ZXingBarcodeReader/group/zxing/oned/UPCEANReader.h +++ b/symbian/ZXingBarcodeReader/group/zxing/oned/UPCEANReader.h @@ -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 row); //throws ReaderException @@ -54,7 +54,7 @@ namespace zxing { Ref decodeRow(int rowNumber, Ref row); Ref decodeRow(int rowNumber, Ref row, int startGuardRange[]); - static int decodeDigit(Ref row, int counters[], int countersLen, int rowOffset, UPC_EAN_PATTERNS paternType); //throws ReaderException + static int decodeDigit(Ref row, int counters[], int countersLen, int rowOffset, UPC_EAN_PATTERNS patternType); //throws ReaderException bool checkChecksum(std::string s); //throws ReaderException @@ -62,4 +62,5 @@ namespace zxing { virtual ~UPCEANReader(); }; } -} \ No newline at end of file +} + diff --git a/symbian/ZXingBarcodeReader/group/zxing/oned/UPCEReader.cpp b/symbian/ZXingBarcodeReader/group/zxing/oned/UPCEReader.cpp index 3738d4c6b..1bba2f73f 100644 --- a/symbian/ZXingBarcodeReader/group/zxing/oned/UPCEReader.cpp +++ b/symbian/ZXingBarcodeReader/group/zxing/oned/UPCEReader.cpp @@ -40,21 +40,11 @@ namespace zxing { {0x07, 0x0B, 0x0D, 0x0E, 0x13, 0x19, 0x1C, 0x15, 0x16, 0x1A} }; - UPCEReader::UPCEReader(){ - decodeMiddleCounters = new int[4]; - for (int i=0; i<4; i++) { - decodeMiddleCounters[i] = 0; - } - } + UPCEReader::UPCEReader(){} int UPCEReader::decodeMiddle(Ref 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(); int rowOffset = startRange[1]; @@ -143,8 +133,5 @@ namespace zxing { BarcodeFormat UPCEReader::getBarcodeFormat(){ return BarcodeFormat_UPC_E; } - UPCEReader::~UPCEReader(){ - delete [] decodeMiddleCounters; - } } } diff --git a/symbian/ZXingBarcodeReader/group/zxing/oned/UPCEReader.h b/symbian/ZXingBarcodeReader/group/zxing/oned/UPCEReader.h index a26e2ec62..5de2ef57b 100644 --- a/symbian/ZXingBarcodeReader/group/zxing/oned/UPCEReader.h +++ b/symbian/ZXingBarcodeReader/group/zxing/oned/UPCEReader.h @@ -26,7 +26,6 @@ namespace zxing { class UPCEReader : public UPCEANReader { private: - int* decodeMiddleCounters; static void determineFirstDigit(std::string& resultString, int lgPatternFound); //throws ReaderException static void determineNumSysAndCheckDigit(std::string& resultString, int lgPatternFound); //throws ReaderException protected: @@ -39,7 +38,6 @@ namespace zxing { static std::string& convertUPCEtoUPCA(std::string upce); BarcodeFormat getBarcodeFormat(); - ~UPCEReader(); }; } -} \ No newline at end of file +} diff --git a/symbian/ZXingBarcodeReader/group/zxing/qrcode/ErrorCorrectionLevel.cpp b/symbian/ZXingBarcodeReader/group/zxing/qrcode/ErrorCorrectionLevel.cpp index 9c610b526..e8faf9091 100644 --- a/symbian/ZXingBarcodeReader/group/zxing/qrcode/ErrorCorrectionLevel.cpp +++ b/symbian/ZXingBarcodeReader/group/zxing/qrcode/ErrorCorrectionLevel.cpp @@ -23,8 +23,8 @@ namespace zxing { namespace qrcode { -ErrorCorrectionLevel::ErrorCorrectionLevel(int ordinal) : - ordinal_(ordinal) { +ErrorCorrectionLevel::ErrorCorrectionLevel(int inOrdinal) : + ordinal_(inOrdinal) { } int ErrorCorrectionLevel::ordinal() { diff --git a/symbian/ZXingBarcodeReader/group/zxing/qrcode/ErrorCorrectionLevel.h b/symbian/ZXingBarcodeReader/group/zxing/qrcode/ErrorCorrectionLevel.h index 426d204cf..9d6a6c524 100644 --- a/symbian/ZXingBarcodeReader/group/zxing/qrcode/ErrorCorrectionLevel.h +++ b/symbian/ZXingBarcodeReader/group/zxing/qrcode/ErrorCorrectionLevel.h @@ -29,7 +29,7 @@ namespace qrcode { class ErrorCorrectionLevel { private: int ordinal_; - ErrorCorrectionLevel(int ordinal); + ErrorCorrectionLevel(int inOrdinal); static ErrorCorrectionLevel *FOR_BITS[]; static int N_LEVELS; public: diff --git a/symbian/ZXingBarcodeReader/group/zxing/qrcode/Version.cpp b/symbian/ZXingBarcodeReader/group/zxing/qrcode/Version.cpp index 5e63c8271..62c2acfe7 100644 --- a/symbian/ZXingBarcodeReader/group/zxing/qrcode/Version.cpp +++ b/symbian/ZXingBarcodeReader/group/zxing/qrcode/Version.cpp @@ -20,9 +20,9 @@ #include #include -#include #include #include +#include namespace zxing { namespace qrcode { @@ -41,13 +41,11 @@ int ECB::getDataCodewords() { } ECBlocks::ECBlocks(int ecCodewords, ECB *ecBlocks) : - ecCodewords_(ecCodewords) { - ecBlocks_.push_back(ecBlocks); + ecCodewords_(ecCodewords), ecBlocks_(1, ecBlocks) { } ECBlocks::ECBlocks(int ecCodewords, ECB *ecBlocks1, ECB *ecBlocks2) : - ecCodewords_(ecCodewords) { - ecBlocks_.push_back(ecBlocks1); + ecCodewords_(ecCodewords), ecBlocks_(1, ecBlocks1) { ecBlocks_.push_back(ecBlocks2); } @@ -78,7 +76,7 @@ int Version::getVersionNumber() { return versionNumber_; } -valarray &Version::getAlignmentPatternCenters() { +vector &Version::getAlignmentPatternCenters() { return alignmentPatternCenters_; } @@ -102,16 +100,16 @@ Version *Version::getProvisionalVersionForDimension(int dimension) { } Version *Version::getVersionForNumber(int versionNumber) { - if (versionNumber < 1 || versionNumber > 40) { + if (versionNumber < 1 || versionNumber > N_VERSIONS) { throw ReaderException("versionNumber must be between 1 and 40"); } return VERSIONS[versionNumber - 1]; } -Version::Version(int versionNumber, valarray *alignmentPatternCenters, ECBlocks *ecBlocks1, ECBlocks *ecBlocks2, +Version::Version(int versionNumber, vector *alignmentPatternCenters, ECBlocks *ecBlocks1, ECBlocks *ecBlocks2, ECBlocks *ecBlocks3, ECBlocks *ecBlocks4) : - versionNumber_(versionNumber), alignmentPatternCenters_(*alignmentPatternCenters), ecBlocks_(4) { + versionNumber_(versionNumber), alignmentPatternCenters_(*alignmentPatternCenters), ecBlocks_(4), totalCodewords_(0) { ecBlocks_[0] = ecBlocks1; ecBlocks_[1] = ecBlocks2; ecBlocks_[2] = ecBlocks3; @@ -207,10 +205,10 @@ Ref Version::buildFunctionPattern() { return functionPattern; } -static valarray *intArray(size_t n...) { +static vector *intArray(size_t n...) { va_list ap; va_start(ap, n); - valarray *result = new valarray(n); + vector *result = new vector(n); for (size_t i = 0; i < n; i++) { (*result)[i] = va_arg(ap, int); } diff --git a/symbian/ZXingBarcodeReader/group/zxing/qrcode/Version.h b/symbian/ZXingBarcodeReader/group/zxing/qrcode/Version.h index 181bd98fe..a89518da3 100644 --- a/symbian/ZXingBarcodeReader/group/zxing/qrcode/Version.h +++ b/symbian/ZXingBarcodeReader/group/zxing/qrcode/Version.h @@ -27,7 +27,6 @@ #include #include #include -#include namespace zxing { namespace qrcode { @@ -58,10 +57,10 @@ class Version : public Counted { private: int versionNumber_; - std::valarray &alignmentPatternCenters_; + std::vector &alignmentPatternCenters_; std::vector ecBlocks_; int totalCodewords_; - Version(int versionNumber, std::valarray *alignmentPatternCenters, ECBlocks *ecBlocks1, ECBlocks *ecBlocks2, + Version(int versionNumber, std::vector *alignmentPatternCenters, ECBlocks *ecBlocks1, ECBlocks *ecBlocks2, ECBlocks *ecBlocks3, ECBlocks *ecBlocks4); public: @@ -71,7 +70,7 @@ public: ~Version(); int getVersionNumber(); - std::valarray &getAlignmentPatternCenters(); + std::vector &getAlignmentPatternCenters(); int getTotalCodewords(); int getDimensionForVersion(); ECBlocks &getECBlocksForLevel(ErrorCorrectionLevel &ecLevel); diff --git a/symbian/ZXingBarcodeReader/group/zxing/qrcode/decoder/BitMatrixParser.cpp b/symbian/ZXingBarcodeReader/group/zxing/qrcode/decoder/BitMatrixParser.cpp index e4ef5e2d8..04cd06bc5 100644 --- a/symbian/ZXingBarcodeReader/group/zxing/qrcode/decoder/BitMatrixParser.cpp +++ b/symbian/ZXingBarcodeReader/group/zxing/qrcode/decoder/BitMatrixParser.cpp @@ -158,8 +158,8 @@ ArrayRef BitMatrixParser::readCodewords() { x--; } // Read alternatingly from bottom to top then top to bottom - for (int count = 0; count < dimension; count++) { - int y = readingUp ? dimension - 1 - count : count; + for (int counter = 0; counter < dimension; counter++) { + int y = readingUp ? dimension - 1 - counter : counter; for (int col = 0; col < 2; col++) { // Ignore bits covered by the function pattern if (!functionPattern->get(x - col, y)) { diff --git a/symbian/ZXingBarcodeReader/group/zxing/qrcode/decoder/BitMatrixParser.h b/symbian/ZXingBarcodeReader/group/zxing/qrcode/decoder/BitMatrixParser.h index 824556b93..093949211 100644 --- a/symbian/ZXingBarcodeReader/group/zxing/qrcode/decoder/BitMatrixParser.h +++ b/symbian/ZXingBarcodeReader/group/zxing/qrcode/decoder/BitMatrixParser.h @@ -44,6 +44,11 @@ public: Ref readFormatInformation(); Version *readVersion(); ArrayRef readCodewords(); + +private: + BitMatrixParser(const BitMatrixParser&); + BitMatrixParser& operator =(const BitMatrixParser&); + }; } diff --git a/symbian/ZXingBarcodeReader/group/zxing/qrcode/decoder/DataBlock.h b/symbian/ZXingBarcodeReader/group/zxing/qrcode/decoder/DataBlock.h index df536f4d6..fed669c11 100644 --- a/symbian/ZXingBarcodeReader/group/zxing/qrcode/decoder/DataBlock.h +++ b/symbian/ZXingBarcodeReader/group/zxing/qrcode/decoder/DataBlock.h @@ -21,7 +21,6 @@ * limitations under the License. */ -#include #include #include #include diff --git a/symbian/ZXingBarcodeReader/group/zxing/qrcode/decoder/DecodedBitStreamParser.cpp b/symbian/ZXingBarcodeReader/group/zxing/qrcode/decoder/DecodedBitStreamParser.cpp index ab32b2e8c..20232fef4 100644 --- a/symbian/ZXingBarcodeReader/group/zxing/qrcode/decoder/DecodedBitStreamParser.cpp +++ b/symbian/ZXingBarcodeReader/group/zxing/qrcode/decoder/DecodedBitStreamParser.cpp @@ -20,7 +20,9 @@ #include #include +#ifndef NO_ICONV #include +#endif // Required for compatibility. TODO: test on Symbian #ifdef ZXING_ICONV_CONST @@ -50,7 +52,8 @@ const char *DecodedBitStreamParser::UTF8 = "UTF-8"; const char *DecodedBitStreamParser::SHIFT_JIS = "SHIFT_JIS"; const char *DecodedBitStreamParser::EUC_JP = "EUC-JP"; -void DecodedBitStreamParser::append(ostream &ost, const unsigned char *bufIn, size_t nIn, const char *src) { +void DecodedBitStreamParser::append(std::string &result, const unsigned char *bufIn, size_t nIn, const char *src) { +#ifndef NO_ICONV if (nIn == 0) { return; } @@ -76,12 +79,14 @@ void DecodedBitStreamParser::append(ostream &ost, const unsigned char *bufIn, si int nResult = maxOut - nTo; bufOut[nResult] = '\0'; - - ost << bufOut; + result.append((const char *)bufOut); delete[] bufOut; + #else + result.append((const char *)bufIn, nIn); + #endif } -void DecodedBitStreamParser::decodeKanjiSegment(Ref bits, ostringstream &result, int count) { +void DecodedBitStreamParser::decodeKanjiSegment(Ref bits, std::string &result, int count) { // Each character will require 2 bytes. Read the characters as 2-byte pairs // and decode as Shift_JIS afterwards size_t nBytes = 2 * count; @@ -109,7 +114,7 @@ void DecodedBitStreamParser::decodeKanjiSegment(Ref bits, ostringstre delete[] buffer; } -void DecodedBitStreamParser::decodeByteSegment(Ref bits, ostringstream &result, int count) { +void DecodedBitStreamParser::decodeByteSegment(Ref bits, std::string &result, int count) { int nBytes = count; unsigned char* readBytes = new unsigned char[nBytes]; if (count << 3 > bits->available()) { @@ -131,7 +136,7 @@ void DecodedBitStreamParser::decodeByteSegment(Ref bits, ostringstrea delete[] readBytes; } -void DecodedBitStreamParser::decodeNumericSegment(Ref bits, ostringstream &result, int count) { +void DecodedBitStreamParser::decodeNumericSegment(Ref bits, std::string &result, int count) { int nBytes = count; unsigned char* bytes = new unsigned char[nBytes]; int i = 0; @@ -176,7 +181,7 @@ void DecodedBitStreamParser::decodeNumericSegment(Ref bits, ostringst delete[] bytes; } -void DecodedBitStreamParser::decodeAlphanumericSegment(Ref bits, ostringstream &result, int count) { +void DecodedBitStreamParser::decodeAlphanumericSegment(Ref bits, std::string &result, int count) { int nBytes = count; unsigned char* bytes = new unsigned char[nBytes]; int i = 0; @@ -248,7 +253,7 @@ DecodedBitStreamParser::guessEncoding(unsigned char *bytes, int length) { } string DecodedBitStreamParser::decode(ArrayRef bytes, Version *version) { - ostringstream result; + string result; Ref bits(new BitSource(bytes)); Mode *mode = &Mode::TERMINATOR; do { @@ -275,7 +280,7 @@ string DecodedBitStreamParser::decode(ArrayRef bytes, Version *ve } } } while (mode != &Mode::TERMINATOR); - return result.str(); + return result; } } diff --git a/symbian/ZXingBarcodeReader/group/zxing/qrcode/decoder/DecodedBitStreamParser.h b/symbian/ZXingBarcodeReader/group/zxing/qrcode/decoder/DecodedBitStreamParser.h index 8c4ab9bb3..83582e156 100644 --- a/symbian/ZXingBarcodeReader/group/zxing/qrcode/decoder/DecodedBitStreamParser.h +++ b/symbian/ZXingBarcodeReader/group/zxing/qrcode/decoder/DecodedBitStreamParser.h @@ -43,12 +43,12 @@ private: static const char *SHIFT_JIS; static const char *EUC_JP; - static void decodeKanjiSegment(Ref bits, std::ostringstream &result, int count); - static void decodeByteSegment(Ref bits, std::ostringstream &result, int count); - static void decodeAlphanumericSegment(Ref bits, std::ostringstream &result, int count); - static void decodeNumericSegment(Ref bits, std::ostringstream &result, int count); + static void decodeKanjiSegment(Ref bits, std::string &result, int count); + static void decodeByteSegment(Ref bits, std::string &result, int count); + static void decodeAlphanumericSegment(Ref bits, std::string &result, int count); + static void decodeNumericSegment(Ref bits, std::string &result, int count); static const char *guessEncoding(unsigned char *bytes, int length); - static void append(std::ostream &ost, const unsigned char *bufIn, size_t nIn, const char *src); + static void append(std::string &ost, const unsigned char *bufIn, size_t nIn, const char *src); public: static std::string decode(ArrayRef bytes, Version *version); diff --git a/symbian/ZXingBarcodeReader/group/zxing/qrcode/decoder/Decoder.h b/symbian/ZXingBarcodeReader/group/zxing/qrcode/decoder/Decoder.h index 96e1dc0cc..14053a3a0 100644 --- a/symbian/ZXingBarcodeReader/group/zxing/qrcode/decoder/Decoder.h +++ b/symbian/ZXingBarcodeReader/group/zxing/qrcode/decoder/Decoder.h @@ -27,7 +27,6 @@ #include #include #include -#include namespace zxing { namespace qrcode { diff --git a/symbian/ZXingBarcodeReader/group/zxing/qrcode/detector/AlignmentPattern.cpp b/symbian/ZXingBarcodeReader/group/zxing/qrcode/detector/AlignmentPattern.cpp index 0f6ee592b..25baeb365 100644 --- a/symbian/ZXingBarcodeReader/group/zxing/qrcode/detector/AlignmentPattern.cpp +++ b/symbian/ZXingBarcodeReader/group/zxing/qrcode/detector/AlignmentPattern.cpp @@ -29,15 +29,15 @@ AlignmentPattern::AlignmentPattern(float posX, float posY, float estimatedModule posX_(posX), posY_(posY), estimatedModuleSize_(estimatedModuleSize) { } -float AlignmentPattern::getX() { +float AlignmentPattern::getX() const { return posX_; } -float AlignmentPattern::getY() { +float AlignmentPattern::getY() const { return posY_; } -bool AlignmentPattern::aboutEquals(float moduleSize, float i, float j) { +bool AlignmentPattern::aboutEquals(float moduleSize, float i, float j) const { return abs(i - posY_) <= moduleSize && abs(j - posX_) <= moduleSize && (abs(moduleSize - estimatedModuleSize_) <= 1.0f || abs(moduleSize - estimatedModuleSize_) / estimatedModuleSize_ <= 0.1f); } diff --git a/symbian/ZXingBarcodeReader/group/zxing/qrcode/detector/AlignmentPattern.h b/symbian/ZXingBarcodeReader/group/zxing/qrcode/detector/AlignmentPattern.h index 56a683f95..b822afacb 100644 --- a/symbian/ZXingBarcodeReader/group/zxing/qrcode/detector/AlignmentPattern.h +++ b/symbian/ZXingBarcodeReader/group/zxing/qrcode/detector/AlignmentPattern.h @@ -35,9 +35,9 @@ namespace zxing { public: AlignmentPattern(float posX, float posY, float estimatedModuleSize); - float getX(); - float getY(); - bool aboutEquals(float moduleSize, float i, float j); + float getX() const; + float getY() const; + bool aboutEquals(float moduleSize, float i, float j) const; }; } diff --git a/symbian/ZXingBarcodeReader/group/zxing/qrcode/detector/AlignmentPatternFinder.cpp b/symbian/ZXingBarcodeReader/group/zxing/qrcode/detector/AlignmentPatternFinder.cpp index b3d92d40c..017e2ee6b 100644 --- a/symbian/ZXingBarcodeReader/group/zxing/qrcode/detector/AlignmentPatternFinder.cpp +++ b/symbian/ZXingBarcodeReader/group/zxing/qrcode/detector/AlignmentPatternFinder.cpp @@ -23,17 +23,18 @@ #include #include #include +#include namespace zxing { namespace qrcode { using namespace std; -float AlignmentPatternFinder::centerFromEnd(valarray &stateCount, int end) { +float AlignmentPatternFinder::centerFromEnd(vector &stateCount, int end) { return (float)(end - stateCount[2]) - stateCount[1] / 2.0f; } -bool AlignmentPatternFinder::foundPatternCross(valarray &stateCount) { +bool AlignmentPatternFinder::foundPatternCross(vector &stateCount) { float maxVariance = moduleSize_ / 2.0f; for (size_t i = 0; i < 3; i++) { if (abs(moduleSize_ - stateCount[i]) >= maxVariance) { @@ -46,7 +47,7 @@ bool AlignmentPatternFinder::foundPatternCross(valarray &stateCount) { float AlignmentPatternFinder::crossCheckVertical(size_t startI, size_t centerJ, int maxCount, int originalStateCountTotal) { int maxI = image_->getHeight(); - valarray stateCount(0, 3); + vector stateCount(3, 0); // Start counting up from center @@ -92,7 +93,7 @@ float AlignmentPatternFinder::crossCheckVertical(size_t startI, size_t centerJ, return foundPatternCross(stateCount) ? centerFromEnd(stateCount, i) : NAN; } -Ref AlignmentPatternFinder::handlePossibleCenter(valarray &stateCount, size_t i, size_t j) { +Ref AlignmentPatternFinder::handlePossibleCenter(vector &stateCount, size_t i, size_t j) { int stateCountTotal = stateCount[0] + stateCount[1] + stateCount[2]; float centerJ = centerFromEnd(stateCount, j); float centerI = crossCheckVertical(i, (int)centerJ, 2 * stateCount[1], stateCountTotal); @@ -136,7 +137,7 @@ Ref AlignmentPatternFinder::find() { // Ref luminanceRow(new BitArray(width_)); // We are looking for black/white/black modules in 1:1:1 ratio; // this tracks the number of black/white/black modules seen so far - valarray stateCount(0, 3); + vector stateCount(3, 0); for (size_t iGen = 0; iGen < height_; iGen++) { // Search from middle outwards size_t i = middleI + ((iGen & 0x01) == 0 ? ((iGen + 1) >> 1) : -((iGen + 1) >> 1)); diff --git a/symbian/ZXingBarcodeReader/group/zxing/qrcode/detector/AlignmentPatternFinder.h b/symbian/ZXingBarcodeReader/group/zxing/qrcode/detector/AlignmentPatternFinder.h index 266364316..6221b6c32 100644 --- a/symbian/ZXingBarcodeReader/group/zxing/qrcode/detector/AlignmentPatternFinder.h +++ b/symbian/ZXingBarcodeReader/group/zxing/qrcode/detector/AlignmentPatternFinder.h @@ -43,18 +43,23 @@ private: size_t height_; float moduleSize_; - static float centerFromEnd(std::valarray &stateCount, int end); - bool foundPatternCross(std::valarray &stateCount); + static float centerFromEnd(std::vector &stateCount, int end); + bool foundPatternCross(std::vector &stateCount); float crossCheckVertical(size_t startI, size_t centerJ, int maxCount, int originalStateCountTotal); - Ref handlePossibleCenter(std::valarray &stateCount, size_t i, size_t j); + Ref handlePossibleCenter(std::vector &stateCount, size_t i, size_t j); public: AlignmentPatternFinder(Ref image, size_t startX, size_t startY, size_t width, size_t height, float moduleSize); ~AlignmentPatternFinder(); Ref find(); + +private: + AlignmentPatternFinder(const AlignmentPatternFinder&); + AlignmentPatternFinder& operator =(const AlignmentPatternFinder&); + }; } } diff --git a/symbian/ZXingBarcodeReader/group/zxing/qrcode/detector/Detector.cpp b/symbian/ZXingBarcodeReader/group/zxing/qrcode/detector/Detector.cpp index 9dbc29754..a50424c9e 100644 --- a/symbian/ZXingBarcodeReader/group/zxing/qrcode/detector/Detector.cpp +++ b/symbian/ZXingBarcodeReader/group/zxing/qrcode/detector/Detector.cpp @@ -27,6 +27,7 @@ #include #include #include +#include namespace zxing { namespace qrcode { @@ -133,8 +134,8 @@ Ref Detector::sampleGrid(Ref image, int dimension, Ref topLeft, Ref topRight, Ref bottomLeft, float moduleSize) { - int tltrCentersDimension = lround(FinderPatternFinder::distance(topLeft, topRight) / moduleSize); - int tlblCentersDimension = lround(FinderPatternFinder::distance(topLeft, bottomLeft) / moduleSize); + int tltrCentersDimension = int(FinderPatternFinder::distance(topLeft, topRight) / moduleSize + 0.5f); + int tlblCentersDimension = int(FinderPatternFinder::distance(topLeft, bottomLeft) / moduleSize + 0.5f); int dimension = ((tltrCentersDimension + tlblCentersDimension) >> 1) + 7; switch (dimension & 0x03) { // mod 4 case 0: diff --git a/symbian/ZXingBarcodeReader/group/zxing/qrcode/detector/FinderPattern.cpp b/symbian/ZXingBarcodeReader/group/zxing/qrcode/detector/FinderPattern.cpp index 531d4e2a1..1c9a53414 100644 --- a/symbian/ZXingBarcodeReader/group/zxing/qrcode/detector/FinderPattern.cpp +++ b/symbian/ZXingBarcodeReader/group/zxing/qrcode/detector/FinderPattern.cpp @@ -29,19 +29,19 @@ namespace zxing { posX_(posX), posY_(posY), estimatedModuleSize_(estimatedModuleSize), counter_(1) { } - float FinderPattern::getX() { + float FinderPattern::getX() const { return posX_; } - float FinderPattern::getY() { + float FinderPattern::getY() const { return posY_; } - int FinderPattern::getCount() { + int FinderPattern::getCount() const { return counter_; } - float FinderPattern::getEstimatedModuleSize() { + float FinderPattern::getEstimatedModuleSize() const { return estimatedModuleSize_; } @@ -49,7 +49,7 @@ namespace zxing { counter_++; } - bool FinderPattern::aboutEquals(float moduleSize, float i, float j) { + bool FinderPattern::aboutEquals(float moduleSize, float i, float j) const { return abs(i - posY_) <= moduleSize && abs(j - posX_) <= moduleSize && (abs(moduleSize - estimatedModuleSize_) <= 1.0f || abs(moduleSize - estimatedModuleSize_) / estimatedModuleSize_ <= 0.1f); } diff --git a/symbian/ZXingBarcodeReader/group/zxing/qrcode/detector/FinderPattern.h b/symbian/ZXingBarcodeReader/group/zxing/qrcode/detector/FinderPattern.h index 0b6615c81..8b2ff590f 100644 --- a/symbian/ZXingBarcodeReader/group/zxing/qrcode/detector/FinderPattern.h +++ b/symbian/ZXingBarcodeReader/group/zxing/qrcode/detector/FinderPattern.h @@ -36,12 +36,12 @@ namespace zxing { public: FinderPattern(float posX, float posY, float estimatedModuleSize); - float getX(); - float getY(); - int getCount(); - float getEstimatedModuleSize(); + float getX() const; + float getY() const; + int getCount() const; + float getEstimatedModuleSize() const; void incrementCount(); - bool aboutEquals(float moduleSize, float i, float j); + bool aboutEquals(float moduleSize, float i, float j) const; }; } } diff --git a/symbian/ZXingBarcodeReader/group/zxing/qrcode/detector/FinderPatternFinder.cpp b/symbian/ZXingBarcodeReader/group/zxing/qrcode/detector/FinderPatternFinder.cpp index 666c4f210..8b46b0f2b 100644 --- a/symbian/ZXingBarcodeReader/group/zxing/qrcode/detector/FinderPatternFinder.cpp +++ b/symbian/ZXingBarcodeReader/group/zxing/qrcode/detector/FinderPatternFinder.cpp @@ -22,6 +22,8 @@ #include #include #include +#include +#include namespace zxing { namespace qrcode { @@ -32,6 +34,8 @@ class ClosestToAverageComparator { private: float averageModuleSize_; public: + ClosestToAverageComparator() : averageModuleSize_(0.0f) { } + ClosestToAverageComparator(float averageModuleSize) : averageModuleSize_(averageModuleSize) { } @@ -393,7 +397,7 @@ Ref FinderPatternFinder::find() { // We are looking for black/white/black/white/black modules in // 1:1:3:1:1 ratio; this tracks the number of such modules seen so far - // As this is used often, we use an integer array instead of valarray + // As this is used often, we use an integer array instead of vector int stateCount[5]; bool done = false; diff --git a/symbian/ZXingBarcodeReader/group/zxing/qrcode/detector/QREdgeDetector.cpp b/symbian/ZXingBarcodeReader/group/zxing/qrcode/detector/QREdgeDetector.cpp index 18affe6e1..b2162ef50 100644 --- a/symbian/ZXingBarcodeReader/group/zxing/qrcode/detector/QREdgeDetector.cpp +++ b/symbian/ZXingBarcodeReader/group/zxing/qrcode/detector/QREdgeDetector.cpp @@ -20,6 +20,7 @@ #include #include +#include using namespace std; diff --git a/symbian/ZXingBarcodeReader/inc/CameraImage.h b/symbian/ZXingBarcodeReader/inc/CameraImage.h index a91950407..e8b102802 100644 --- a/symbian/ZXingBarcodeReader/inc/CameraImage.h +++ b/symbian/ZXingBarcodeReader/inc/CameraImage.h @@ -15,10 +15,10 @@ public: CameraImage(CameraImage& otherInstance); ~CameraImage(); - int getWidth(); - int getHeight(); + int getWidth() const; + int getHeight() const; - unsigned char getPixel(int x, int y); + unsigned char getPixel(int x, int y) const; void setImage(CFbsBitmap* newImage); diff --git a/symbian/ZXingBarcodeReader/sis/ZXingBarcodeReader_S60.sisx b/symbian/ZXingBarcodeReader/sis/ZXingBarcodeReader_S60.sisx index abdf27b9e..81fdd0212 100644 Binary files a/symbian/ZXingBarcodeReader/sis/ZXingBarcodeReader_S60.sisx and b/symbian/ZXingBarcodeReader/sis/ZXingBarcodeReader_S60.sisx differ diff --git a/symbian/ZXingBarcodeReader/src/CameraImage.cpp b/symbian/ZXingBarcodeReader/src/CameraImage.cpp index 4ebce640f..d7a44c47f 100644 --- a/symbian/ZXingBarcodeReader/src/CameraImage.cpp +++ b/symbian/ZXingBarcodeReader/src/CameraImage.cpp @@ -14,17 +14,17 @@ CameraImage::~CameraImage() { } -int CameraImage::getWidth() +int CameraImage::getWidth() const { return image->SizeInPixels().iWidth; } -int CameraImage::getHeight() +int CameraImage::getHeight() const { return image->SizeInPixels().iHeight; } -unsigned char CameraImage::getPixel(int x, int y) +unsigned char CameraImage::getPixel(int x, int y) const { TPoint pixelPosition(x,y); TRgb color; diff --git a/symbian/ZXingBarcodeReader/src/DecodingOperations.cpp b/symbian/ZXingBarcodeReader/src/DecodingOperations.cpp index 47b87437a..b7287a9af 100644 --- a/symbian/ZXingBarcodeReader/src/DecodingOperations.cpp +++ b/symbian/ZXingBarcodeReader/src/DecodingOperations.cpp @@ -2,6 +2,7 @@ #include #include +#include #include #include @@ -35,7 +36,7 @@ TInt CZXingBarcodeReaderAppView::Tick(TAny* aObject) void CZXingBarcodeReaderAppView::decodeBackbufferImage() { - QRCodeReader decoder; + MultiFormatReader decoder; CameraImage image; image.setImage(iBackBuffer);