diff --git a/cpp/.gdbinit b/cpp/.gdbinit new file mode 100644 index 000000000..adb6d4184 --- /dev/null +++ b/cpp/.gdbinit @@ -0,0 +1 @@ +set history save on diff --git a/cpp/.valgrind.supp b/cpp/.valgrind.supp index a77f590ab..4b343b323 100644 --- a/cpp/.valgrind.supp +++ b/cpp/.valgrind.supp @@ -1,14 +1,12 @@ { - zxing::common::CharacterSetECI::init_tables - Memcheck:Leak - fun:malloc - ... - fun:_ZN5zxing6common15CharacterSetECI11init_tablesEv -} + dlsym + Memcheck:Value8 + fun:_simple_salloc + fun:_ZN4dyld9mkstringfEPKcz +} { - ImageMagick - Memcheck:Leak - ... - fun:AcquireImage + dlsym + Memcheck:Cond + fun:_ZN4dyld9mkstringfEPKcz } \ No newline at end of file diff --git a/cpp/core/src/zxing/BarcodeFormat.cpp b/cpp/core/src/zxing/BarcodeFormat.cpp old mode 100755 new mode 100644 index 5dae4a106..d1044fd87 --- a/cpp/core/src/zxing/BarcodeFormat.cpp +++ b/cpp/core/src/zxing/BarcodeFormat.cpp @@ -18,20 +18,22 @@ #include -namespace zxing { - -const char *barcodeFormatNames[] = { - "None", - "QR_CODE", - "DATA_MATRIX", - "UPC_E", - "UPC_A", - "EAN_8", - "EAN_13", - "CODE_128", - "CODE_39", - "ITF", - "AZTEC" +const char* zxing::BarcodeFormat::barcodeFormatNames[] = { + "AZTEC", + "CODABAR", + "CODE_39", + "CODE_93", + "CODE_128", + "DATA_MATRIX", + "EAN_8", + "EAN_13", + "ITF", + "MAXICODE", + "PDF_417", + "QR_CODE", + "RSS_14", + "RSS_EXPANDED", + "UPC_A", + "UPC_E", + "UPC_EAN_EXTENSION", }; - -} diff --git a/cpp/core/src/zxing/BarcodeFormat.h b/cpp/core/src/zxing/BarcodeFormat.h index 4dc9f6f8b..cb2bffb05 100644 --- a/cpp/core/src/zxing/BarcodeFormat.h +++ b/cpp/core/src/zxing/BarcodeFormat.h @@ -22,23 +22,41 @@ */ namespace zxing { - - typedef enum BarcodeFormat { - BarcodeFormat_None = 0, - BarcodeFormat_QR_CODE, - BarcodeFormat_DATA_MATRIX, - BarcodeFormat_UPC_E, - BarcodeFormat_UPC_A, - BarcodeFormat_EAN_8, - BarcodeFormat_EAN_13, - BarcodeFormat_CODE_128, - BarcodeFormat_CODE_39, - BarcodeFormat_ITF, - BarcodeFormat_AZTEC - } BarcodeFormat; + class BarcodeFormat; +} - /* if you update the enum, please update the name in BarcodeFormat.cpp */ - extern const char *barcodeFormatNames[]; +class zxing::BarcodeFormat { +public: + enum Value { + AZTEC, + CODABAR, + CODE_39, + CODE_93, + CODE_128, + DATA_MATRIX, + EAN_8, + EAN_13, + ITF, + MAXICODE, + PDF_417, + QR_CODE, + RSS_14, + RSS_EXPANDED, + UPC_A, + UPC_E, + UPC_EAN_EXTENSION, + }; + + BarcodeFormat(Value v) : value(v) {} + const Value value; + operator Value () const {return value;} + + /* if you update the enum, please update the name in BarcodeFormat.cpp */ + static char const* barcodeFormatNames[]; +}; + +namespace zxing { + class BarcodeFormat; } #endif // __BARCODE_FORMAT_H__ diff --git a/cpp/core/src/zxing/BinaryBitmap.cpp b/cpp/core/src/zxing/BinaryBitmap.cpp index a1c68dbf4..7cd3b8f99 100644 --- a/cpp/core/src/zxing/BinaryBitmap.cpp +++ b/cpp/core/src/zxing/BinaryBitmap.cpp @@ -1,3 +1,4 @@ +// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*- /* * BinaryBitmap.cpp * zxing @@ -19,49 +20,51 @@ #include -namespace zxing { +using zxing::Ref; +using zxing::BitArray; +using zxing::BitMatrix; +using zxing::LuminanceSource; +using zxing::BinaryBitmap; - BinaryBitmap::BinaryBitmap(Ref binarizer) : binarizer_(binarizer) { - - } - - BinaryBitmap::~BinaryBitmap() { - } - - Ref BinaryBitmap::getBlackRow(int y, Ref row) { - return binarizer_->getBlackRow(y, row); - } - - Ref BinaryBitmap::getBlackMatrix() { - return binarizer_->getBlackMatrix(); - } - - int BinaryBitmap::getWidth() const { - return getLuminanceSource()->getWidth(); - } - - int BinaryBitmap::getHeight() const { - return getLuminanceSource()->getHeight(); - } - - Ref BinaryBitmap::getLuminanceSource() const { - return binarizer_->getLuminanceSource(); - } - - - bool BinaryBitmap::isCropSupported() const { - return getLuminanceSource()->isCropSupported(); - } - - Ref BinaryBitmap::crop(int left, int top, int width, int height) { - return Ref (new BinaryBitmap(binarizer_->createBinarizer(getLuminanceSource()->crop(left, top, width, height)))); - } - - bool BinaryBitmap::isRotateSupported() const { - return getLuminanceSource()->isRotateSupported(); - } - - Ref BinaryBitmap::rotateCounterClockwise() { - return Ref (new BinaryBitmap(binarizer_->createBinarizer(getLuminanceSource()->rotateCounterClockwise()))); - } +BinaryBitmap::BinaryBitmap(Ref binarizer) : binarizer_(binarizer) { +} + +BinaryBitmap::~BinaryBitmap() { +} + +Ref BinaryBitmap::getBlackRow(int y, Ref row) { + return binarizer_->getBlackRow(y, row); +} + +Ref BinaryBitmap::getBlackMatrix() { + return binarizer_->getBlackMatrix(); +} + +int BinaryBitmap::getWidth() const { + return getLuminanceSource()->getWidth(); +} + +int BinaryBitmap::getHeight() const { + return getLuminanceSource()->getHeight(); +} + +Ref BinaryBitmap::getLuminanceSource() const { + return binarizer_->getLuminanceSource(); +} + + +bool BinaryBitmap::isCropSupported() const { + return getLuminanceSource()->isCropSupported(); +} + +Ref BinaryBitmap::crop(int left, int top, int width, int height) { + return Ref (new BinaryBitmap(binarizer_->createBinarizer(getLuminanceSource()->crop(left, top, width, height)))); +} + +bool BinaryBitmap::isRotateSupported() const { + return getLuminanceSource()->isRotateSupported(); +} + +Ref BinaryBitmap::rotateCounterClockwise() { + return Ref (new BinaryBitmap(binarizer_->createBinarizer(getLuminanceSource()->rotateCounterClockwise()))); } diff --git a/cpp/core/src/zxing/ChecksumException.cpp b/cpp/core/src/zxing/ChecksumException.cpp new file mode 100644 index 000000000..f03e9e35f --- /dev/null +++ b/cpp/core/src/zxing/ChecksumException.cpp @@ -0,0 +1,41 @@ +// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*- +/* + * ChecksumException.cpp + * zxing + * + * Created by Christian Brunschen on 13/05/2008. + * Copyright 2008 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 { + +ChecksumException::ChecksumException() {} + +ChecksumException::ChecksumException(const char *msg) : + ReaderException(msg) { +} + +ChecksumException::~ChecksumException() throw() { +} + +ChecksumException const& +ChecksumException::getChecksumInstance() { + static ChecksumException instance; + return instance; +} + +} diff --git a/cpp/core/src/zxing/ChecksumException.h b/cpp/core/src/zxing/ChecksumException.h new file mode 100644 index 000000000..c3df7ed41 --- /dev/null +++ b/cpp/core/src/zxing/ChecksumException.h @@ -0,0 +1,35 @@ +// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*- + +#ifndef __CHECKSUM_EXCEPTION_H__ +#define __NOT_FOUND_EXCEPTION_H__ + +/* + * Copyright 20011 ZXing authors + * + * 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 { + class ChecksumException : public ReaderException { + typedef ReaderException Base; + public: + ChecksumException(); + ChecksumException(const char *msg); + ~ChecksumException() throw(); + static ChecksumException const& getChecksumInstance(); + }; +} + +#endif // __CHECKSUM_EXCEPTION_H__ diff --git a/cpp/core/src/zxing/DecodeHints.cpp b/cpp/core/src/zxing/DecodeHints.cpp index 6bbac0f1c..16d339b98 100644 --- a/cpp/core/src/zxing/DecodeHints.cpp +++ b/cpp/core/src/zxing/DecodeHints.cpp @@ -1,3 +1,4 @@ +// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*- /* * DecodeHintType.cpp * zxing @@ -19,36 +20,37 @@ #include #include -namespace zxing { + +using zxing::Ref; +using zxing::ResultPointCallback; +using zxing::DecodeHintType; +using zxing::DecodeHints; const DecodeHintType DecodeHints::CHARACTER_SET; const DecodeHints DecodeHints::PRODUCT_HINT( - BARCODEFORMAT_UPC_E_HINT | - BARCODEFORMAT_UPC_A_HINT | - BARCODEFORMAT_EAN_8_HINT | - BARCODEFORMAT_EAN_13_HINT); + UPC_A_HINT | + UPC_E_HINT | + EAN_13_HINT | + EAN_8_HINT | + RSS_14_HINT + ); const DecodeHints DecodeHints::ONED_HINT( - BARCODEFORMAT_UPC_E_HINT | - BARCODEFORMAT_UPC_A_HINT | - BARCODEFORMAT_EAN_8_HINT | - BARCODEFORMAT_EAN_13_HINT | - BARCODEFORMAT_CODE_128_HINT | - BARCODEFORMAT_CODE_39_HINT | - BARCODEFORMAT_ITF_HINT); + CODE_39_HINT | + CODE_93_HINT | + CODE_128_HINT | + ITF_HINT | + CODABAR_HINT | + DecodeHints::PRODUCT_HINT + ); const DecodeHints DecodeHints::DEFAULT_HINT( - BARCODEFORMAT_UPC_E_HINT | - BARCODEFORMAT_UPC_A_HINT | - BARCODEFORMAT_EAN_8_HINT | - BARCODEFORMAT_EAN_13_HINT | - BARCODEFORMAT_CODE_128_HINT | - BARCODEFORMAT_CODE_39_HINT | - BARCODEFORMAT_ITF_HINT | - BARCODEFORMAT_DATA_MATRIX_HINT | - BARCODEFORMAT_AZTEC_HINT | - BARCODEFORMAT_QR_CODE_HINT); + ONED_HINT | + QR_CODE_HINT | + DATA_MATRIX_HINT | + AZTEC_HINT + ); DecodeHints::DecodeHints() { hints = 0; @@ -60,34 +62,46 @@ DecodeHints::DecodeHints(DecodeHintType init) { void DecodeHints::addFormat(BarcodeFormat toadd) { switch (toadd) { - case BarcodeFormat_AZTEC: hints |= BARCODEFORMAT_AZTEC_HINT; break; - case BarcodeFormat_QR_CODE: hints |= BARCODEFORMAT_QR_CODE_HINT; break; - case BarcodeFormat_DATA_MATRIX: hints |= BARCODEFORMAT_DATA_MATRIX_HINT; break; - case BarcodeFormat_UPC_E: hints |= BARCODEFORMAT_UPC_E_HINT; break; - case BarcodeFormat_UPC_A: hints |= BARCODEFORMAT_UPC_A_HINT; break; - case BarcodeFormat_EAN_8: hints |= BARCODEFORMAT_EAN_8_HINT; break; - case BarcodeFormat_EAN_13: hints |= BARCODEFORMAT_EAN_13_HINT; break; - case BarcodeFormat_CODE_128: hints |= BARCODEFORMAT_CODE_128_HINT; break; - case BarcodeFormat_CODE_39: hints |= BARCODEFORMAT_CODE_39_HINT; break; - case BarcodeFormat_ITF: hints |= BARCODEFORMAT_ITF_HINT; break; - default: throw IllegalArgumentException("Unrecognizd barcode format"); + case BarcodeFormat::AZTEC: hints |= AZTEC_HINT; break; + case BarcodeFormat::CODABAR: hints |= CODABAR_HINT; break; + case BarcodeFormat::CODE_39: hints |= CODE_39_HINT; break; + case BarcodeFormat::CODE_93: hints |= CODE_93_HINT; break; + case BarcodeFormat::CODE_128: hints |= CODE_128_HINT; break; + case BarcodeFormat::DATA_MATRIX: hints |= DATA_MATRIX_HINT; break; + case BarcodeFormat::EAN_8: hints |= EAN_8_HINT; break; + case BarcodeFormat::EAN_13: hints |= EAN_13_HINT; break; + case BarcodeFormat::ITF: hints |= ITF_HINT; break; + case BarcodeFormat::MAXICODE: hints |= MAXICODE_HINT; break; + case BarcodeFormat::QR_CODE: hints |= QR_CODE_HINT; break; + case BarcodeFormat::RSS_14: hints |= RSS_14_HINT; break; + case BarcodeFormat::RSS_EXPANDED: hints |= RSS_EXPANDED_HINT; break; + case BarcodeFormat::UPC_A: hints |= UPC_A_HINT; break; + case BarcodeFormat::UPC_E: hints |= UPC_E_HINT; break; + case BarcodeFormat::UPC_EAN_EXTENSION: hints |= UPC_EAN_EXTENSION_HINT; break; + default: throw IllegalArgumentException("Unrecognizd barcode format"); } } bool DecodeHints::containsFormat(BarcodeFormat tocheck) const { - DecodeHintType checkAgainst; + DecodeHintType checkAgainst = 0; switch (tocheck) { - case BarcodeFormat_AZTEC: checkAgainst = BARCODEFORMAT_AZTEC_HINT; break; - case BarcodeFormat_QR_CODE: checkAgainst = BARCODEFORMAT_QR_CODE_HINT; break; - case BarcodeFormat_DATA_MATRIX: checkAgainst = BARCODEFORMAT_DATA_MATRIX_HINT; break; - case BarcodeFormat_UPC_E: checkAgainst = BARCODEFORMAT_UPC_E_HINT; break; - case BarcodeFormat_UPC_A: checkAgainst = BARCODEFORMAT_UPC_A_HINT; break; - case BarcodeFormat_EAN_8: checkAgainst = BARCODEFORMAT_EAN_8_HINT; break; - case BarcodeFormat_EAN_13: checkAgainst = BARCODEFORMAT_EAN_13_HINT; break; - case BarcodeFormat_CODE_128: checkAgainst = BARCODEFORMAT_CODE_128_HINT; break; - case BarcodeFormat_CODE_39: checkAgainst = BARCODEFORMAT_CODE_39_HINT; break; - case BarcodeFormat_ITF: checkAgainst = BARCODEFORMAT_ITF_HINT; break; - default: throw IllegalArgumentException("Unrecognizd barcode format"); + case BarcodeFormat::AZTEC: checkAgainst |= AZTEC_HINT; break; + case BarcodeFormat::CODABAR: checkAgainst |= CODABAR_HINT; break; + case BarcodeFormat::CODE_39: checkAgainst |= CODE_39_HINT; break; + case BarcodeFormat::CODE_93: checkAgainst |= CODE_93_HINT; break; + case BarcodeFormat::CODE_128: checkAgainst |= CODE_128_HINT; break; + case BarcodeFormat::DATA_MATRIX: checkAgainst |= DATA_MATRIX_HINT; break; + case BarcodeFormat::EAN_8: checkAgainst |= EAN_8_HINT; break; + case BarcodeFormat::EAN_13: checkAgainst |= EAN_13_HINT; break; + case BarcodeFormat::ITF: checkAgainst |= ITF_HINT; break; + case BarcodeFormat::MAXICODE: checkAgainst |= MAXICODE_HINT; break; + case BarcodeFormat::QR_CODE: checkAgainst |= QR_CODE_HINT; break; + case BarcodeFormat::RSS_14: checkAgainst |= RSS_14_HINT; break; + case BarcodeFormat::RSS_EXPANDED: checkAgainst |= RSS_EXPANDED_HINT; break; + case BarcodeFormat::UPC_A: checkAgainst |= UPC_A_HINT; break; + case BarcodeFormat::UPC_E: checkAgainst |= UPC_E_HINT; break; + case BarcodeFormat::UPC_EAN_EXTENSION: checkAgainst |= UPC_EAN_EXTENSION_HINT; break; + default: throw IllegalArgumentException("Unrecognizd barcode format"); } return (hints & checkAgainst); } @@ -105,11 +119,18 @@ bool DecodeHints::getTryHarder() const { } void DecodeHints::setResultPointCallback(Ref const& _callback) { - callback = _callback; + callback = _callback; } Ref DecodeHints::getResultPointCallback() const { - return callback; + return callback; } -} /* namespace */ +DecodeHints zxing::operator | (DecodeHints const& l, DecodeHints const& r) { + DecodeHints result (l); + result.hints |= r.hints; + if (!result.callback) { + result.callback = r.callback; + } + return result; +} diff --git a/cpp/core/src/zxing/DecodeHints.h b/cpp/core/src/zxing/DecodeHints.h index 16486665c..c8bc58fa6 100644 --- a/cpp/core/src/zxing/DecodeHints.h +++ b/cpp/core/src/zxing/DecodeHints.h @@ -1,3 +1,4 @@ +// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*- #ifndef __DECODEHINTS_H_ #define __DECODEHINTS_H_ /* @@ -23,29 +24,35 @@ #include namespace zxing { + typedef unsigned int DecodeHintType; + class DecodeHints; + DecodeHints operator | (DecodeHints const&, DecodeHints const&); +} -typedef unsigned int DecodeHintType; - -class DecodeHints { - +class zxing::DecodeHints { private: - DecodeHintType hints; - Ref callback; public: + static const DecodeHintType AZTEC_HINT = 1 << BarcodeFormat::AZTEC; + static const DecodeHintType CODABAR_HINT = 1 << BarcodeFormat::CODABAR; + static const DecodeHintType CODE_39_HINT = 1 << BarcodeFormat::CODE_39; + static const DecodeHintType CODE_93_HINT = 1 << BarcodeFormat::CODE_93; + static const DecodeHintType CODE_128_HINT = 1 << BarcodeFormat::CODE_128; + static const DecodeHintType DATA_MATRIX_HINT = 1 << BarcodeFormat::DATA_MATRIX; + static const DecodeHintType EAN_8_HINT = 1 << BarcodeFormat::EAN_8; + static const DecodeHintType EAN_13_HINT = 1 << BarcodeFormat::EAN_13; + static const DecodeHintType ITF_HINT = 1 << BarcodeFormat::ITF; + static const DecodeHintType MAXICODE_HINT = 1 << BarcodeFormat::MAXICODE; + static const DecodeHintType PDF_417_HINT = 1 << BarcodeFormat::PDF_417; + static const DecodeHintType QR_CODE_HINT = 1 << BarcodeFormat::QR_CODE; + static const DecodeHintType RSS_14_HINT = 1 << BarcodeFormat::RSS_14; + static const DecodeHintType RSS_EXPANDED_HINT = 1 << BarcodeFormat::RSS_EXPANDED; + static const DecodeHintType UPC_A_HINT = 1 << BarcodeFormat::UPC_A; + static const DecodeHintType UPC_E_HINT = 1 << BarcodeFormat::UPC_E; + static const DecodeHintType UPC_EAN_EXTENSION_HINT = 1 << BarcodeFormat::UPC_EAN_EXTENSION; - static const DecodeHintType BARCODEFORMAT_QR_CODE_HINT = 1 << BarcodeFormat_QR_CODE; - static const DecodeHintType BARCODEFORMAT_DATA_MATRIX_HINT = 1 << BarcodeFormat_DATA_MATRIX; - static const DecodeHintType BARCODEFORMAT_UPC_E_HINT = 1 << BarcodeFormat_UPC_E; - static const DecodeHintType BARCODEFORMAT_UPC_A_HINT = 1 << BarcodeFormat_UPC_A; - static const DecodeHintType BARCODEFORMAT_EAN_8_HINT = 1 << BarcodeFormat_EAN_8; - static const DecodeHintType BARCODEFORMAT_EAN_13_HINT = 1 << BarcodeFormat_EAN_13; - static const DecodeHintType BARCODEFORMAT_CODE_128_HINT = 1 << BarcodeFormat_CODE_128; - static const DecodeHintType BARCODEFORMAT_CODE_39_HINT = 1 << BarcodeFormat_CODE_39; - static const DecodeHintType BARCODEFORMAT_ITF_HINT = 1 << BarcodeFormat_ITF; - static const DecodeHintType BARCODEFORMAT_AZTEC_HINT = 1 << BarcodeFormat_AZTEC; static const DecodeHintType CHARACTER_SET = 1 << 30; static const DecodeHintType TRYHARDER_HINT = 1 << 31; @@ -64,8 +71,7 @@ class DecodeHints { void setResultPointCallback(Ref const&); Ref getResultPointCallback() const; + friend DecodeHints operator | (DecodeHints const&, DecodeHints const&); }; -} - #endif diff --git a/cpp/core/src/zxing/FormatException.cpp b/cpp/core/src/zxing/FormatException.cpp index d3981c50f..488b3d48d 100644 --- a/cpp/core/src/zxing/FormatException.cpp +++ b/cpp/core/src/zxing/FormatException.cpp @@ -32,4 +32,10 @@ FormatException::FormatException(const char *msg) : FormatException::~FormatException() throw() { } +FormatException const& +FormatException::getFormatInstance() { + static FormatException instance; + return instance; +} + } diff --git a/cpp/core/src/zxing/FormatException.h b/cpp/core/src/zxing/FormatException.h index da50b501e..090d79cad 100644 --- a/cpp/core/src/zxing/FormatException.h +++ b/cpp/core/src/zxing/FormatException.h @@ -29,6 +29,8 @@ public: FormatException(); FormatException(const char *msg); ~FormatException() throw(); + + static FormatException const& getFormatInstance(); }; } diff --git a/cpp/core/src/zxing/LuminanceSource.cpp b/cpp/core/src/zxing/LuminanceSource.cpp index 0ba1ff1e1..c2e0133b4 100644 --- a/cpp/core/src/zxing/LuminanceSource.cpp +++ b/cpp/core/src/zxing/LuminanceSource.cpp @@ -22,7 +22,8 @@ #include #include -namespace zxing { +using zxing::Ref; +using zxing::LuminanceSource; LuminanceSource::LuminanceSource() { } @@ -51,7 +52,7 @@ Ref LuminanceSource::rotateCounterClockwise() { } LuminanceSource::operator std::string() { - unsigned char* row = 0; + ArrayRef row; std::ostringstream oss; for (int y = 0; y < getHeight(); y++) { row = getRow(y, row); @@ -71,10 +72,5 @@ LuminanceSource::operator std::string() { } oss << '\n'; } - delete [] row; return oss.str(); } - - - -} diff --git a/cpp/core/src/zxing/LuminanceSource.h b/cpp/core/src/zxing/LuminanceSource.h index 7130808f5..6178e9aba 100644 --- a/cpp/core/src/zxing/LuminanceSource.h +++ b/cpp/core/src/zxing/LuminanceSource.h @@ -21,11 +21,14 @@ */ #include +#include #include namespace zxing { + class LuminanceSource; +} -class LuminanceSource : public Counted { +class zxing::LuminanceSource : public Counted { public: LuminanceSource(); virtual ~LuminanceSource(); @@ -34,8 +37,8 @@ public: virtual int getHeight() const = 0; // Callers take ownership of the returned memory and must call delete [] on it themselves. - virtual unsigned char* getRow(int y, unsigned char* row) = 0; - virtual unsigned char* getMatrix() = 0; + virtual ArrayRef getRow(int y, ArrayRef row) = 0; + virtual ArrayRef getMatrix() = 0; virtual bool isCropSupported() const; virtual Ref crop(int left, int top, int width, int height); @@ -44,9 +47,7 @@ public: virtual Ref rotateCounterClockwise(); operator std::string (); // should be const but don't want to make sure a - // large breaking change right now + // large breaking change right now }; -} - #endif /* LUMINANCESOURCE_H_ */ diff --git a/cpp/core/src/zxing/MultiFormatReader.cpp b/cpp/core/src/zxing/MultiFormatReader.cpp index 82067df0b..d60c38ec6 100644 --- a/cpp/core/src/zxing/MultiFormatReader.cpp +++ b/cpp/core/src/zxing/MultiFormatReader.cpp @@ -1,3 +1,4 @@ +// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*- /* * MultiFormatBarcodeReader.cpp * ZXing @@ -27,80 +28,96 @@ #include #include -namespace zxing { - MultiFormatReader::MultiFormatReader() { +using zxing::Ref; +using zxing::Result; +using zxing::MultiFormatReader; - } +MultiFormatReader::MultiFormatReader() {} - Ref MultiFormatReader::decode(Ref image) { +Ref MultiFormatReader::decode(Ref image) { + setHints(DecodeHints::DEFAULT_HINT); + return decodeInternal(image); +} + +Ref MultiFormatReader::decode(Ref image, DecodeHints hints) { + setHints(hints); + return decodeInternal(image); +} + +Ref MultiFormatReader::decodeWithState(Ref image) { + // Make sure to set up the default state so we don't crash + if (readers_.size() == 0) { setHints(DecodeHints::DEFAULT_HINT); - return decodeInternal(image); } + return decodeInternal(image); +} - Ref MultiFormatReader::decode(Ref image, DecodeHints hints) { - setHints(hints); - return decodeInternal(image); +void MultiFormatReader::setHints(DecodeHints hints) { + hints_ = hints; + readers_.clear(); + bool tryHarder = hints.getTryHarder(); + + bool addOneDReader = hints.containsFormat(BarcodeFormat::UPC_E) || + hints.containsFormat(BarcodeFormat::UPC_A) || + hints.containsFormat(BarcodeFormat::UPC_E) || + hints.containsFormat(BarcodeFormat::EAN_13) || + hints.containsFormat(BarcodeFormat::EAN_8) || + hints.containsFormat(BarcodeFormat::CODABAR) || + hints.containsFormat(BarcodeFormat::CODE_39) || + hints.containsFormat(BarcodeFormat::CODE_93) || + hints.containsFormat(BarcodeFormat::CODE_128) || + hints.containsFormat(BarcodeFormat::ITF) || + hints.containsFormat(BarcodeFormat::RSS_14) || + hints.containsFormat(BarcodeFormat::RSS_EXPANDED); + if (addOneDReader && !tryHarder) { + readers_.push_back(Ref(new zxing::oned::MultiFormatOneDReader(hints))); } - - Ref MultiFormatReader::decodeWithState(Ref image) { - // Make sure to set up the default state so we don't crash - if (readers_.size() == 0) { - setHints(DecodeHints::DEFAULT_HINT); - } - return decodeInternal(image); + if (hints.containsFormat(BarcodeFormat::QR_CODE)) { + readers_.push_back(Ref(new zxing::qrcode::QRCodeReader())); } - - void MultiFormatReader::setHints(DecodeHints hints) { - hints_ = hints; - readers_.clear(); - bool tryHarder = hints.getTryHarder(); - - bool addOneDReader = hints.containsFormat(BarcodeFormat_UPC_E) || - hints.containsFormat(BarcodeFormat_UPC_A) || - hints.containsFormat(BarcodeFormat_EAN_8) || - hints.containsFormat(BarcodeFormat_EAN_13) || - hints.containsFormat(BarcodeFormat_CODE_128) || - hints.containsFormat(BarcodeFormat_CODE_39) || - hints.containsFormat(BarcodeFormat_ITF); - if (addOneDReader && !tryHarder) { + if (hints.containsFormat(BarcodeFormat::DATA_MATRIX)) { + readers_.push_back(Ref(new zxing::datamatrix::DataMatrixReader())); + } + if (hints.containsFormat(BarcodeFormat::AZTEC)) { + readers_.push_back(Ref(new zxing::aztec::AztecReader())); + } +/* + if (formats.contains(BarcodeFormat.PDF_417)) { + readers.add(new PDF417Reader()); + } + if (formats.contains(BarcodeFormat.MAXICODE)) { + readers.add(new MaxiCodeReader()); + } +*/ + if (addOneDReader && tryHarder) { + readers_.push_back(Ref(new zxing::oned::MultiFormatOneDReader(hints))); + } + if (readers_.size() == 0) { + if (!tryHarder) { readers_.push_back(Ref(new zxing::oned::MultiFormatOneDReader(hints))); } - if (hints.containsFormat(BarcodeFormat_QR_CODE)) { - readers_.push_back(Ref(new zxing::qrcode::QRCodeReader())); - } - if (hints.containsFormat(BarcodeFormat_DATA_MATRIX)) { - readers_.push_back(Ref(new zxing::datamatrix::DataMatrixReader())); - } - if (hints.containsFormat(BarcodeFormat_AZTEC)) { - readers_.push_back(Ref(new zxing::aztec::AztecReader())); - } - //TODO: add PDF417 here once PDF417 reader is implemented - if (addOneDReader && tryHarder) { + readers_.push_back(Ref(new zxing::qrcode::QRCodeReader())); + readers_.push_back(Ref(new zxing::datamatrix::DataMatrixReader())); + readers_.push_back(Ref(new zxing::aztec::AztecReader())); + // readers.add(new PDF417Reader()); + // readers.add(new MaxiCodeReader()); + + if (tryHarder) { readers_.push_back(Ref(new zxing::oned::MultiFormatOneDReader(hints))); } - if (readers_.size() == 0) { - if (!tryHarder) { - readers_.push_back(Ref(new zxing::oned::MultiFormatOneDReader(hints))); - } - readers_.push_back(Ref(new zxing::qrcode::QRCodeReader())); - if (tryHarder) { - readers_.push_back(Ref(new zxing::oned::MultiFormatOneDReader(hints))); - } - } - } - - Ref MultiFormatReader::decodeInternal(Ref image) { - for (unsigned int i = 0; i < readers_.size(); i++) { - try { - return readers_[i]->decode(image, hints_); - } catch (ReaderException const& re) { - // continue - } - } - throw ReaderException("No code detected"); - } - - MultiFormatReader::~MultiFormatReader() { - } } + +Ref MultiFormatReader::decodeInternal(Ref image) { + for (unsigned int i = 0; i < readers_.size(); i++) { + try { + // std::cerr << "0 " << typeid(readers_[i]).name() << std::endl; + return readers_[i]->decode(image, hints_); + } catch (ReaderException const& re) { + // continue + } + } + throw ReaderException("No code detected"); +} + +MultiFormatReader::~MultiFormatReader() {} diff --git a/cpp/core/src/zxing/MultiFormatReader.h b/cpp/core/src/zxing/MultiFormatReader.h index 9411cfbf1..af07899f9 100644 --- a/cpp/core/src/zxing/MultiFormatReader.h +++ b/cpp/core/src/zxing/MultiFormatReader.h @@ -28,7 +28,6 @@ namespace zxing { class MultiFormatReader : public Reader { - private: Ref decodeInternal(Ref image); diff --git a/cpp/core/src/zxing/NotFoundException.cpp b/cpp/core/src/zxing/NotFoundException.cpp index 8adc51420..b35d6e040 100644 --- a/cpp/core/src/zxing/NotFoundException.cpp +++ b/cpp/core/src/zxing/NotFoundException.cpp @@ -17,14 +17,18 @@ #include -namespace zxing { +using zxing::NotFoundException; - NotFoundException::NotFoundException() {} +NotFoundException::NotFoundException() {} - NotFoundException::NotFoundException(const char *msg) - : ReaderException(msg) {} +NotFoundException::NotFoundException(const char *msg) + : ReaderException(msg) {} - NotFoundException::~NotFoundException() throw() { - } +NotFoundException::~NotFoundException() throw() {} + +NotFoundException const& +NotFoundException::getNotFoundInstance() { + static NotFoundException instance; + return instance; } diff --git a/cpp/core/src/zxing/NotFoundException.h b/cpp/core/src/zxing/NotFoundException.h index 1ef9609ed..4bdccdfeb 100644 --- a/cpp/core/src/zxing/NotFoundException.h +++ b/cpp/core/src/zxing/NotFoundException.h @@ -28,6 +28,8 @@ namespace zxing { NotFoundException(); NotFoundException(const char *msg); ~NotFoundException() throw(); + + static NotFoundException const& getNotFoundInstance(); }; } diff --git a/cpp/core/src/zxing/Reader.cpp b/cpp/core/src/zxing/Reader.cpp old mode 100755 new mode 100644 diff --git a/cpp/core/src/zxing/Reader.h b/cpp/core/src/zxing/Reader.h old mode 100755 new mode 100644 diff --git a/cpp/core/src/zxing/Result.cpp b/cpp/core/src/zxing/Result.cpp index 7ab6e312c..1ec7fd1d0 100644 --- a/cpp/core/src/zxing/Result.cpp +++ b/cpp/core/src/zxing/Result.cpp @@ -21,10 +21,15 @@ #include -namespace zxing { -using namespace std; +using zxing::Result; +using zxing::Ref; +using zxing::ArrayRef; +using zxing::String; +using zxing::ResultPoint; -Result::Result(Ref text, ArrayRef rawBytes, std::vector > resultPoints, +Result::Result(Ref text, + ArrayRef rawBytes, + ArrayRef< Ref > resultPoints, BarcodeFormat format) : text_(text), rawBytes_(rawBytes), resultPoints_(resultPoints), format_(format) { } @@ -36,29 +41,18 @@ Ref Result::getText() { return text_; } -ArrayRef Result::getRawBytes() { +ArrayRef Result::getRawBytes() { return rawBytes_; } -const std::vector >& Result::getResultPoints() const { +ArrayRef< Ref > const& Result::getResultPoints() const { return resultPoints_; } -std::vector >& Result::getResultPoints() { +ArrayRef< Ref >& Result::getResultPoints() { return resultPoints_; } -BarcodeFormat Result::getBarcodeFormat() const { +zxing::BarcodeFormat Result::getBarcodeFormat() const { return format_; } - -ostream& operator<<(ostream &out, Result& result) { - if (result.text_ != 0) { - out << result.text_->getText(); - } else { - out << "[" << result.rawBytes_->size() << " bytes]"; - } - return out; -} - -} diff --git a/cpp/core/src/zxing/Result.h b/cpp/core/src/zxing/Result.h index 711605962..1a5da7b8f 100644 --- a/cpp/core/src/zxing/Result.h +++ b/cpp/core/src/zxing/Result.h @@ -21,7 +21,6 @@ */ #include -#include #include #include #include @@ -33,18 +32,20 @@ namespace zxing { class Result : public Counted { private: Ref text_; - ArrayRef rawBytes_; - std::vector > resultPoints_; + ArrayRef rawBytes_; + ArrayRef< Ref > resultPoints_; BarcodeFormat format_; public: - Result(Ref text, ArrayRef rawBytes, std::vector > resultPoints, + Result(Ref text, + ArrayRef rawBytes, + ArrayRef< Ref > resultPoints, BarcodeFormat format); ~Result(); Ref getText(); - ArrayRef getRawBytes(); - const std::vector >& getResultPoints() const; - std::vector >& getResultPoints(); + ArrayRef getRawBytes(); + ArrayRef< Ref > const& getResultPoints() const; + ArrayRef< Ref >& getResultPoints(); BarcodeFormat getBarcodeFormat() const; friend std::ostream& operator<<(std::ostream &out, Result& result); diff --git a/cpp/core/src/zxing/ResultIO.cpp b/cpp/core/src/zxing/ResultIO.cpp new file mode 100644 index 000000000..e682dfab4 --- /dev/null +++ b/cpp/core/src/zxing/ResultIO.cpp @@ -0,0 +1,34 @@ +// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*- +/* + * ResultIO.cpp + * zxing + * + * Created by Christian Brunschen on 13/05/2008. + * Copyright 2008 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 + +using zxing::Result; +using std::ostream; + +ostream& zxing::operator<<(ostream &out, Result& result) { + if (result.text_ != 0) { + out << result.text_->getText(); + } else { + out << "[" << result.rawBytes_->size() << " bytes]"; + } + return out; +} diff --git a/cpp/core/src/zxing/ResultPoint.cpp b/cpp/core/src/zxing/ResultPoint.cpp old mode 100755 new mode 100644 diff --git a/cpp/core/src/zxing/aztec/AztecDetectorResult.cpp b/cpp/core/src/zxing/aztec/AztecDetectorResult.cpp index 72fae6931..5f29cfb92 100644 --- a/cpp/core/src/zxing/aztec/AztecDetectorResult.cpp +++ b/cpp/core/src/zxing/aztec/AztecDetectorResult.cpp @@ -21,25 +21,27 @@ #include -namespace zxing { - namespace aztec { - AztecDetectorResult::AztecDetectorResult(Ref bits, std::vector > points, bool compact, int nbDatablocks, int nbLayers) - : DetectorResult(bits, points), - compact_(compact), - nbDatablocks_(nbDatablocks), - nbLayers_(nbLayers) { - }; +using zxing::aztec::AztecDetectorResult; + +AztecDetectorResult::AztecDetectorResult(Ref bits, + ArrayRef< Ref > points, + bool compact, + int nbDatablocks, + int nbLayers) + : DetectorResult(bits, points), + compact_(compact), + nbDatablocks_(nbDatablocks), + nbLayers_(nbLayers) { + }; - bool AztecDetectorResult::isCompact() { - return compact_; - } +bool AztecDetectorResult::isCompact() { + return compact_; +} - int AztecDetectorResult::getNBDatablocks() { - return nbDatablocks_; - } +int AztecDetectorResult::getNBDatablocks() { + return nbDatablocks_; +} - int AztecDetectorResult::getNBLayers() { - return nbLayers_; - } - } -} \ No newline at end of file +int AztecDetectorResult::getNBLayers() { + return nbLayers_; +} diff --git a/cpp/core/src/zxing/aztec/AztecDetectorResult.h b/cpp/core/src/zxing/aztec/AztecDetectorResult.h index dc2cc4e3d..0e0ca9dc6 100644 --- a/cpp/core/src/zxing/aztec/AztecDetectorResult.h +++ b/cpp/core/src/zxing/aztec/AztecDetectorResult.h @@ -31,7 +31,11 @@ namespace zxing { bool compact_; int nbDatablocks_, nbLayers_; public: - AztecDetectorResult(Ref bits, std::vector > points, bool compact, int nbDatablocks, int nbLayers); + AztecDetectorResult(Ref bits, + ArrayRef< Ref > points, + bool compact, + int nbDatablocks, + int nbLayers); bool isCompact(); int getNBDatablocks(); int getNBLayers(); diff --git a/cpp/core/src/zxing/aztec/AztecReader.cpp b/cpp/core/src/zxing/aztec/AztecReader.cpp index 05fd79c57..96aa2d62e 100644 --- a/cpp/core/src/zxing/aztec/AztecReader.cpp +++ b/cpp/core/src/zxing/aztec/AztecReader.cpp @@ -23,42 +23,41 @@ #include #include -namespace zxing { - namespace aztec { +using zxing::Ref; +using zxing::ArrayRef; +using zxing::Result; +using zxing::aztec::AztecReader; - AztecReader::AztecReader() : decoder_() { - // nothing - }; +AztecReader::AztecReader() : decoder_() { + // nothing +}; - Ref AztecReader::decode(Ref image) { - Detector detector(image->getBlackMatrix()); +Ref AztecReader::decode(Ref image) { + Detector detector(image->getBlackMatrix()); - Ref detectorResult(detector.detect()); + Ref detectorResult(detector.detect()); - std::vector > points(detectorResult->getPoints()); + ArrayRef< Ref > points(detectorResult->getPoints()); - Ref decoderResult(decoder_.decode(detectorResult)); + Ref decoderResult(decoder_.decode(detectorResult)); - Ref result(new Result(decoderResult->getText(), - decoderResult->getRawBytes(), - points, - BarcodeFormat_AZTEC)); + Ref result(new Result(decoderResult->getText(), + decoderResult->getRawBytes(), + points, + BarcodeFormat::AZTEC)); - return result; - } - - Ref AztecReader::decode(Ref image, DecodeHints) { - //cout << "decoding with hints not supported for aztec" << "\n" << flush; - return this->decode(image); - } - - AztecReader::~AztecReader() { - // nothing - } - - Decoder& AztecReader::getDecoder() { - return decoder_; - } - - } + return result; +} + +Ref AztecReader::decode(Ref image, DecodeHints) { + //cout << "decoding with hints not supported for aztec" << "\n" << flush; + return this->decode(image); +} + +AztecReader::~AztecReader() { + // nothing +} + +zxing::aztec::Decoder& AztecReader::getDecoder() { + return decoder_; } diff --git a/cpp/core/src/zxing/aztec/decoder/Decoder.cpp b/cpp/core/src/zxing/aztec/decoder/Decoder.cpp index 0141cdb00..44ee40227 100644 --- a/cpp/core/src/zxing/aztec/decoder/Decoder.cpp +++ b/cpp/core/src/zxing/aztec/decoder/Decoder.cpp @@ -40,7 +40,7 @@ using zxing::Ref; using std::string; namespace { - void add(string& result, unsigned char character) { + void add(string& result, char character) { #ifndef NO_ICONV char s[] = { character & 0xff }; char* ss = s; @@ -163,9 +163,9 @@ Ref Decoder::decode(Ref detect Ref result = getEncodedData(aCorrectedBits); // std::printf("constructing array\n"); - ArrayRef arrayOut(aCorrectedBits->getSize()); + ArrayRef arrayOut(aCorrectedBits->getSize()); for (int i = 0; i < aCorrectedBits->count(); i++) { - arrayOut[i] = (unsigned char)aCorrectedBits->get(i); + arrayOut[i] = (char)aCorrectedBits->get(i); } // std::printf("returning\n"); @@ -376,7 +376,7 @@ Ref Decoder::correctBits(Ref rawbits) { } - flag = (unsigned int)flag >> 1; + flag = ((unsigned int)flag) >> 1; } } diff --git a/cpp/core/src/zxing/aztec/detector/Detector.cpp b/cpp/core/src/zxing/aztec/detector/Detector.cpp index 563c52916..dfca21ec3 100644 --- a/cpp/core/src/zxing/aztec/detector/Detector.cpp +++ b/cpp/core/src/zxing/aztec/detector/Detector.cpp @@ -29,10 +29,12 @@ #include #include +using std::vector; using zxing::aztec::Detector; using zxing::aztec::Point; using zxing::aztec::AztecDetectorResult; using zxing::Ref; +using zxing::ArrayRef; using zxing::ResultPoint; using zxing::BitArray; using zxing::BitMatrix; @@ -52,10 +54,15 @@ Ref Detector::detect() { std::vector > bullEyeCornerPoints = getBullEyeCornerPoints(pCenter); extractParameters(bullEyeCornerPoints); + + ArrayRef< Ref > corners = getMatrixCornerPoints(bullEyeCornerPoints); - std::vector > corners = getMatrixCornerPoints(bullEyeCornerPoints); - - Ref bits = sampleGrid(image_, corners[shift_%4], corners[(shift_+3)%4], corners[(shift_+2)%4], corners[(shift_+1)%4]); + Ref bits = + sampleGrid(image_, + corners[shift_%4], + corners[(shift_+3)%4], + corners[(shift_+2)%4], + corners[(shift_+1)%4]); // std::printf("------------\ndetected: compact:%s, nbDataBlocks:%d, nbLayers:%d\n------------\n",compact_?"YES":"NO", nbDataBlocks_, nbLayers_); @@ -127,7 +134,8 @@ void Detector::extractParameters(std::vector > bullEyeCornerPoints) { getParameters(parameterData); } -std::vector > Detector::getMatrixCornerPoints(std::vector > bullEyeCornerPoints) { +ArrayRef< Ref > +Detector::getMatrixCornerPoints(std::vector > bullEyeCornerPoints) { float ratio = (2 * nbLayers_ + (nbLayers_ > 4 ? 1 : 0) + (nbLayers_ - 4) / 8) / (2.0f * nbCenterLayers_); int dx = bullEyeCornerPoints[0]->x - bullEyeCornerPoints[2]->x; @@ -157,14 +165,13 @@ std::vector > Detector::getMatrixCornerPoints(std::vector > returnValue; + Array< Ref >* array = new Array< Ref >(); + vector< Ref >& returnValue (array->values()); returnValue.push_back(Ref(new ResultPoint(targetax, targetay))); returnValue.push_back(Ref(new ResultPoint(targetbx, targetby))); returnValue.push_back(Ref(new ResultPoint(targetcx, targetcy))); returnValue.push_back(Ref(new ResultPoint(targetdx, targetdy))); - - return returnValue; - + return ArrayRef< Ref >(array); } void Detector::correctParameterData(Ref parameterData, bool compact) { diff --git a/cpp/core/src/zxing/aztec/detector/Detector.h b/cpp/core/src/zxing/aztec/detector/Detector.h index d265446d8..34728d0ca 100644 --- a/cpp/core/src/zxing/aztec/detector/Detector.h +++ b/cpp/core/src/zxing/aztec/detector/Detector.h @@ -29,57 +29,58 @@ #include namespace zxing { - namespace aztec { - - class Point : public Counted { - public: - int x; - int y; - - Ref toResultPoint() { - return Ref(new ResultPoint(x, y)); - } - - Point(int ax, int ay):x(ax),y(ay) {}; - - }; - - class Detector : public Counted { - - private: - Ref image_; - - bool compact_; - int nbLayers_; - int nbDataBlocks_; - int nbCenterLayers_; - int shift_; - - void extractParameters(std::vector > bullEyeCornerPoints); - std::vector > getMatrixCornerPoints(std::vector > bullEyeCornerPoints); - static void correctParameterData(Ref parameterData, bool compact); - std::vector > getBullEyeCornerPoints(Ref pCenter); - Ref getMatrixCenter(); - Ref sampleGrid(Ref image, - Ref topLeft, - Ref bottomLeft, - Ref bottomRight, - Ref topRight); - void getParameters(Ref parameterData); - Ref sampleLine(Ref p1, Ref p2, int size); - bool isWhiteOrBlackRectangle(Ref p1, - Ref p2, - Ref p3, - Ref p4); - int getColor(Ref p1, Ref p2); - Ref getFirstDifferent(Ref init, bool color, int dx, int dy); - bool isValid(int x, int y); - static float distance(Ref a, Ref b); - - public: - Detector(Ref image); - Ref detect(); - }; - - } + namespace aztec { + class Point; + class Detector; + } } + +class zxing::aztec::Point : public Counted { +public: + int x; + int y; + + Ref toResultPoint() { + return Ref(new ResultPoint(x, y)); + } + + Point(int ax, int ay):x(ax),y(ay) {}; + +}; + +class zxing::aztec::Detector : public Counted { + +private: + Ref image_; + + bool compact_; + int nbLayers_; + int nbDataBlocks_; + int nbCenterLayers_; + int shift_; + + void extractParameters(std::vector > bullEyeCornerPoints); + ArrayRef< Ref > getMatrixCornerPoints(std::vector > bullEyeCornerPoints); + static void correctParameterData(Ref parameterData, bool compact); + std::vector > getBullEyeCornerPoints(Ref pCenter); + Ref getMatrixCenter(); + Ref sampleGrid(Ref image, + Ref topLeft, + Ref bottomLeft, + Ref bottomRight, + Ref topRight); + void getParameters(Ref parameterData); + Ref sampleLine(Ref p1, Ref p2, int size); + bool isWhiteOrBlackRectangle(Ref p1, + Ref p2, + Ref p3, + Ref p4); + int getColor(Ref p1, Ref p2); + Ref getFirstDifferent(Ref init, bool color, int dx, int dy); + bool isValid(int x, int y); + static float distance(Ref a, Ref b); + +public: + Detector(Ref image); + Ref detect(); +}; diff --git a/cpp/core/src/zxing/common/Array.h b/cpp/core/src/zxing/common/Array.h index 9c676b4a1..78c3c5cfa 100644 --- a/cpp/core/src/zxing/common/Array.h +++ b/cpp/core/src/zxing/common/Array.h @@ -37,13 +37,14 @@ template class Array : public Counted { protected: public: std::vector values_; - Array(size_t n) : + Array() {} + Array(int n) : Counted(), values_(n, T()) { } - Array(T *ts, size_t n) : + Array(T const* ts, int n) : Counted(), values_(ts, ts+n) { } - Array(T v, size_t n) : + Array(T v, int n) : Counted(), values_(n, v) { } Array(std::vector &v) : @@ -77,16 +78,19 @@ public: #endif return *this; } - T operator[](size_t i) const { + T operator[](int i) const { return values_[i]; } - T& operator[](size_t i) { + T& operator[](int i) { return values_[i]; } - size_t size() const { + int size() const { return values_.size(); } - std::vector values() const { + bool empty() const { + return values_.size() == 0; + } + std::vector const& values() const { return values_; } std::vector& values() { @@ -104,14 +108,14 @@ public: cout << "instantiating empty ArrayRef " << this << "\n"; #endif } - ArrayRef(size_t n) : + explicit ArrayRef(int n) : array_(0) { #ifdef DEBUG_COUNTING cout << "instantiating ArrayRef " << this << "with size " << n << "\n"; #endif reset(new Array (n)); } - ArrayRef(T *ts, size_t n) : + ArrayRef(T *ts, int n) : array_(0) { #ifdef DEBUG_COUNTING cout << "instantiating ArrayRef " << this << "with " << n << " elements at " << (void *)ts << "\n"; @@ -160,13 +164,13 @@ public: array_ = 0; } - T operator[](size_t i) const { + T operator[](int i) const { return (*array_)[i]; } - T& operator[](size_t i) { + T& operator[](int i) { return (*array_)[i]; } - size_t size() const { + int size() const { return array_->size(); } @@ -201,6 +205,12 @@ public: Array* operator->() { return array_; } + operator bool () const { + return array_ != 0; + } + bool operator ! () const { + return array_ == 0; + } }; } // namespace zxing diff --git a/cpp/core/src/zxing/common/BitArray.cpp b/cpp/core/src/zxing/common/BitArray.cpp index 410059f42..44ba7065b 100644 --- a/cpp/core/src/zxing/common/BitArray.cpp +++ b/cpp/core/src/zxing/common/BitArray.cpp @@ -17,28 +17,26 @@ #include -using namespace std; +using std::vector; +using zxing::BitArray; -namespace zxing { - - -size_t BitArray::wordsForBits(size_t bits) { +int BitArray::wordsForBits(int bits) { int arraySize = (bits + bitsPerWord_ - 1) >> logBits_; return arraySize; } -BitArray::BitArray(size_t size) : - size_(size), bits_(wordsForBits(size), (const unsigned int)0) { +BitArray::BitArray(int size) : + size_(size), bits_(wordsForBits(size), 0) { } BitArray::~BitArray() { } -size_t BitArray::getSize() { +int BitArray::getSize() const { return size_; } -void BitArray::setBulk(size_t i, unsigned int newBits) { +void BitArray::setBulk(int i, int newBits) { bits_[i >> logBits_] = newBits; } @@ -69,13 +67,13 @@ void BitArray::setRange(int start, int end) { } void BitArray::clear() { - size_t max = bits_.size(); - for (size_t i = 0; i < max; i++) { + int max = bits_.size(); + for (int i = 0; i < max; i++) { bits_[i] = 0; } } -bool BitArray::isRange(size_t start, size_t end, bool value) { +bool BitArray::isRange(int start, int end, bool value) { if (end < start) { throw IllegalArgumentException("end must be after start"); } @@ -84,17 +82,17 @@ bool BitArray::isRange(size_t start, size_t end, bool value) { } // treat the 'end' as inclusive, rather than exclusive end--; - size_t firstWord = start >> logBits_; - size_t lastWord = end >> logBits_; - for (size_t i = firstWord; i <= lastWord; i++) { - size_t firstBit = i > firstWord ? 0 : start & bitsMask_; - size_t lastBit = i < lastWord ? bitsPerWord_ - 1: end & bitsMask_; - unsigned int mask; + int firstWord = start >> logBits_; + int lastWord = end >> logBits_; + for (int i = firstWord; i <= lastWord; i++) { + int firstBit = i > firstWord ? 0 : start & bitsMask_; + int lastBit = i < lastWord ? bitsPerWord_ - 1: end & bitsMask_; + int mask; if (firstBit == 0 && lastBit == bitsPerWord_ - 1) { - mask = numeric_limits::max(); + mask = -1; } else { mask = 0; - for (size_t j = firstBit; j <= lastBit; j++) { + for (int j = firstBit; j <= lastBit; j++) { mask |= 1 << j; } } @@ -111,17 +109,75 @@ bool BitArray::isRange(size_t start, size_t end, bool value) { return true; } -vector& BitArray::getBitArray() { +vector& BitArray::getBitArray() { return bits_; } void BitArray::reverse() { - std::vector newBits(bits_.size(),(const unsigned int) 0); - for (size_t i = 0; i < size_; i++) { + // std::cerr << "reverse" << std::endl; + std::vector newBits(bits_.size(), 0); + for (int i = 0; i < size_; i++) { if (get(size_ - i - 1)) { newBits[i >> logBits_] |= 1<< (i & bitsMask_); } } bits_ = newBits; } + +BitArray::Reverse::Reverse(Ref array_) : array(array_) { + array->reverse(); +} + +BitArray::Reverse::~Reverse() { + array->reverse(); +} + +namespace { + int numberOfTrailingZeros(int i) { + // HD, Figure 5-14 + int y; + if (i == 0) return 32; + int n = 31; + y = i <<16; if (y != 0) { n = n -16; i = y; } + y = i << 8; if (y != 0) { n = n - 8; i = y; } + y = i << 4; if (y != 0) { n = n - 4; i = y; } + y = i << 2; if (y != 0) { n = n - 2; i = y; } + return n - (((unsigned int)(i << 1)) >> 31); + } +} + +int BitArray::getNextSet(int from) { + if (from >= size_) { + return size_; + } + int bitsOffset = from >> 5; + int currentBits = bits_[bitsOffset]; + // mask off lesser bits first + currentBits &= ~((1 << (from & 0x1F)) - 1); + while (currentBits == 0) { + if (++bitsOffset == (int)bits_.size()) { + return size_; + } + currentBits = bits_[bitsOffset]; + } + int result = (bitsOffset << 5) + numberOfTrailingZeros(currentBits); + return result > size_ ? size_ : result; +} + +int BitArray::getNextUnset(int from) { + if (from >= size_) { + return size_; + } + int bitsOffset = from >> 5; + int currentBits = ~bits_[bitsOffset]; + // mask off lesser bits first + currentBits &= ~((1 << (from & 0x1F)) - 1); + while (currentBits == 0) { + if (++bitsOffset == (int)bits_.size()) { + return size_; + } + currentBits = ~bits_[bitsOffset]; + } + int result = (bitsOffset << 5) + numberOfTrailingZeros(currentBits); + return result > size_ ? size_ : result; } diff --git a/cpp/core/src/zxing/common/BitArray.h b/cpp/core/src/zxing/common/BitArray.h index b2b422928..36acc7a93 100644 --- a/cpp/core/src/zxing/common/BitArray.h +++ b/cpp/core/src/zxing/common/BitArray.h @@ -22,8 +22,12 @@ #include #include #include +#include namespace zxing { + class BitArray; + std::ostream& operator << (std::ostream&, BitArray const&); +} #define ZX_LOG_DIGITS(digits) \ ((digits == 8) ? 3 : \ @@ -33,38 +37,49 @@ namespace zxing { ((digits == 128) ? 7 : \ (-1)))))) -class BitArray : public Counted { +class zxing::BitArray : public Counted { private: - size_t size_; - std::vector bits_; - static const unsigned int bitsPerWord_ = + int size_; + std::vector bits_; + static const int bitsPerWord_ = std::numeric_limits::digits; - static const unsigned int logBits_ = ZX_LOG_DIGITS(bitsPerWord_); - static const unsigned int bitsMask_ = (1 << logBits_) - 1; - static size_t wordsForBits(size_t bits); + static const int logBits_ = ZX_LOG_DIGITS(bitsPerWord_); + static const int bitsMask_ = (1 << logBits_) - 1; + static int wordsForBits(int bits); explicit BitArray(); public: - BitArray(size_t size); + BitArray(int size); ~BitArray(); - size_t getSize(); + int getSize() const; - bool get(size_t i) { + bool get(int i) const { return (bits_[i >> logBits_] & (1 << (i & bitsMask_))) != 0; } - void set(size_t i) { + void set(int i) { bits_[i >> logBits_] |= 1 << (i & bitsMask_); } - void setBulk(size_t i, unsigned int newBits); + int getNextSet(int from); + int getNextUnset(int from); + + void setBulk(int i, int newBits); void setRange(int start, int end); void clear(); - bool isRange(size_t start, size_t end, bool value); - std::vector& getBitArray(); + bool isRange(int start, int end, bool value); + std::vector& getBitArray(); + void reverse(); + class Reverse; }; -} +class zxing::BitArray::Reverse { +private: + Ref array; +public: + Reverse(Ref array); + ~Reverse(); +}; #endif // __BIT_ARRAY_H__ diff --git a/cpp/core/src/zxing/common/BitArrayIO.cpp b/cpp/core/src/zxing/common/BitArrayIO.cpp new file mode 100644 index 000000000..35d2bca67 --- /dev/null +++ b/cpp/core/src/zxing/common/BitArrayIO.cpp @@ -0,0 +1,31 @@ +// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*- +/* + * 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 + +using zxing::BitArray; +using std::ostream; + +ostream& zxing::operator << (ostream& os, BitArray const& ba) { + for (int i = 0, size = ba.getSize(); i < size; i++) { + if ((i & 0x07) == 0) { + os << ' '; + } + os << (ba.get(i) ? 'X' : '.'); + } + return os; +} diff --git a/cpp/core/src/zxing/common/BitMatrix.cpp b/cpp/core/src/zxing/common/BitMatrix.cpp index eac68731d..581e0c542 100644 --- a/cpp/core/src/zxing/common/BitMatrix.cpp +++ b/cpp/core/src/zxing/common/BitMatrix.cpp @@ -27,63 +27,62 @@ using std::ostringstream; using zxing::BitMatrix; using zxing::BitArray; +using zxing::ArrayRef; using zxing::Ref; namespace { - size_t wordsForSize(size_t width, - size_t height, - unsigned int bitsPerWord, - unsigned int logBits) { - size_t bits = width * height; + int wordsForSize(int width, + int height, + int bitsPerWord, + int logBits) { + int bits = width * height; int arraySize = (bits + bitsPerWord - 1) >> logBits; return arraySize; } } -BitMatrix::BitMatrix(size_t dimension) : - width_(dimension), height_(dimension), words_(0), bits_(NULL) { +BitMatrix::BitMatrix(int dimension) : + width_(dimension), height_(dimension), words_(0) { words_ = wordsForSize(width_, height_, bitsPerWord, logBits); - bits_ = new unsigned int[words_]; + bits_ = ArrayRef(words_); clear(); } -BitMatrix::BitMatrix(size_t width, size_t height) : - width_(width), height_(height), words_(0), bits_(NULL) { +BitMatrix::BitMatrix(int width, int height) : + width_(width), height_(height), words_(0) { words_ = wordsForSize(width_, height_, bitsPerWord, logBits); - bits_ = new unsigned int[words_]; + bits_ = ArrayRef(words_); clear(); } -BitMatrix::~BitMatrix() { - delete[] bits_; -} +BitMatrix::~BitMatrix() {} -void BitMatrix::flip(size_t x, size_t y) { - size_t offset = x + width_ * y; +void BitMatrix::flip(int x, int y) { + int offset = x + width_ * y; bits_[offset >> logBits] ^= 1 << (offset & bitsMask); } void BitMatrix::clear() { - std::fill(bits_, bits_+words_, 0); + std::fill(&bits_[0], &bits_[words_], 0); } -void BitMatrix::setRegion(size_t left, size_t top, size_t width, size_t height) { +void BitMatrix::setRegion(int left, int top, int width, int height) { if ((long)top < 0 || (long)left < 0) { throw IllegalArgumentException("topI and leftJ must be nonnegative"); } if (height < 1 || width < 1) { throw IllegalArgumentException("height and width must be at least 1"); } - size_t right = left + width; - size_t bottom = top + height; + int right = left + width; + int bottom = top + height; if (right > width_ || bottom > height_) { throw IllegalArgumentException("top + height and left + width must be <= matrix dimension"); } - for (size_t y = top; y < bottom; y++) { + for (int y = top; y < bottom; y++) { int yOffset = width_ * y; - for (size_t x = left; x < right; x++) { - size_t offset = x + yOffset; + for (int x = left; x < right; x++) { + int offset = x + yOffset; bits_[offset >> logBits] |= 1 << (offset & bitsMask); } } @@ -95,26 +94,26 @@ Ref BitMatrix::getRow(int y, Ref row) { } else { row->clear(); } - size_t start = y * width_; - size_t end = start + width_ - 1; // end is inclusive - size_t firstWord = start >> logBits; - size_t lastWord = end >> logBits; - size_t bitOffset = start & bitsMask; - for (size_t i = firstWord; i <= lastWord; i++) { - size_t firstBit = i > firstWord ? 0 : start & bitsMask; - size_t lastBit = i < lastWord ? bitsPerWord - 1 : end & bitsMask; - unsigned int mask; + int start = y * width_; + int end = start + width_ - 1; // end is inclusive + int firstWord = start >> logBits; + int lastWord = end >> logBits; + int bitOffset = start & bitsMask; + for (int i = firstWord; i <= lastWord; i++) { + int firstBit = i > firstWord ? 0 : start & bitsMask; + int lastBit = i < lastWord ? bitsPerWord - 1 : end & bitsMask; + int mask; if (firstBit == 0 && lastBit == logBits) { - mask = std::numeric_limits::max(); + mask = std::numeric_limits::max(); } else { mask = 0; - for (size_t j = firstBit; j <= lastBit; j++) { + for (int j = firstBit; j <= lastBit; j++) { mask |= 1 << j; } } row->setBulk((i - firstWord) << logBits, (bits_[i] & mask) >> bitOffset); if (firstBit == 0 && bitOffset != 0) { - unsigned int prevBulk = row->getBitArray()[i - firstWord - 1]; + int prevBulk = row->getBitArray()[i - firstWord - 1]; prevBulk |= (bits_[i] & mask) << (bitsPerWord - bitOffset); row->setBulk((i - firstWord - 1) << logBits, prevBulk); } @@ -122,26 +121,26 @@ Ref BitMatrix::getRow(int y, Ref row) { return row; } -size_t BitMatrix::getWidth() const { +int BitMatrix::getWidth() const { return width_; } -size_t BitMatrix::getHeight() const { +int BitMatrix::getHeight() const { return height_; } -size_t BitMatrix::getDimension() const { +int BitMatrix::getDimension() const { return width_; } -unsigned int* BitMatrix::getBits() const { +ArrayRef BitMatrix::getBits() const { return bits_; } namespace zxing { 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++) { + for (int y = 0; y < bm.height_; y++) { + for (int x = 0; x < bm.width_; x++) { out << (bm.get(x, y) ? "X " : " "); } out << "\n"; diff --git a/cpp/core/src/zxing/common/BitMatrix.h b/cpp/core/src/zxing/common/BitMatrix.h index 2a78a5aad..18e7a6eb5 100644 --- a/cpp/core/src/zxing/common/BitMatrix.h +++ b/cpp/core/src/zxing/common/BitMatrix.h @@ -23,16 +23,19 @@ #include #include +#include #include namespace zxing { + class BitMatrix; +} -class BitMatrix : public Counted { +class zxing::BitMatrix : public Counted { private: - size_t width_; - size_t height_; - size_t words_; - unsigned int* bits_; + int width_; + int height_; + int words_; + ArrayRef bits_; #define ZX_LOG_DIGITS(digits) \ ((digits == 8) ? 3 : \ @@ -42,37 +45,37 @@ private: ((digits == 128) ? 7 : \ (-1)))))) - static const unsigned int bitsPerWord = + static const int bitsPerWord = std::numeric_limits::digits; - static const unsigned int logBits = ZX_LOG_DIGITS(bitsPerWord); - static const unsigned int bitsMask = (1 << logBits) - 1; + static const int logBits = ZX_LOG_DIGITS(bitsPerWord); + static const int bitsMask = (1 << logBits) - 1; public: - BitMatrix(size_t dimension); - BitMatrix(size_t width, size_t height); + BitMatrix(int dimension); + BitMatrix(int width, int height); ~BitMatrix(); - bool get(size_t x, size_t y) const { - size_t offset = x + width_ * y; + bool get(int x, int y) const { + int offset = x + width_ * y; return ((bits_[offset >> logBits] >> (offset & bitsMask)) & 0x01) != 0; } - void set(size_t x, size_t y) { - size_t offset = x + width_ * y; + void set(int x, int y) { + int offset = x + width_ * y; bits_[offset >> logBits] |= 1 << (offset & bitsMask); } - void flip(size_t x, size_t y); + void flip(int x, int y); void clear(); - void setRegion(size_t left, size_t top, size_t width, size_t height); + void setRegion(int left, int top, int width, int height); Ref getRow(int y, Ref row); - size_t getDimension() const; - size_t getWidth() const; - size_t getHeight() const; + int getDimension() const; + int getWidth() const; + int getHeight() const; - unsigned int* getBits() const; + ArrayRef getBits() const; friend std::ostream& operator<<(std::ostream &out, const BitMatrix &bm); const char *description(); @@ -82,6 +85,4 @@ private: BitMatrix& operator =(const BitMatrix&); }; -} - #endif // __BIT_MATRIX_H__ diff --git a/cpp/core/src/zxing/common/BitSource.h b/cpp/core/src/zxing/common/BitSource.h index 9404d107e..3ab16a062 100644 --- a/cpp/core/src/zxing/common/BitSource.h +++ b/cpp/core/src/zxing/common/BitSource.h @@ -33,7 +33,7 @@ namespace zxing { * @author christian.brunschen@gmail.com (Christian Brunschen) */ class BitSource : public Counted { - typedef unsigned char byte; + typedef char byte; private: ArrayRef bytes_; int byteOffset_; diff --git a/cpp/core/src/zxing/common/Counted.h b/cpp/core/src/zxing/common/Counted.h index ccfcf509c..2f751a9f3 100644 --- a/cpp/core/src/zxing/common/Counted.h +++ b/cpp/core/src/zxing/common/Counted.h @@ -97,6 +97,7 @@ public: reset(o); } +/* explicit Ref(const T &o) : object_(0) { #ifdef DEBUG_COUNTING @@ -104,6 +105,7 @@ public: #endif reset(const_cast(&o)); } +*/ Ref(const Ref &other) : object_(0) { diff --git a/cpp/core/src/zxing/common/DecoderResult.cpp b/cpp/core/src/zxing/common/DecoderResult.cpp index af7e5e2e3..923f9e5bd 100644 --- a/cpp/core/src/zxing/common/DecoderResult.cpp +++ b/cpp/core/src/zxing/common/DecoderResult.cpp @@ -24,20 +24,20 @@ using namespace std; using namespace zxing; -DecoderResult::DecoderResult(ArrayRef rawBytes, +DecoderResult::DecoderResult(ArrayRef rawBytes, Ref text, - ArrayRef< ArrayRef >& byteSegments, + ArrayRef< ArrayRef >& byteSegments, string const& ecLevel) : rawBytes_(rawBytes), text_(text), byteSegments_(byteSegments), ecLevel_(ecLevel) {} -DecoderResult::DecoderResult(ArrayRef rawBytes, +DecoderResult::DecoderResult(ArrayRef rawBytes, Ref text) : rawBytes_(rawBytes), text_(text) {} -ArrayRef DecoderResult::getRawBytes() { +ArrayRef DecoderResult::getRawBytes() { return rawBytes_; } diff --git a/cpp/core/src/zxing/common/DecoderResult.h b/cpp/core/src/zxing/common/DecoderResult.h index d26caa3aa..9a1f7fa80 100644 --- a/cpp/core/src/zxing/common/DecoderResult.h +++ b/cpp/core/src/zxing/common/DecoderResult.h @@ -29,20 +29,20 @@ namespace zxing { class DecoderResult : public Counted { private: - ArrayRef rawBytes_; + ArrayRef rawBytes_; Ref text_; - ArrayRef< ArrayRef > byteSegments_; + ArrayRef< ArrayRef > byteSegments_; std::string ecLevel_; public: - DecoderResult(ArrayRef rawBytes, + DecoderResult(ArrayRef rawBytes, Ref text, - ArrayRef< ArrayRef >& byteSegments, + ArrayRef< ArrayRef >& byteSegments, std::string const& ecLevel); - DecoderResult(ArrayRef rawBytes, Ref text); + DecoderResult(ArrayRef rawBytes, Ref text); - ArrayRef getRawBytes(); + ArrayRef getRawBytes(); Ref getText(); }; diff --git a/cpp/core/src/zxing/common/DetectorResult.cpp b/cpp/core/src/zxing/common/DetectorResult.cpp index c13898346..323ffb3c8 100644 --- a/cpp/core/src/zxing/common/DetectorResult.cpp +++ b/cpp/core/src/zxing/common/DetectorResult.cpp @@ -23,15 +23,16 @@ namespace zxing { -DetectorResult::DetectorResult(Ref bits, std::vector > points) : - bits_(bits), points_(points) { +DetectorResult::DetectorResult(Ref bits, + ArrayRef< Ref > points) + : bits_(bits), points_(points) { } Ref DetectorResult::getBits() { return bits_; } -std::vector > DetectorResult::getPoints() { +ArrayRef< Ref > DetectorResult::getPoints() { return points_; } diff --git a/cpp/core/src/zxing/common/DetectorResult.h b/cpp/core/src/zxing/common/DetectorResult.h index ebf5910cc..2b0a7ee95 100644 --- a/cpp/core/src/zxing/common/DetectorResult.h +++ b/cpp/core/src/zxing/common/DetectorResult.h @@ -20,24 +20,24 @@ * limitations under the License. */ -#include #include #include #include #include namespace zxing { - -class DetectorResult : public Counted { -private: - Ref bits_; - std::vector > points_; - -public: - DetectorResult(Ref bits, std::vector > points); - Ref getBits(); - std::vector > getPoints(); -}; + class DetectorResult; } +class zxing::DetectorResult : public Counted { +private: + Ref bits_; + ArrayRef< Ref > points_; + +public: + DetectorResult(Ref bits, ArrayRef< Ref > points); + Ref getBits(); + ArrayRef< Ref > getPoints(); +}; + #endif // __DETECTOR_RESULT_H__ diff --git a/cpp/core/src/zxing/common/GlobalHistogramBinarizer.cpp b/cpp/core/src/zxing/common/GlobalHistogramBinarizer.cpp index ac5460f5d..f633f1ab2 100644 --- a/cpp/core/src/zxing/common/GlobalHistogramBinarizer.cpp +++ b/cpp/core/src/zxing/common/GlobalHistogramBinarizer.cpp @@ -19,35 +19,39 @@ */ #include -#include +#include #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), cached_matrix_(NULL), cached_row_(NULL), cached_row_num_(-1) { +using zxing::GlobalHistogramBinarizer; +using zxing::Binarizer; +using zxing::ArrayRef; +using zxing::Ref; +using zxing::BitArray; +using zxing::BitMatrix; +namespace { + const int LUMINANCE_BITS = 5; + const int LUMINANCE_SHIFT = 8 - LUMINANCE_BITS; + const int LUMINANCE_BUCKETS = 1 << LUMINANCE_BITS; + const ArrayRef EMPTY (0); } -GlobalHistogramBinarizer::~GlobalHistogramBinarizer() { -} +GlobalHistogramBinarizer::GlobalHistogramBinarizer(Ref source) + : Binarizer(source), luminances(EMPTY), buckets(LUMINANCE_BUCKETS) {} +GlobalHistogramBinarizer::~GlobalHistogramBinarizer() {} + +void GlobalHistogramBinarizer::initArrays(int luminanceSize) { + if (luminances.size() < luminanceSize) { + luminances = ArrayRef(luminanceSize); + } + for (int x = 0; x < LUMINANCE_BUCKETS; x++) { + buckets[x] = 0; + } +} Ref GlobalHistogramBinarizer::getBlackRow(int y, Ref row) { - if (y == cached_row_num_) { - if (cached_row_ != NULL) { - return cached_row_; - } else { - throw IllegalArgumentException("Too little dynamic range in luminance"); - } - } - - vector histogram(LUMINANCE_BUCKETS, 0); + // std::cerr << "gbr " << y << std::endl; LuminanceSource& source = *getLuminanceSource(); int width = source.getWidth(); if (row == NULL || static_cast(row->getSize()) < width) { @@ -56,99 +60,96 @@ Ref GlobalHistogramBinarizer::getBlackRow(int y, Ref row) { row->clear(); } - //TODO(flyashi): cache this instead of allocating and deleting per row - unsigned char* row_pixels = NULL; - try { - row_pixels = new unsigned char[width]; - row_pixels = source.getRow(y, row_pixels); - for (int x = 0; x < width; x++) { - histogram[row_pixels[x] >> LUMINANCE_SHIFT]++; + initArrays(width); + ArrayRef localLuminances = source.getRow(y, luminances); + if (false) { + std::cerr << "gbr " << y << " r "; + for(int i=0, e=localLuminances->size(); i < e; ++i) { + std::cerr << 0+localLuminances[i] << " "; } - int blackPoint = estimate(histogram); - - BitArray& array = *row; - int left = row_pixels[0]; - int center = row_pixels[1]; - for (int x = 1; x < width - 1; x++) { - int right = row_pixels[x + 1]; - // A simple -1 4 -1 box filter with a weight of 2. - int luminance = ((center << 2) - left - right) >> 1; - if (luminance < blackPoint) { - array.set(x); - } - left = center; - center = right; - } - - cached_row_ = row; - cached_row_num_ = y; - delete [] row_pixels; - return row; - } catch (IllegalArgumentException const& iae) { - // Cache the fact that this row failed. - cached_row_ = NULL; - cached_row_num_ = y; - delete [] row_pixels; - throw iae; + std::cerr << std::endl; } + ArrayRef localBuckets = buckets; + for (int x = 0; x < width; x++) { + int pixel = localLuminances[x] & 0xff; + localBuckets[pixel >> LUMINANCE_SHIFT]++; + } + int blackPoint = estimateBlackPoint(localBuckets); + // std::cerr << "gbr bp " << y << " " << blackPoint << std::endl; + + int left = localLuminances[0] & 0xff; + int center = localLuminances[1] & 0xff; + for (int x = 1; x < width - 1; x++) { + int right = localLuminances[x + 1] & 0xff; + // A simple -1 4 -1 box filter with a weight of 2. + int luminance = ((center << 2) - left - right) >> 1; + if (luminance < blackPoint) { + row->set(x); + } + left = center; + center = right; + } + return row; } - + Ref GlobalHistogramBinarizer::getBlackMatrix() { - if (cached_matrix_ != NULL) { - return cached_matrix_; - } - - // Faster than working with the reference LuminanceSource& source = *getLuminanceSource(); int width = source.getWidth(); int height = source.getHeight(); - vector histogram(LUMINANCE_BUCKETS, 0); + Ref matrix(new BitMatrix(width, height)); // 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. - ArrayRef ref (width); - unsigned char* row = &ref[0]; + initArrays(width); + ArrayRef localBuckets = buckets; for (int y = 1; y < 5; y++) { - int rownum = height * y / 5; + int row = height * y / 5; + ArrayRef localLuminances = source.getRow(row, luminances); int right = (width << 2) / 5; - row = source.getRow(rownum, row); for (int x = width / 5; x < right; x++) { - histogram[row[x] >> LUMINANCE_SHIFT]++; + int pixel = localLuminances[x] & 0xff; + localBuckets[pixel >> LUMINANCE_SHIFT]++; } } - int blackPoint = estimate(histogram); + int blackPoint = estimateBlackPoint(localBuckets); - Ref matrix_ref(new BitMatrix(width, height)); - BitMatrix& matrix = *matrix_ref; + ArrayRef localLuminances = source.getMatrix(); for (int y = 0; y < height; y++) { - row = source.getRow(y, row); + int offset = y * width; for (int x = 0; x < width; x++) { - if (row[x] < blackPoint) - matrix.set(x, y); + int pixel = localLuminances[offset + x] & 0xff; + if (pixel < blackPoint) { + matrix->set(x, y); + } } } - - cached_matrix_ = matrix_ref; - // delete [] row; - return matrix_ref; + + return matrix; } -int GlobalHistogramBinarizer::estimate(vector &histogram) { - int numBuckets = histogram.size(); - int maxBucketCount = 0; +using namespace std; +int GlobalHistogramBinarizer::estimateBlackPoint(ArrayRef const& buckets) { // Find tallest peak in histogram + int numBuckets = buckets.size(); + int maxBucketCount = 0; int firstPeak = 0; int firstPeakSize = 0; - for (int i = 0; i < numBuckets; i++) { - if (histogram[i] > firstPeakSize) { - firstPeak = i; - firstPeakSize = histogram[i]; + if (false) { + for (int x = 0; x < numBuckets; x++) { + cerr << buckets[x] << " "; } - if (histogram[i] > maxBucketCount) { - maxBucketCount = histogram[i]; + cerr << endl; + } + for (int x = 0; x < numBuckets; x++) { + if (buckets[x] > firstPeakSize) { + firstPeak = x; + firstPeakSize = buckets[x]; + } + if (buckets[x] > maxBucketCount) { + maxBucketCount = buckets[x]; } } @@ -156,17 +157,16 @@ int GlobalHistogramBinarizer::estimate(vector &histogram) { // so close to the first one int secondPeak = 0; int secondPeakScore = 0; - for (int i = 0; i < numBuckets; i++) { - int distanceToBiggest = i - firstPeak; + for (int x = 0; x < numBuckets; x++) { + int distanceToBiggest = x - firstPeak; // Encourage more distant second peaks by multiplying by square of distance - int score = histogram[i] * distanceToBiggest * distanceToBiggest; + int score = buckets[x] * distanceToBiggest * distanceToBiggest; if (score > secondPeakScore) { - secondPeak = i; + secondPeak = x; secondPeakScore = score; } } - // Put firstPeak first if (firstPeak > secondPeak) { int temp = firstPeak; firstPeak = secondPeak; @@ -180,30 +180,30 @@ int GlobalHistogramBinarizer::estimate(vector &histogram) { // a false positive for 1D formats, which are relatively lenient. // We arbitrarily say "close" is // "<= 1/16 of the total histogram buckets apart" + // std::cerr << "! " << secondPeak << " " << firstPeak << " " << numBuckets << std::endl; if (secondPeak - firstPeak <= numBuckets >> 4) { - throw IllegalArgumentException("Too little dynamic range in luminance"); + throw NotFoundException(); } // 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; + for (int x = secondPeak - 1; x > firstPeak; x--) { + int fromFirst = x - 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]); + int score = fromFirst * fromFirst * (secondPeak - x) * + (maxBucketCount - buckets[x]); if (score > bestValleyScore) { - bestValley = i; + bestValley = x; bestValleyScore = score; } } + // std::cerr << "bps " << (bestValley << LUMINANCE_SHIFT) << std::endl; return bestValley << LUMINANCE_SHIFT; } Ref GlobalHistogramBinarizer::createBinarizer(Ref source) { return Ref (new GlobalHistogramBinarizer(source)); } - -} // namespace zxing diff --git a/cpp/core/src/zxing/common/GlobalHistogramBinarizer.h b/cpp/core/src/zxing/common/GlobalHistogramBinarizer.h index 72b59296b..57813a785 100644 --- a/cpp/core/src/zxing/common/GlobalHistogramBinarizer.h +++ b/cpp/core/src/zxing/common/GlobalHistogramBinarizer.h @@ -1,3 +1,4 @@ +// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*- #ifndef __GLOBALHISTOGRAMBINARIZER_H__ #define __GLOBALHISTOGRAMBINARIZER_H__ /* @@ -19,29 +20,29 @@ * limitations under the License. */ -#include #include #include #include +#include namespace zxing { - - class GlobalHistogramBinarizer : public Binarizer { - private: - Ref cached_matrix_; - Ref cached_row_; - int cached_row_num_; - - public: - GlobalHistogramBinarizer(Ref source); - virtual ~GlobalHistogramBinarizer(); - - virtual Ref getBlackRow(int y, Ref row); - virtual Ref getBlackMatrix(); - static int estimate(std::vector &histogram); - Ref createBinarizer(Ref source); - }; - + class GlobalHistogramBinarizer; } - + +class zxing::GlobalHistogramBinarizer : public Binarizer { +private: + ArrayRef luminances; + ArrayRef buckets; +public: + GlobalHistogramBinarizer(Ref source); + virtual ~GlobalHistogramBinarizer(); + + virtual Ref getBlackRow(int y, Ref row); + virtual Ref getBlackMatrix(); + static int estimateBlackPoint(ArrayRef const& buckets); + Ref createBinarizer(Ref source); +private: + void initArrays(int luminanceSize); +}; + #endif /* GLOBALHISTOGRAMBINARIZER_H_ */ diff --git a/cpp/core/src/zxing/common/GreyscaleLuminanceSource.cpp b/cpp/core/src/zxing/common/GreyscaleLuminanceSource.cpp index b6c917f5c..b5beb8010 100644 --- a/cpp/core/src/zxing/common/GreyscaleLuminanceSource.cpp +++ b/cpp/core/src/zxing/common/GreyscaleLuminanceSource.cpp @@ -1,3 +1,4 @@ +// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*- /* * GreyscaleLuminanceSource.cpp * zxing @@ -21,50 +22,90 @@ #include #include -namespace zxing { - -GreyscaleLuminanceSource::GreyscaleLuminanceSource(unsigned char* greyData, int dataWidth, - int dataHeight, int left, int top, int width, int height) : greyData_(greyData), - dataWidth_(dataWidth), dataHeight_(dataHeight), left_(left), top_(top), width_(width), - height_(height) { +using zxing::Ref; +using zxing::ArrayRef; +using zxing::LuminanceSource; +using zxing::GreyscaleLuminanceSource; +GreyscaleLuminanceSource:: +GreyscaleLuminanceSource(ArrayRef greyData, + int dataWidth, int dataHeight, + int left, int top, + int width, int height) + : greyData_(greyData), + dataWidth_(dataWidth), dataHeight_(dataHeight), + left_(left), top_(top), + width_(width), height_(height) { + if (left + width > dataWidth || top + height > dataHeight || top < 0 || left < 0) { throw IllegalArgumentException("Crop rectangle does not fit within image data."); } } -unsigned char* GreyscaleLuminanceSource::getRow(int y, unsigned char* row) { +ArrayRef GreyscaleLuminanceSource::getRow(int y, ArrayRef row) { if (y < 0 || y >= this->getHeight()) { throw IllegalArgumentException("Requested row is outside the image."); } int width = getWidth(); - // TODO(flyashi): determine if row has enough size. - if (row == NULL) { - row = new unsigned char[width_]; + if (!row || row.size() < width) { + ArrayRef temp (width); + row = temp; } int offset = (y + top_) * dataWidth_ + left_; - memcpy(row, &greyData_[offset], width); + memcpy(&row[0], &greyData_[offset], width); return row; } -unsigned char* GreyscaleLuminanceSource::getMatrix() { +ArrayRef GreyscaleLuminanceSource::getMatrix() { int size = width_ * height_; - unsigned char* result = new unsigned char[size]; + ArrayRef result (size); if (left_ == 0 && top_ == 0 && dataWidth_ == width_ && dataHeight_ == height_) { - memcpy(result, greyData_, size); + memcpy(&result[0], &greyData_[0], size); } else { for (int row = 0; row < height_; row++) { - memcpy(result + row * width_, greyData_ + (top_ + row) * dataWidth_ + left_, width_); + memcpy(&result[row * width_], &greyData_[(top_ + row) * dataWidth_ + left_], width_); } } return result; } -Ref GreyscaleLuminanceSource::rotateCounterClockwise() { - // Intentionally flip the left, top, width, and height arguments as needed. dataWidth and - // dataHeight are always kept unrotated. - return Ref (new GreyscaleRotatedLuminanceSource(greyData_, dataWidth_, - dataHeight_, top_, left_, height_, width_)); -} + extern "C" void abort(); -} /* namespace */ +Ref GreyscaleLuminanceSource::rotateCounterClockwise() { + // Intentionally flip the left, top, width, and height arguments as + // needed. dataWidth and dataHeight are always kept unrotated. + Ref result ( + new GreyscaleRotatedLuminanceSource(greyData_, + dataWidth_, dataHeight_, + top_, left_, height_, width_) + ); + + /* + // testing code ... remove when we trust everything. + // NB: very slow, so don't forget and leave on. + for(int r = top_; r < top_+height_; ++r) { + for(int c = left_; c < left_+width_; ++c) { + int rot_r = r; + int rot_c = c; + // transpose + int tmp = rot_r; + rot_r = rot_c; + rot_c = tmp; + // flip vert + rot_r = width_-rot_r-1; + if (getRow(r, ArrayRef())[c] != + result->getRow(rot_r, ArrayRef())[rot_c]) { + using namespace std; + cerr << r << "," << c << " " + << rot_r << "," << rot_c << " " + << (0+getRow(r, ArrayRef())[c]) << " " + << (0+result->getRow(rot_r, ArrayRef())[rot_c]) << " " + << endl; + abort(); + } + } + } + */ + + return result; +} diff --git a/cpp/core/src/zxing/common/GreyscaleLuminanceSource.h b/cpp/core/src/zxing/common/GreyscaleLuminanceSource.h index 4729191f3..4b78b01fe 100644 --- a/cpp/core/src/zxing/common/GreyscaleLuminanceSource.h +++ b/cpp/core/src/zxing/common/GreyscaleLuminanceSource.h @@ -1,3 +1,4 @@ +// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*- #ifndef __GREYSCALE_LUMINANCE_SOURCE__ #define __GREYSCALE_LUMINANCE_SOURCE__ /* @@ -22,11 +23,13 @@ #include namespace zxing { + class GreyscaleLuminanceSource; +} -class GreyscaleLuminanceSource : public LuminanceSource { +class zxing::GreyscaleLuminanceSource : public LuminanceSource { - private: - unsigned char* greyData_; +private: + ArrayRef greyData_; int dataWidth_; int dataHeight_; int left_; @@ -34,12 +37,12 @@ class GreyscaleLuminanceSource : public LuminanceSource { int width_; int height_; - public: - GreyscaleLuminanceSource(unsigned char* greyData, int dataWidth, int dataHeight, int left, - int top, int width, int height); +public: + GreyscaleLuminanceSource(ArrayRef greyData, int dataWidth, int dataHeight, int left, + int top, int width, int height); - unsigned char* getRow(int y, unsigned char* row); - unsigned char* getMatrix(); + ArrayRef getRow(int y, ArrayRef row); + ArrayRef getMatrix(); bool isRotateSupported() const { return true; @@ -57,6 +60,4 @@ class GreyscaleLuminanceSource : public LuminanceSource { }; -} /* namespace */ - #endif diff --git a/cpp/core/src/zxing/common/GreyscaleRotatedLuminanceSource.cpp b/cpp/core/src/zxing/common/GreyscaleRotatedLuminanceSource.cpp index 52c99144f..dd7153fa9 100644 --- a/cpp/core/src/zxing/common/GreyscaleRotatedLuminanceSource.cpp +++ b/cpp/core/src/zxing/common/GreyscaleRotatedLuminanceSource.cpp @@ -1,3 +1,4 @@ +// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*- /* * GreyscaleRotatedLuminanceSource.cpp * zxing @@ -21,15 +22,21 @@ #include #include -namespace zxing { +using zxing::ArrayRef; +using zxing::GreyscaleRotatedLuminanceSource; -// Note that dataWidth and dataHeight are not reversed, as we need to be able to traverse the -// greyData correctly, which does not get rotated. -GreyscaleRotatedLuminanceSource::GreyscaleRotatedLuminanceSource(unsigned char* greyData, - int dataWidth, int dataHeight, int left, int top, int width, int height) : greyData_(greyData), - dataWidth_(dataWidth), left_(left), top_(top), width_(width), +// Note that dataWidth and dataHeight are not reversed, as we need to +// be able to traverse the greyData correctly, which does not get +// rotated. +GreyscaleRotatedLuminanceSource:: +GreyscaleRotatedLuminanceSource(ArrayRef greyData, + int dataWidth, int /* dataHeight */, + int left, int top, + int width, int height) + : greyData_(greyData), + dataWidth_(dataWidth), + left_(left), top_(top), width_(width), height_(height) { - // Intentionally comparing to the opposite dimension since we're rotated. if (left + width > dataHeight || top + height > dataWidth) { throw IllegalArgumentException("Crop rectangle does not fit within image data."); @@ -37,29 +44,38 @@ GreyscaleRotatedLuminanceSource::GreyscaleRotatedLuminanceSource(unsigned char* } // The API asks for rows, but we're rotated, so we return columns. -unsigned char* GreyscaleRotatedLuminanceSource::getRow(int y, unsigned char* row) { +ArrayRef +GreyscaleRotatedLuminanceSource::getRow(int y, ArrayRef row) { if (y < 0 || y >= getHeight()) { throw IllegalArgumentException("Requested row is outside the image."); } - int width = getWidth(); - if (row == NULL) { - row = new unsigned char[width]; + if (!row || row.size() < width_) { + row = ArrayRef(width_); } int offset = (left_ * dataWidth_) + (dataWidth_ - 1 - (y + top_)); - for (int x = 0; x < width; x++) { + using namespace std; + if (false) { + cerr << offset << " = " + << top_ << " " << left_ << " " + << height_ << " " << width_ << " " + << y << endl; + } + for (int x = 0; x < width_; x++) { row[x] = greyData_[offset]; offset += dataWidth_; } return row; } -unsigned char* GreyscaleRotatedLuminanceSource::getMatrix() { - unsigned char* result = new unsigned char[width_ * height_]; - // This depends on getRow() honoring its second parameter. +ArrayRef GreyscaleRotatedLuminanceSource::getMatrix() { + ArrayRef result (width_ * height_); for (int y = 0; y < height_; y++) { - getRow(y, &result[y * width_]); + char* row = &result[y * width_]; + int offset = (left_ * dataWidth_) + (dataWidth_ - 1 - (y + top_)); + for (int x = 0; x < width_; x++) { + row[x] = greyData_[offset]; + offset += dataWidth_; + } } return result; } - -} // namespace diff --git a/cpp/core/src/zxing/common/GreyscaleRotatedLuminanceSource.h b/cpp/core/src/zxing/common/GreyscaleRotatedLuminanceSource.h index 10afe8897..292159ada 100644 --- a/cpp/core/src/zxing/common/GreyscaleRotatedLuminanceSource.h +++ b/cpp/core/src/zxing/common/GreyscaleRotatedLuminanceSource.h @@ -1,3 +1,4 @@ +// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*- #ifndef __GREYSCALE_ROTATED_LUMINANCE_SOURCE__ #define __GREYSCALE_ROTATED_LUMINANCE_SOURCE__ /* @@ -23,22 +24,24 @@ #include namespace zxing { + class GreyscaleRotatedLuminanceSource; +} -class GreyscaleRotatedLuminanceSource : public LuminanceSource { +class zxing::GreyscaleRotatedLuminanceSource : public LuminanceSource { private: - unsigned char* greyData_; - int dataWidth_; - int left_; - int top_; - int width_; - int height_; + ArrayRef greyData_; + const int dataWidth_; + const int left_; + const int top_; + const int width_; + const int height_; public: - GreyscaleRotatedLuminanceSource(unsigned char* greyData, int dataWidth, int dataHeight, + GreyscaleRotatedLuminanceSource(ArrayRef greyData, int dataWidth, int dataHeight, int left, int top, int width, int height); - unsigned char* getRow(int y, unsigned char* row); - unsigned char* getMatrix(); + ArrayRef getRow(int y, ArrayRef row); + ArrayRef getMatrix(); bool isRotateSupported() const { return false; @@ -54,6 +57,4 @@ public: }; -} /* namespace */ - #endif diff --git a/cpp/core/src/zxing/common/HybridBinarizer.cpp b/cpp/core/src/zxing/common/HybridBinarizer.cpp index 9c59e2423..1789e24f7 100644 --- a/cpp/core/src/zxing/common/HybridBinarizer.cpp +++ b/cpp/core/src/zxing/common/HybridBinarizer.cpp @@ -59,7 +59,7 @@ Ref HybridBinarizer::getBlackMatrix() { int width = source.getWidth(); int height = source.getHeight(); if (width >= MINIMUM_DIMENSION && height >= MINIMUM_DIMENSION) { - unsigned char* luminances = source.getMatrix(); + ArrayRef luminances = source.getMatrix(); int subWidth = width >> BLOCK_SIZE_POWER; if ((width & BLOCK_SIZE_MASK) != 0) { subWidth++; @@ -68,7 +68,7 @@ Ref HybridBinarizer::getBlackMatrix() { if ((height & BLOCK_SIZE_MASK) != 0) { subHeight++; } - int* blackPoints = + ArrayRef blackPoints = calculateBlackPoints(luminances, subWidth, subHeight, width, height); Ref newMatrix (new BitMatrix(width, height)); @@ -80,13 +80,6 @@ Ref HybridBinarizer::getBlackMatrix() { blackPoints, newMatrix); matrix_ = newMatrix; - - // N.B.: these deletes are inadequate if anything between the new - // and this point can throw. As of this writing, it doesn't look - // like they do. - - delete [] blackPoints; - delete [] luminances; } else { // If the image is too small, fall back to the global histogram approach. matrix_ = GlobalHistogramBinarizer::getBlackMatrix(); @@ -101,12 +94,12 @@ namespace { } void -HybridBinarizer::calculateThresholdForBlock(unsigned char* luminances, +HybridBinarizer::calculateThresholdForBlock(ArrayRef luminances, int subWidth, int subHeight, int width, int height, - int blackPoints[], + ArrayRef blackPoints, Ref const& matrix) { for (int y = 0; y < subHeight; y++) { int yoffset = y << BLOCK_SIZE_POWER; @@ -137,7 +130,7 @@ HybridBinarizer::calculateThresholdForBlock(unsigned char* luminances, } } -void HybridBinarizer::thresholdBlock(unsigned char* luminances, +void HybridBinarizer::thresholdBlock(ArrayRef luminances, int xoffset, int yoffset, int threshold, @@ -156,7 +149,7 @@ void HybridBinarizer::thresholdBlock(unsigned char* luminances, } namespace { - inline int getBlackPointFromNeighbors(int* blackPoints, int subWidth, int x, int y) { + inline int getBlackPointFromNeighbors(ArrayRef blackPoints, int subWidth, int x, int y) { return (blackPoints[(y-1)*subWidth+x] + 2*blackPoints[y*subWidth+x-1] + blackPoints[(y-1)*subWidth+x-1]) >> 2; @@ -164,14 +157,14 @@ namespace { } -int* HybridBinarizer::calculateBlackPoints(unsigned char* luminances, - int subWidth, - int subHeight, - int width, - int height) { +ArrayRef HybridBinarizer::calculateBlackPoints(ArrayRef luminances, + int subWidth, + int subHeight, + int width, + int height) { const int minDynamicRange = 24; - int *blackPoints = new int[subHeight * subWidth]; + ArrayRef blackPoints (subHeight * subWidth); for (int y = 0; y < subHeight; y++) { int yoffset = y << BLOCK_SIZE_POWER; int maxYOffset = height - BLOCK_SIZE; diff --git a/cpp/core/src/zxing/common/HybridBinarizer.h b/cpp/core/src/zxing/common/HybridBinarizer.h index 9f1ea8bf9..932c2a2d7 100644 --- a/cpp/core/src/zxing/common/HybridBinarizer.h +++ b/cpp/core/src/zxing/common/HybridBinarizer.h @@ -42,19 +42,19 @@ namespace zxing { private: // We'll be using one-D arrays because C++ can't dynamically allocate 2D // arrays - int* calculateBlackPoints(unsigned char* luminances, - int subWidth, - int subHeight, - int width, - int height); - void calculateThresholdForBlock(unsigned char* luminances, + ArrayRef calculateBlackPoints(ArrayRef luminances, + int subWidth, + int subHeight, + int width, + int height); + void calculateThresholdForBlock(ArrayRef luminances, int subWidth, int subHeight, int width, int height, - int blackPoints[], + ArrayRef blackPoints, Ref const& matrix); - void thresholdBlock(unsigned char* luminances, + void thresholdBlock(ArrayRefluminances, int xoffset, int yoffset, int threshold, diff --git a/cpp/core/src/zxing/common/Str.cpp b/cpp/core/src/zxing/common/Str.cpp index 6259f9477..069bfcbf5 100644 --- a/cpp/core/src/zxing/common/Str.cpp +++ b/cpp/core/src/zxing/common/Str.cpp @@ -1,3 +1,4 @@ +// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*- /* * String.cpp * zxing @@ -20,19 +21,25 @@ #include -namespace zxing { -using namespace std; +using std::string; +using zxing::String; +using zxing::Ref; String::String(const std::string &text) : - text_(text) { + text_(text) { } const std::string& String::getText() const { return text_; } -ostream &operator<<(ostream &out, const String &s) { +char String::charAt(int i) const { return text_[i]; } +int String::size() const { return text_.size(); } +int String::length() const { return text_.size(); } +Ref String::substring(int i) const { + return Ref(new String(text_.substr(i))); +} + +std::ostream& zxing::operator << (std::ostream& out, String const& s) { out << s.text_; return out; } - -} diff --git a/cpp/core/src/zxing/common/Str.h b/cpp/core/src/zxing/common/Str.h index 8f093591e..a74de63db 100644 --- a/cpp/core/src/zxing/common/Str.h +++ b/cpp/core/src/zxing/common/Str.h @@ -1,3 +1,4 @@ +// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*- #ifndef __STR_H__ #define __STR_H__ @@ -25,16 +26,21 @@ #include namespace zxing { + class String; + std::ostream& operator << (std::ostream& out, String const& s); +} -class String : public Counted { +class zxing::String : public Counted { private: std::string text_; public: - String(const std::string &text); + explicit String(const std::string &text); + char charAt(int) const; + Ref substring(int) const; const std::string &getText() const; - friend std::ostream &operator<<(std::ostream &out, const String &s); + int size() const; + int length() const; + friend std::ostream& zxing::operator << (std::ostream& out, String const& s); }; -} - #endif // __COMMON__STRING_H__ diff --git a/cpp/core/src/zxing/common/StringUtils.cpp b/cpp/core/src/zxing/common/StringUtils.cpp index abb869730..30f9325be 100644 --- a/cpp/core/src/zxing/common/StringUtils.cpp +++ b/cpp/core/src/zxing/common/StringUtils.cpp @@ -35,7 +35,7 @@ char const* const StringUtils::ISO88591 = "ISO8859-1"; const bool StringUtils::ASSUME_SHIFT_JIS = false; string -StringUtils::guessEncoding(unsigned char* bytes, int length, +StringUtils::guessEncoding(char* bytes, int length, Hashtable const& hints) { Hashtable::const_iterator i = hints.find(DecodeHints::CHARACTER_SET); if (i != hints.end()) { @@ -64,7 +64,7 @@ StringUtils::guessEncoding(unsigned char* bytes, int length, //int isoHighChars = 0; int isoHighOther = 0; - typedef unsigned char byte; + typedef char byte; boolean utf8bom = length > 3 && bytes[0] == (byte) 0xEF && bytes[1] == (byte) 0xBB && diff --git a/cpp/core/src/zxing/common/StringUtils.h b/cpp/core/src/zxing/common/StringUtils.h index 87ffb3b15..32354fb22 100644 --- a/cpp/core/src/zxing/common/StringUtils.h +++ b/cpp/core/src/zxing/common/StringUtils.h @@ -46,7 +46,7 @@ public: typedef std::map Hashtable; - static std::string guessEncoding(unsigned char* bytes, int length, Hashtable const& hints); + static std::string guessEncoding(char* bytes, int length, Hashtable const& hints); }; #endif diff --git a/cpp/core/src/zxing/common/reedsolomon/GenericGFPoly.h b/cpp/core/src/zxing/common/reedsolomon/GenericGFPoly.h index feabc0aae..f39ac8143 100644 --- a/cpp/core/src/zxing/common/reedsolomon/GenericGFPoly.h +++ b/cpp/core/src/zxing/common/reedsolomon/GenericGFPoly.h @@ -28,27 +28,28 @@ namespace zxing { class GenericGF; - - class GenericGFPoly : public Counted { - private: - Ref field_; - ArrayRef coefficients_; - - public: - GenericGFPoly(Ref field, ArrayRef coefficients); - ArrayRef getCoefficients(); - int getDegree(); - bool isZero(); - int getCoefficient(int degree); - int evaluateAt(int a); - Ref addOrSubtract(Ref other); - Ref multiply(Ref other); - Ref multiply(int scalar); - Ref multiplyByMonomial(int degree, int coefficient); - std::vector > divide(Ref other); - - //#warning todo: add print method - }; + class GenericGFPoly; } + +class zxing::GenericGFPoly : public Counted { +private: + Ref field_; + ArrayRef coefficients_; + +public: + GenericGFPoly(Ref field, ArrayRef coefficients); + ArrayRef getCoefficients(); + int getDegree(); + bool isZero(); + int getCoefficient(int degree); + int evaluateAt(int a); + Ref addOrSubtract(Ref other); + Ref multiply(Ref other); + Ref multiply(int scalar); + Ref multiplyByMonomial(int degree, int coefficient); + std::vector > divide(Ref other); + + //#warning todo: add print method +}; -#endif //GENERICGFPOLY_H \ No newline at end of file +#endif //GENERICGFPOLY_H diff --git a/cpp/core/src/zxing/common/reedsolomon/ReedSolomonDecoder.cpp b/cpp/core/src/zxing/common/reedsolomon/ReedSolomonDecoder.cpp index 36bff1b9e..3f36c6288 100644 --- a/cpp/core/src/zxing/common/reedsolomon/ReedSolomonDecoder.cpp +++ b/cpp/core/src/zxing/common/reedsolomon/ReedSolomonDecoder.cpp @@ -1,3 +1,4 @@ +// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*- /* * ReedSolomonDecoder.cpp * zxing @@ -25,36 +26,23 @@ #include #include -using namespace std; +using namespace std; // remove -namespace zxing { +using zxing::Ref; +using zxing::ArrayRef; +using zxing::ReedSolomonDecoder; +using zxing::GenericGFPoly; ReedSolomonDecoder::ReedSolomonDecoder(Ref fld) : - field(fld) { + field(fld) { } ReedSolomonDecoder::~ReedSolomonDecoder() { } void ReedSolomonDecoder::decode(ArrayRef received, int twoS) { - Ref poly(new GenericGFPoly(field, received)); - - -/* -#ifdef DEBUG - cout << "decoding with poly " << *poly << endl; -#endif -*/ - - ArrayRef syndromeCoefficients(new Array (twoS)); - - -#ifdef DEBUG - cout << "syndromeCoefficients array = " << - syndromeCoefficients.array_ << endl; -#endif - + ArrayRef syndromeCoefficients(twoS); bool dataMatrix = (field.object_ == GenericGF::DATA_MATRIX_FIELD_256.object_); bool noError = true; for (int i = 0; i < twoS; i++) { @@ -67,17 +55,18 @@ void ReedSolomonDecoder::decode(ArrayRef received, int twoS) { if (noError) { return; } - Ref syndrome(new GenericGFPoly(field, syndromeCoefficients)); - Ref monomial = field->buildMonomial(twoS, 1); - vector > sigmaOmega = runEuclideanAlgorithm(monomial, syndrome, twoS); - ArrayRef errorLocations = findErrorLocations(sigmaOmega[0]); - ArrayRef errorMagitudes = findErrorMagnitudes(sigmaOmega[1], errorLocations, dataMatrix); - for (unsigned i = 0; i < errorLocations->size(); i++) { + vector > sigmaOmega = + runEuclideanAlgorithm(field->buildMonomial(twoS, 1), syndrome, twoS); + Ref sigma = sigmaOmega[0]; + Ref omega = sigmaOmega[1]; + ArrayRef errorLocations = findErrorLocations(sigma); + ArrayRef errorMagitudes = findErrorMagnitudes(omega, errorLocations, dataMatrix); + for (int i = 0; i < errorLocations->size(); i++) { int position = received->size() - 1 - field->log(errorLocations[i]); - //TODO: check why the position would be invalid - if (position < 0 || (size_t)position >= received.size()) - throw IllegalArgumentException("Invalid position (ReedSolomonDecoder)"); + if (position < 0) { + throw ReedSolomonException("Bad error location"); + } received[position] = GenericGF::addOrSubtract(received[position], errorMagitudes[i]); } } @@ -137,12 +126,12 @@ vector > ReedSolomonDecoder::runEuclideanAlgorithm(Ref > points(detectorResult->getPoints()); + ArrayRef< Ref > points(detectorResult->getPoints()); #ifdef DEBUG @@ -69,7 +69,7 @@ Ref DataMatrixReader::decode(Ref image, DecodeHints hints) #endif Ref result( - new Result(decoderResult->getText(), decoderResult->getRawBytes(), points, BarcodeFormat_DATA_MATRIX)); + new Result(decoderResult->getText(), decoderResult->getRawBytes(), points, BarcodeFormat::DATA_MATRIX)); #ifdef DEBUG cout << "(5) created result " << result.object_ << ", returning\n" << flush; #endif diff --git a/cpp/core/src/zxing/datamatrix/decoder/BitMatrixParser.cpp b/cpp/core/src/zxing/datamatrix/decoder/BitMatrixParser.cpp index 2e61da7a2..ef31f6fbc 100644 --- a/cpp/core/src/zxing/datamatrix/decoder/BitMatrixParser.cpp +++ b/cpp/core/src/zxing/datamatrix/decoder/BitMatrixParser.cpp @@ -57,9 +57,9 @@ Ref BitMatrixParser::readVersion(Ref bitMatrix) { throw ReaderException("Couldn't decode version"); } -ArrayRef BitMatrixParser::readCodewords() { - ArrayRef result(parsedVersion_->getTotalCodewords()); - int resultOffset = 0; +ArrayRef BitMatrixParser::readCodewords() { + ArrayRef result(parsedVersion_->getTotalCodewords()); + int resultOffset = 0; int row = 4; int column = 0; @@ -75,22 +75,22 @@ ArrayRef BitMatrixParser::readCodewords() { do { // Check the four corner cases if ((row == numRows) && (column == 0) && !corner1Read) { - result[resultOffset++] = (unsigned char) readCorner1(numRows, numColumns); + result[resultOffset++] = (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); + result[resultOffset++] = (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); + result[resultOffset++] = (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); + result[resultOffset++] = (char) readCorner4(numRows, numColumns); row -= 2; column +=2; corner4Read = true; @@ -98,7 +98,7 @@ ArrayRef BitMatrixParser::readCodewords() { // 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); + result[resultOffset++] = (char) readUtah(row, column, numRows, numColumns); } row -= 2; column +=2; @@ -109,7 +109,7 @@ ArrayRef BitMatrixParser::readCodewords() { // 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); + result[resultOffset++] = (char) readUtah(row, column, numRows, numColumns); } row += 2; column -=2; diff --git a/cpp/core/src/zxing/datamatrix/decoder/BitMatrixParser.h b/cpp/core/src/zxing/datamatrix/decoder/BitMatrixParser.h index 30123d59c..aed7b61fe 100644 --- a/cpp/core/src/zxing/datamatrix/decoder/BitMatrixParser.h +++ b/cpp/core/src/zxing/datamatrix/decoder/BitMatrixParser.h @@ -41,7 +41,7 @@ private: public: BitMatrixParser(Ref bitMatrix); Ref readVersion(Ref bitMatrix); - ArrayRef readCodewords(); + ArrayRef readCodewords(); bool readModule(int row, int column, int numRows, int numColumns); private: diff --git a/cpp/core/src/zxing/datamatrix/decoder/DataBlock.cpp b/cpp/core/src/zxing/datamatrix/decoder/DataBlock.cpp index c87d5f309..541e58333 100644 --- a/cpp/core/src/zxing/datamatrix/decoder/DataBlock.cpp +++ b/cpp/core/src/zxing/datamatrix/decoder/DataBlock.cpp @@ -26,7 +26,7 @@ namespace datamatrix { using namespace std; -DataBlock::DataBlock(int numDataCodewords, ArrayRef codewords) : +DataBlock::DataBlock(int numDataCodewords, ArrayRef codewords) : numDataCodewords_(numDataCodewords), codewords_(codewords) { } @@ -34,11 +34,11 @@ int DataBlock::getNumDataCodewords() { return numDataCodewords_; } -ArrayRef DataBlock::getCodewords() { +ArrayRef DataBlock::getCodewords() { return codewords_; } -std::vector > DataBlock::getDataBlocks(ArrayRef rawCodewords, Version *version) { +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(); @@ -58,7 +58,7 @@ std::vector > DataBlock::getDataBlocks(ArrayRef ra for (int i = 0; i < ecBlock->getCount(); i++) { int numDataCodewords = ecBlock->getDataCodewords(); int numBlockCodewords = ecBlocks->getECCodewords() + numDataCodewords; - ArrayRef buffer(numBlockCodewords); + ArrayRef buffer(numBlockCodewords); Ref blockRef(new DataBlock(numDataCodewords, buffer)); result[numResultBlocks++] = blockRef; } @@ -102,7 +102,7 @@ std::vector > DataBlock::getDataBlocks(ArrayRef ra } } - if ((size_t)rawCodewordsOffset != rawCodewords.size()) { + if (rawCodewordsOffset != rawCodewords.size()) { throw IllegalArgumentException("rawCodewordsOffset != rawCodewords.length"); } diff --git a/cpp/core/src/zxing/datamatrix/decoder/DataBlock.h b/cpp/core/src/zxing/datamatrix/decoder/DataBlock.h index 7fc72f655..5bc48db2c 100644 --- a/cpp/core/src/zxing/datamatrix/decoder/DataBlock.h +++ b/cpp/core/src/zxing/datamatrix/decoder/DataBlock.h @@ -32,15 +32,15 @@ namespace datamatrix { class DataBlock : public Counted { private: int numDataCodewords_; - ArrayRef codewords_; + ArrayRef codewords_; - DataBlock(int numDataCodewords, ArrayRef codewords); + DataBlock(int numDataCodewords, ArrayRef codewords); public: - static std::vector > getDataBlocks(ArrayRef rawCodewords, Version *version); + static std::vector > getDataBlocks(ArrayRef rawCodewords, Version *version); int getNumDataCodewords(); - ArrayRef getCodewords(); + ArrayRef getCodewords(); }; } diff --git a/cpp/core/src/zxing/datamatrix/decoder/DecodedBitStreamParser.cpp b/cpp/core/src/zxing/datamatrix/decoder/DecodedBitStreamParser.cpp index 7d86f1648..8482b1a83 100644 --- a/cpp/core/src/zxing/datamatrix/decoder/DecodedBitStreamParser.cpp +++ b/cpp/core/src/zxing/datamatrix/decoder/DecodedBitStreamParser.cpp @@ -51,11 +51,11 @@ const char DecodedBitStreamParser::TEXT_SHIFT3_SET_CHARS[] = { 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '{', '|', '}', '~', (char) 127 }; -Ref DecodedBitStreamParser::decode(ArrayRef bytes) { +Ref DecodedBitStreamParser::decode(ArrayRef bytes) { Ref bits(new BitSource(bytes)); ostringstream result; ostringstream resultTrailer; - vector byteSegments; + vector byteSegments; int mode = ASCII_ENCODE; do { if (mode == ASCII_ENCODE) { @@ -87,7 +87,7 @@ Ref DecodedBitStreamParser::decode(ArrayRef bytes) if (resultTrailer.str().size() > 0) { result << resultTrailer.str(); } - ArrayRef rawBytes(bytes); + ArrayRef rawBytes(bytes); Ref text(new String(result.str())); return Ref(new DecoderResult(rawBytes, text)); } @@ -381,7 +381,7 @@ void DecodedBitStreamParser::decodeEdifactSegment(Ref bits, ostringst } while (bits->available() > 0); } -void DecodedBitStreamParser::decodeBase256Segment(Ref bits, ostringstream& result, vector byteSegments) { +void DecodedBitStreamParser::decodeBase256Segment(Ref bits, ostringstream& result, vector byteSegments) { // Figure out how long the Base 256 Segment is. int codewordPosition = 1 + bits->getByteOffset(); // position is 1-indexed int d1 = unrandomize255State(bits->readBits(8), codewordPosition++); @@ -399,7 +399,7 @@ void DecodedBitStreamParser::decodeBase256Segment(Ref bits, ostringst throw FormatException("NegativeArraySizeException"); } - unsigned char* bytes = new unsigned char[count]; + char* bytes = new char[count]; for (int i = 0; i < count; i++) { // Have seen this particular error in the wild, such as at // http://www.bcgen.com/demo/IDAutomationStreamingDataMatrix.aspx?MODE=3&D=Fred&PFMT=3&PT=F&X=0.3&O=0&LM=0.2 diff --git a/cpp/core/src/zxing/datamatrix/decoder/DecodedBitStreamParser.h b/cpp/core/src/zxing/datamatrix/decoder/DecodedBitStreamParser.h index 5d322a0db..2acc831a7 100644 --- a/cpp/core/src/zxing/datamatrix/decoder/DecodedBitStreamParser.h +++ b/cpp/core/src/zxing/datamatrix/decoder/DecodedBitStreamParser.h @@ -79,23 +79,23 @@ private: /** * See ISO 16022:2006, 5.2.9 and Annex B, B.2 */ - void decodeBase256Segment(Ref bits, std::ostringstream &result, std::vector byteSegments); + 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) { + char unrandomize255State(int randomizedBase256Codeword, + int base256CodewordPosition) { int pseudoRandomNumber = ((149 * base256CodewordPosition) % 255) + 1; int tempVariable = randomizedBase256Codeword - pseudoRandomNumber; - return (unsigned char) (tempVariable >= 0 ? tempVariable : (tempVariable + 256)); + return (char) (tempVariable >= 0 ? tempVariable : (tempVariable + 256)); }; - void append(std::ostream &ost, const unsigned char *bufIn, size_t nIn, const char *src); + void append(std::ostream &ost, const char *bufIn, size_t nIn, const char *src); public: DecodedBitStreamParser() { }; - Ref decode(ArrayRef bytes); + Ref decode(ArrayRef bytes); }; } diff --git a/cpp/core/src/zxing/datamatrix/decoder/Decoder.cpp b/cpp/core/src/zxing/datamatrix/decoder/Decoder.cpp index eff4e36be..f65074c08 100644 --- a/cpp/core/src/zxing/datamatrix/decoder/Decoder.cpp +++ b/cpp/core/src/zxing/datamatrix/decoder/Decoder.cpp @@ -36,7 +36,7 @@ Decoder::Decoder() : } -void Decoder::correctErrors(ArrayRef codewordBytes, int numDataCodewords) { +void Decoder::correctErrors(ArrayRef codewordBytes, int numDataCodewords) { int numCodewords = codewordBytes->size(); ArrayRef codewordInts(numCodewords); for (int i = 0; i < numCodewords; i++) { @@ -52,7 +52,7 @@ void Decoder::correctErrors(ArrayRef codewordBytes, int numDataCo // Copy back into array of bytes -- only need to worry about the bytes that were data // We don't care about errors in the error-correction codewords for (int i = 0; i < numDataCodewords; i++) { - codewordBytes[i] = (unsigned char)codewordInts[i]; + codewordBytes[i] = (char)codewordInts[i]; } } @@ -62,7 +62,7 @@ Ref Decoder::decode(Ref bits) { Version *version = parser.readVersion(bits); // Read codewords - ArrayRef codewords(parser.readCodewords()); + ArrayRef codewords(parser.readCodewords()); // Separate into data blocks std::vector > dataBlocks = DataBlock::getDataBlocks(codewords, version); @@ -73,12 +73,12 @@ Ref Decoder::decode(Ref bits) { for (int i = 0; i < dataBlocksCount; i++) { totalBytes += dataBlocks[i]->getNumDataCodewords(); } - ArrayRef resultBytes(totalBytes); + ArrayRef resultBytes(totalBytes); // Error-correct and copy data blocks together into a stream of bytes for (int j = 0; j < dataBlocksCount; j++) { Ref dataBlock(dataBlocks[j]); - ArrayRef codewordBytes = dataBlock->getCodewords(); + ArrayRef codewordBytes = dataBlock->getCodewords(); int numDataCodewords = dataBlock->getNumDataCodewords(); correctErrors(codewordBytes, numDataCodewords); for (int i = 0; i < numDataCodewords; i++) { diff --git a/cpp/core/src/zxing/datamatrix/decoder/Decoder.h b/cpp/core/src/zxing/datamatrix/decoder/Decoder.h index cc5652d88..6394a9f90 100644 --- a/cpp/core/src/zxing/datamatrix/decoder/Decoder.h +++ b/cpp/core/src/zxing/datamatrix/decoder/Decoder.h @@ -35,7 +35,7 @@ class Decoder { private: ReedSolomonDecoder rsDecoder_; - void correctErrors(ArrayRef bytes, int numDataCodewords); + void correctErrors(ArrayRef bytes, int numDataCodewords); public: Decoder(); diff --git a/cpp/core/src/zxing/datamatrix/detector/Detector.cpp b/cpp/core/src/zxing/datamatrix/detector/Detector.cpp index a53a31ce2..a230f482f 100644 --- a/cpp/core/src/zxing/datamatrix/detector/Detector.cpp +++ b/cpp/core/src/zxing/datamatrix/detector/Detector.cpp @@ -245,7 +245,7 @@ Ref Detector::detect() { bits = sampleGrid(image_, dimensionCorrected, dimensionCorrected, transform); } - std::vector > points(4); + ArrayRef< Ref > points (new Array< Ref >(4)); points[0].reset(topLeft); points[1].reset(bottomLeft); points[2].reset(correctedTopRight); diff --git a/cpp/core/src/zxing/multi/GenericMultipleBarcodeReader.cpp b/cpp/core/src/zxing/multi/GenericMultipleBarcodeReader.cpp index adad94d04..c80263ed3 100644 --- a/cpp/core/src/zxing/multi/GenericMultipleBarcodeReader.cpp +++ b/cpp/core/src/zxing/multi/GenericMultipleBarcodeReader.cpp @@ -60,8 +60,8 @@ void GenericMultipleBarcodeReader::doDecodeMultiple(Ref image, } results.push_back(translateResultPoints(result, xOffset, yOffset)); - const std::vector > resultPoints = result->getResultPoints(); - if (resultPoints.empty()) { + ArrayRef< Ref > resultPoints = result->getResultPoints(); + if (resultPoints->empty()) { return; } @@ -71,7 +71,7 @@ void GenericMultipleBarcodeReader::doDecodeMultiple(Ref image, float minY = height; float maxX = 0.0f; float maxY = 0.0f; - for (unsigned int i = 0; i < resultPoints.size(); i++) { + for (int i = 0; i < resultPoints.size(); i++) { Ref point = resultPoints[i]; float x = point->getX(); float y = point->getY(); @@ -112,14 +112,14 @@ void GenericMultipleBarcodeReader::doDecodeMultiple(Ref image, } Ref GenericMultipleBarcodeReader::translateResultPoints(Ref result, int xOffset, int yOffset){ - const std::vector > oldResultPoints = result->getResultPoints(); - if (oldResultPoints.empty()) { + ArrayRef< Ref > oldResultPoints = result->getResultPoints(); + if (oldResultPoints->empty()) { return result; } - std::vector > newResultPoints; - for (unsigned int i = 0; i < oldResultPoints.size(); i++) { + ArrayRef< Ref > newResultPoints; + for (int i = 0; i < oldResultPoints.size(); i++) { Ref oldPoint = oldResultPoints[i]; - newResultPoints.push_back(Ref(new ResultPoint(oldPoint->getX() + xOffset, oldPoint->getY() + yOffset))); + newResultPoints->values().push_back(Ref(new ResultPoint(oldPoint->getX() + xOffset, oldPoint->getY() + yOffset))); } return Ref(new Result(result->getText(), result->getRawBytes(), newResultPoints, result->getBarcodeFormat())); } diff --git a/cpp/core/src/zxing/multi/qrcode/QRCodeMultiReader.cpp b/cpp/core/src/zxing/multi/qrcode/QRCodeMultiReader.cpp index d60f5e069..90cfb0274 100644 --- a/cpp/core/src/zxing/multi/qrcode/QRCodeMultiReader.cpp +++ b/cpp/core/src/zxing/multi/qrcode/QRCodeMultiReader.cpp @@ -36,10 +36,10 @@ std::vector > QRCodeMultiReader::decodeMultiple(Ref im for (unsigned int i = 0; i < detectorResult.size(); i++) { try { Ref decoderResult = getDecoder().decode(detectorResult[i]->getBits()); - std::vector > points = detectorResult[i]->getPoints(); + ArrayRef< Ref > points = detectorResult[i]->getPoints(); Ref result = Ref(new Result(decoderResult->getText(), decoderResult->getRawBytes(), - points, BarcodeFormat_QR_CODE)); + points, BarcodeFormat::QR_CODE)); // result->putMetadata(ResultMetadataType.BYTE_SEGMENTS, decoderResult->getByteSegments()); // result->putMetadata(ResultMetadataType.ERROR_CORRECTION_LEVEL, decoderResult->getECLevel().toString()); results.push_back(result); diff --git a/cpp/core/src/zxing/oned/CodaBarReader.cpp b/cpp/core/src/zxing/oned/CodaBarReader.cpp new file mode 100644 index 000000000..a8e0320f5 --- /dev/null +++ b/cpp/core/src/zxing/oned/CodaBarReader.cpp @@ -0,0 +1,328 @@ +// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*- +/* + * 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 "CodaBarReader.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using std::vector; +using std::string; +using zxing::NotFoundException; +using zxing::FormatException; +using zxing::ChecksumException; +using zxing::Ref; +using zxing::Result; +using zxing::oned::CodaBarReader; + +namespace { + char const ALPHABET_STRING[] = "0123456789-$:/.+ABCD"; + char const* const ALPHABET = ALPHABET_STRING; + + /** + * These represent the encodings of characters, as patterns of wide and narrow bars. The 7 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[] = { + 0x003, 0x006, 0x009, 0x060, 0x012, 0x042, 0x021, 0x024, 0x030, 0x048, // 0-9 + 0x00c, 0x018, 0x045, 0x051, 0x054, 0x015, 0x01A, 0x029, 0x00B, 0x00E, // -$:/.+ABCD + }; + + // minimal number of characters that should be present (inclusing start and stop characters) + // under normal circumstances this should be set to 3, but can be set higher + // as a last-ditch attempt to reduce false positives. + const int MIN_CHARACTER_LENGTH = 3; + + // official start and end patterns + const char STARTEND_ENCODING[] = {'A', 'B', 'C', 'D', 0}; + // some codabar generator allow the codabar string to be closed by every + // character. This will cause lots of false positives! + + // some industries use a checksum standard but this is not part of the original codabar standard + // for more information see : http://www.mecsw.com/specs/codabar.html +} + +// These values are critical for determining how permissive the decoding +// will be. All stripe sizes must be within the window these define, as +// compared to the average stripe size. +const int CodaBarReader::MAX_ACCEPTABLE = + (int) (PATTERN_MATCH_RESULT_SCALE_FACTOR * 2.0f); +const int CodaBarReader::PADDING = + (int) (PATTERN_MATCH_RESULT_SCALE_FACTOR * 1.5f); + +CodaBarReader::CodaBarReader() + : counters(80, 0), counterLength(0) {} + +using namespace std; + +Ref CodaBarReader::decodeRow(int rowNumber, + Ref row) { + // cerr << "cbr " << rowNumber << " " << *row << endl; + setCounters(row); + int startOffset = findStartPattern(); + int nextStart = startOffset; + + decodeRowResult.clear(); + do { + int charOffset = toNarrowWidePattern(nextStart); + if (charOffset == -1) { + throw NotFoundException::getNotFoundInstance(); + } + // Hack: We store the position in the alphabet table into a + // StringBuilder, so that we can access the decoded patterns in + // validatePattern. We'll translate to the actual characters later. + decodeRowResult.append(1, (char)charOffset); + nextStart += 8; + // Stop as soon as we see the end character. + if (decodeRowResult.length() > 1 && + arrayContains(STARTEND_ENCODING, ALPHABET[charOffset])) { + break; + } + } while (nextStart < counterLength); // no fixed end pattern so keep on reading while data is available + + // Look for whitespace after pattern: + int trailingWhitespace = counters[nextStart - 1]; + int lastPatternSize = 0; + for (int i = -8; i < -1; i++) { + lastPatternSize += counters[nextStart + i]; + } + + // We need to see whitespace equal to 50% of the last pattern size, + // otherwise this is probably a false positive. The exception is if we are + // at the end of the row. (I.e. the barcode barely fits.) + if (nextStart < counterLength && trailingWhitespace < lastPatternSize / 2) { + throw NotFoundException::getNotFoundInstance(); + } + + validatePattern(startOffset); + + // Translate character table offsets to actual characters. + for (int i = 0; i < (int)decodeRowResult.length(); i++) { + decodeRowResult[i] = ALPHABET[(int)decodeRowResult[i]]; + } + // Ensure a valid start and end character + char startchar = decodeRowResult[0]; + if (!arrayContains(STARTEND_ENCODING, startchar)) { + throw NotFoundException::getNotFoundInstance(); + } + char endchar = decodeRowResult[decodeRowResult.length() - 1]; + if (!arrayContains(STARTEND_ENCODING, endchar)) { + throw NotFoundException::getNotFoundInstance(); + } + + // remove stop/start characters character and check if a long enough string is contained + if ((int)decodeRowResult.length() <= MIN_CHARACTER_LENGTH) { + // Almost surely a false positive ( start + stop + at least 1 character) + throw NotFoundException::getNotFoundInstance(); + } + +decodeRowResult.erase(decodeRowResult.length() - 1, 1); +decodeRowResult.erase(0, 1); + + int runningCount = 0; + for (int i = 0; i < startOffset; i++) { + runningCount += counters[i]; + } + float left = (float) runningCount; + for (int i = startOffset; i < nextStart - 1; i++) { + runningCount += counters[i]; + } + float right = (float) runningCount; + + ArrayRef< Ref > resultPoints(2); + resultPoints[0] = + Ref(new OneDResultPoint(left, (float) rowNumber)); + resultPoints[1] = + Ref(new OneDResultPoint(right, (float) rowNumber)); + + return Ref( + new Result( + Ref(new String(decodeRowResult)), + ArrayRef(), + resultPoints, + BarcodeFormat::CODABAR) + ); +} + +void CodaBarReader::validatePattern(int start) { + // First, sum up the total size of our four categories of stripe sizes; + vector sizes (4, 0); + vector counts (4, 0); + int end = decodeRowResult.length() - 1; + + // We break out of this loop in the middle, in order to handle + // inter-character spaces properly. + int pos = start; + for (int i = 0; true; i++) { + int pattern = CHARACTER_ENCODINGS[(int)decodeRowResult[i]]; + for (int j = 6; j >= 0; j--) { + // Even j = bars, while odd j = spaces. Categories 2 and 3 are for + // long stripes, while 0 and 1 are for short stripes. + int category = (j & 1) + (pattern & 1) * 2; + sizes[category] += counters[pos + j]; + counts[category]++; + pattern >>= 1; + } + if (i >= end) { + break; + } + // We ignore the inter-character space - it could be of any size. + pos += 8; + } + + // Calculate our allowable size thresholds using fixed-point math. + vector maxes (4, 0); + vector mins (4, 0); + // Define the threshold of acceptability to be the midpoint between the + // average small stripe and the average large stripe. No stripe lengths + // should be on the "wrong" side of that line. + for (int i = 0; i < 2; i++) { + mins[i] = 0; // Accept arbitrarily small "short" stripes. + mins[i + 2] = ((sizes[i] << INTEGER_MATH_SHIFT) / counts[i] + + (sizes[i + 2] << INTEGER_MATH_SHIFT) / counts[i + 2]) >> 1; + maxes[i] = mins[i + 2]; + maxes[i + 2] = (sizes[i + 2] * MAX_ACCEPTABLE + PADDING) / counts[i + 2]; + } + + // Now verify that all of the stripes are within the thresholds. + pos = start; + for (int i = 0; true; i++) { + int pattern = CHARACTER_ENCODINGS[(int)decodeRowResult[i]]; + for (int j = 6; j >= 0; j--) { + // Even j = bars, while odd j = spaces. Categories 2 and 3 are for + // long stripes, while 0 and 1 are for short stripes. + int category = (j & 1) + (pattern & 1) * 2; + int size = counters[pos + j] << INTEGER_MATH_SHIFT; + if (size < mins[category] || size > maxes[category]) { + throw NotFoundException::getNotFoundInstance(); + } + pattern >>= 1; + } + if (i >= end) { + break; + } + pos += 8; + } +} + +/** + * Records the size of all runs of white and black pixels, starting with white. + * This is just like recordPattern, except it records all the counters, and + * uses our builtin "counters" member for storage. + * @param row row to count from + */ +void CodaBarReader::setCounters(Ref row) { + counterLength = 0; + // Start from the first white bit. + int i = row->getNextUnset(0); + int end = row->getSize(); + if (i >= end) { + throw NotFoundException::getNotFoundInstance(); + } + bool isWhite = true; + int count = 0; + for (; i < end; i++) { + if (row->get(i) ^ isWhite) { // that is, exactly one is true + count++; + } else { + counterAppend(count); + count = 1; + isWhite = !isWhite; + } + } + counterAppend(count); +} + +void CodaBarReader::counterAppend(int e) { + if (counterLength < (int)counters.size()) { + counters[counterLength] = e; + } else { + counters.push_back(e); + } + counterLength++; +} + +int CodaBarReader::findStartPattern() { + for (int i = 1; i < counterLength; i += 2) { + int charOffset = toNarrowWidePattern(i); + if (charOffset != -1 && arrayContains(STARTEND_ENCODING, ALPHABET[charOffset])) { + // Look for whitespace before start pattern, >= 50% of width of start pattern + // We make an exception if the whitespace is the first element. + int patternSize = 0; + for (int j = i; j < i + 7; j++) { + patternSize += counters[j]; + } + if (i == 1 || counters[i-1] >= patternSize / 2) { + return i; + } + } + } + throw NotFoundException::getNotFoundInstance(); +} + +bool CodaBarReader::arrayContains(char const array[], char key) { + return index(array, key) != 0; +} + +// Assumes that counters[position] is a bar. +int CodaBarReader::toNarrowWidePattern(int position) { + int end = position + 7; + if (end >= counterLength) { + return -1; + } + // First element is for bars, second is for spaces. + vector maxes (2, 0); + vector mins (2, std::numeric_limits::max()); + vector thresholds (2, 0); + + for (int i = 0; i < 2; i++) { + for (int j = position + i; j < end; j += 2) { + if (counters[j] < mins[i]) { + mins[i] = counters[j]; + } + if (counters[j] > maxes[i]) { + maxes[i] = counters[j]; + } + } + thresholds[i] = (mins[i] + maxes[i]) / 2; + } + + int bitmask = 1 << 7; + int pattern = 0; + for (int i = 0; i < 7; i++) { + int barOrSpace = i & 1; + bitmask >>= 1; + if (counters[position + i] > thresholds[barOrSpace]) { + pattern |= bitmask; + } + } + + for (int i = 0; + i < (int)(sizeof(CHARACTER_ENCODINGS)/sizeof(CHARACTER_ENCODINGS[0])); + i++) { + if (CHARACTER_ENCODINGS[i] == pattern) { + return i; + } + } + return -1; +} diff --git a/cpp/core/src/zxing/oned/CodaBarReader.h b/cpp/core/src/zxing/oned/CodaBarReader.h new file mode 100644 index 000000000..826aebe63 --- /dev/null +++ b/cpp/core/src/zxing/oned/CodaBarReader.h @@ -0,0 +1,57 @@ +// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*- +#ifndef __CODA_BAR_READER_H__ +#define __CODA_BAR_READER_H__ +/* + * 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 oned { + class CodaBarReader; + } +} + +class zxing::oned::CodaBarReader : public OneDReader { +private: + static const int MAX_ACCEPTABLE; + static const int PADDING; + + // Keep some instance variables to avoid reallocations + std::string decodeRowResult; + std::vector counters; + int counterLength; + +public: + CodaBarReader(); + + Ref decodeRow(int rowNumber, Ref row); + + void validatePattern(int start); + +private: + void setCounters(Ref row); + void counterAppend(int e); + int findStartPattern(); + + static bool arrayContains(char const array[], char key); + + int toNarrowWidePattern(int position); +}; + +#endif diff --git a/cpp/core/src/zxing/oned/Code128Reader.cpp b/cpp/core/src/zxing/oned/Code128Reader.cpp index 8bddc47ba..3a546c3ed 100644 --- a/cpp/core/src/zxing/oned/Code128Reader.cpp +++ b/cpp/core/src/zxing/oned/Code128Reader.cpp @@ -19,471 +19,457 @@ #include #include #include +#include +#include +#include #include #include #include -namespace zxing { - namespace oned { +using std::vector; +using std::string; +using zxing::NotFoundException; +using zxing::FormatException; +using zxing::ChecksumException; +using zxing::Ref; +using zxing::Result; +using zxing::oned::Code128Reader; - 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}, - {1, 2, 1, 2, 2, 3}, - {1, 2, 1, 3, 2, 2}, - {1, 3, 1, 2, 2, 2}, /* 5 */ - {1, 2, 2, 2, 1, 3}, - {1, 2, 2, 3, 1, 2}, - {1, 3, 2, 2, 1, 2}, - {2, 2, 1, 2, 1, 3}, - {2, 2, 1, 3, 1, 2}, /* 10 */ - {2, 3, 1, 2, 1, 2}, - {1, 1, 2, 2, 3, 2}, - {1, 2, 2, 1, 3, 2}, - {1, 2, 2, 2, 3, 1}, - {1, 1, 3, 2, 2, 2}, /* 15 */ - {1, 2, 3, 1, 2, 2}, - {1, 2, 3, 2, 2, 1}, - {2, 2, 3, 2, 1, 1}, - {2, 2, 1, 1, 3, 2}, - {2, 2, 1, 2, 3, 1}, /* 20 */ - {2, 1, 3, 2, 1, 2}, - {2, 2, 3, 1, 1, 2}, - {3, 1, 2, 1, 3, 1}, - {3, 1, 1, 2, 2, 2}, - {3, 2, 1, 1, 2, 2}, /* 25 */ - {3, 2, 1, 2, 2, 1}, - {3, 1, 2, 2, 1, 2}, - {3, 2, 2, 1, 1, 2}, - {3, 2, 2, 2, 1, 1}, - {2, 1, 2, 1, 2, 3}, /* 30 */ - {2, 1, 2, 3, 2, 1}, - {2, 3, 2, 1, 2, 1}, - {1, 1, 1, 3, 2, 3}, - {1, 3, 1, 1, 2, 3}, - {1, 3, 1, 3, 2, 1}, /* 35 */ - {1, 1, 2, 3, 1, 3}, - {1, 3, 2, 1, 1, 3}, - {1, 3, 2, 3, 1, 1}, - {2, 1, 1, 3, 1, 3}, - {2, 3, 1, 1, 1, 3}, /* 40 */ - {2, 3, 1, 3, 1, 1}, - {1, 1, 2, 1, 3, 3}, - {1, 1, 2, 3, 3, 1}, - {1, 3, 2, 1, 3, 1}, - {1, 1, 3, 1, 2, 3}, /* 45 */ - {1, 1, 3, 3, 2, 1}, - {1, 3, 3, 1, 2, 1}, - {3, 1, 3, 1, 2, 1}, - {2, 1, 1, 3, 3, 1}, - {2, 3, 1, 1, 3, 1}, /* 50 */ - {2, 1, 3, 1, 1, 3}, - {2, 1, 3, 3, 1, 1}, - {2, 1, 3, 1, 3, 1}, - {3, 1, 1, 1, 2, 3}, - {3, 1, 1, 3, 2, 1}, /* 55 */ - {3, 3, 1, 1, 2, 1}, - {3, 1, 2, 1, 1, 3}, - {3, 1, 2, 3, 1, 1}, - {3, 3, 2, 1, 1, 1}, - {3, 1, 4, 1, 1, 1}, /* 60 */ - {2, 2, 1, 4, 1, 1}, - {4, 3, 1, 1, 1, 1}, - {1, 1, 1, 2, 2, 4}, - {1, 1, 1, 4, 2, 2}, - {1, 2, 1, 1, 2, 4}, /* 65 */ - {1, 2, 1, 4, 2, 1}, - {1, 4, 1, 1, 2, 2}, - {1, 4, 1, 2, 2, 1}, - {1, 1, 2, 2, 1, 4}, - {1, 1, 2, 4, 1, 2}, /* 70 */ - {1, 2, 2, 1, 1, 4}, - {1, 2, 2, 4, 1, 1}, - {1, 4, 2, 1, 1, 2}, - {1, 4, 2, 2, 1, 1}, - {2, 4, 1, 2, 1, 1}, /* 75 */ - {2, 2, 1, 1, 1, 4}, - {4, 1, 3, 1, 1, 1}, - {2, 4, 1, 1, 1, 2}, - {1, 3, 4, 1, 1, 1}, - {1, 1, 1, 2, 4, 2}, /* 80 */ - {1, 2, 1, 1, 4, 2}, - {1, 2, 1, 2, 4, 1}, - {1, 1, 4, 2, 1, 2}, - {1, 2, 4, 1, 1, 2}, - {1, 2, 4, 2, 1, 1}, /* 85 */ - {4, 1, 1, 2, 1, 2}, - {4, 2, 1, 1, 1, 2}, - {4, 2, 1, 2, 1, 1}, - {2, 1, 2, 1, 4, 1}, - {2, 1, 4, 1, 2, 1}, /* 90 */ - {4, 1, 2, 1, 2, 1}, - {1, 1, 1, 1, 4, 3}, - {1, 1, 1, 3, 4, 1}, - {1, 3, 1, 1, 4, 1}, - {1, 1, 4, 1, 1, 3}, /* 95 */ - {1, 1, 4, 3, 1, 1}, - {4, 1, 1, 1, 1, 3}, - {4, 1, 1, 3, 1, 1}, - {1, 1, 3, 1, 4, 1}, - {1, 1, 4, 1, 3, 1}, /* 100 */ - {3, 1, 1, 1, 4, 1}, - {4, 1, 1, 1, 3, 1}, - {2, 1, 1, 4, 1, 2}, - {2, 1, 1, 2, 1, 4}, - {2, 1, 1, 2, 3, 2}, /* 105 */ - {2, 3, 3, 1, 1, 1} - }; +const int Code128Reader::MAX_AVG_VARIANCE = int(PATTERN_MATCH_RESULT_SCALE_FACTOR * 250/1000); +const int Code128Reader::MAX_INDIVIDUAL_VARIANCE = int(PATTERN_MATCH_RESULT_SCALE_FACTOR * 700/1000); - - Code128Reader::Code128Reader(){ - } - - int* Code128Reader::findStartPattern(Ref row){ - int width = row->getSize(); - int rowOffset = 0; - while (rowOffset < width) { - if (row->get(rowOffset)) { - break; - } - rowOffset++; - } - - int counterPosition = 0; - int counters[countersLength] = {0,0,0,0,0,0}; - int patternStart = rowOffset; - bool isWhite = false; - int patternLength = sizeof(counters) / sizeof(int); - - for (int i = rowOffset; i < width; i++) { - bool pixel = row->get(i); - if (pixel ^ isWhite) { - counters[counterPosition]++; - } else { - if (counterPosition == patternLength - 1) { - unsigned int bestVariance = MAX_AVG_VARIANCE; - int bestMatch = -1; - for (int startCode = CODE_START_A; startCode <= CODE_START_C; startCode++) { - unsigned int variance = patternMatchVariance(counters, sizeof(counters) / sizeof(int), - CODE_PATTERNS[startCode], MAX_INDIVIDUAL_VARIANCE); - if (variance < bestVariance) { - bestVariance = variance; - bestMatch = startCode; - } - } - // Look for whitespace before start pattern, >= 50% of width of start pattern - if (bestMatch >= 0 && - row->isRange(std::max(0, patternStart - (i - patternStart) / 2), patternStart, - false)) { - int* resultValue = new int[3]; - resultValue[0] = patternStart; - resultValue[1] = i; - resultValue[2] = bestMatch; - 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(""); - } - - int Code128Reader::decodeCode(Ref row, int counters[], int countersCount, - int rowOffset) { - if (!recordPattern(row, rowOffset, counters, countersCount)) { - throw ReaderException(""); - } - 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]; - - for(int ind = 0; ind< countersLength; ind++){ - pattern[ind] = CODE_PATTERNS[d][ind]; - } -// memcpy(pattern, CODE_PATTERNS[d], countersLength); - unsigned int variance = patternMatchVariance(counters, countersCount, pattern, - MAX_INDIVIDUAL_VARIANCE); - if (variance < bestVariance) { - bestVariance = variance; - bestMatch = d; - } - } - // TODO We're overlooking the fact that the STOP pattern has 7 values, not 6. - if (bestMatch >= 0) { - return bestMatch; - } else { - throw ReaderException(""); - } - } - - Ref Code128Reader::decodeRow(int rowNumber, Ref row) { - int* startPatternInfo = NULL; - try { - startPatternInfo = findStartPattern(row); - int startCode = startPatternInfo[2]; - int codeSet; - switch (startCode) { - case CODE_START_A: - codeSet = CODE_CODE_A; - break; - case CODE_START_B: - codeSet = CODE_CODE_B; - break; - case CODE_START_C: - codeSet = CODE_CODE_C; - break; - default: - throw ReaderException(""); - } - - bool done = false; - bool isNextShifted = false; - - std::string tmpResultString; - std::stringstream tmpResultSStr; // used if its Code 128C - - int lastStart = startPatternInfo[0]; - int nextStart = startPatternInfo[1]; - int counters[countersLength] = {0,0,0,0,0,0}; - - int lastCode = 0; - int code = 0; - int checksumTotal = startCode; - int multiplier = 0; - bool lastCharacterWasPrintable = true; - - while (!done) { - bool unshift = isNextShifted; - isNextShifted = false; - - // Save off last code - lastCode = code; - - // Decode another code from image - try { - code = decodeCode(row, counters, sizeof(counters)/sizeof(int), nextStart); - } catch (ReaderException const& re) { - throw re; - } - - // Remember whether the last code was printable or not (excluding CODE_STOP) - if (code != CODE_STOP) { - lastCharacterWasPrintable = true; - } - - // Add to checksum computation (if not CODE_STOP of course) - if (code != CODE_STOP) { - multiplier++; - checksumTotal += multiplier * code; - } - - // Advance to where the next code will to start - lastStart = nextStart; - int _countersLength = sizeof(counters) / sizeof(int); - for (int i = 0; i < _countersLength; i++) { - nextStart += counters[i]; - } - - // Take care of illegal start codes - switch (code) { - case CODE_START_A: - case CODE_START_B: - case CODE_START_C: - throw ReaderException(""); - } - - switch (codeSet) { - - case CODE_CODE_A: - if (code < 64) { - tmpResultString.append(1, (char) (' ' + code)); - } else if (code < 96) { - tmpResultString.append(1, (char) (code - 64)); - } else { - // Don't let CODE_STOP, which always appears, affect whether whether we think the - // last code was printable or not. - if (code != CODE_STOP) { - lastCharacterWasPrintable = false; - } - switch (code) { - case CODE_FNC_1: - case CODE_FNC_2: - case CODE_FNC_3: - case CODE_FNC_4_A: - // do nothing? - break; - case CODE_SHIFT: - isNextShifted = true; - codeSet = CODE_CODE_B; - break; - case CODE_CODE_B: - codeSet = CODE_CODE_B; - break; - case CODE_CODE_C: - codeSet = CODE_CODE_C; - break; - case CODE_STOP: - done = true; - break; - } - } - break; - case CODE_CODE_B: - if (code < 96) { - tmpResultString.append(1, (char) (' ' + code)); - } else { - if (code != CODE_STOP) { - lastCharacterWasPrintable = false; - } - switch (code) { - case CODE_FNC_1: - case CODE_FNC_2: - case CODE_FNC_3: - case CODE_FNC_4_B: - // do nothing? - break; - case CODE_SHIFT: - isNextShifted = true; - codeSet = CODE_CODE_C; - break; - case CODE_CODE_A: - codeSet = CODE_CODE_A; - break; - case CODE_CODE_C: - codeSet = CODE_CODE_C; - break; - case CODE_STOP: - done = true; - break; - } - } - break; - case CODE_CODE_C: - tmpResultSStr.str(std::string()); - // the code read in this case is the number encoded directly - if (code < 100) { - if (code < 10) { - tmpResultSStr << '0'; - } - tmpResultSStr << code; - tmpResultString.append(tmpResultSStr.str()); - } else { - if (code != CODE_STOP) { - lastCharacterWasPrintable = false; - } - switch (code) { - case CODE_FNC_1: - // do nothing? - break; - case CODE_CODE_A: - codeSet = CODE_CODE_A; - break; - case CODE_CODE_B: - codeSet = CODE_CODE_B; - break; - case CODE_STOP: - done = true; - break; - } - } - break; - } - - // Unshift back to another code set if we were shifted - if (unshift) { - switch (codeSet) { - case CODE_CODE_A: - codeSet = CODE_CODE_C; - break; - case CODE_CODE_B: - codeSet = CODE_CODE_A; - break; - case CODE_CODE_C: - codeSet = CODE_CODE_B; - break; - } - } - - } - - // Check for ample whitespace following pattern, but, to do this we first need to remember that - // we fudged decoding CODE_STOP since it actually has 7 bars, not 6. There is a black bar left - // to read off. Would be slightly better to properly read. Here we just skip it: - int width = row->getSize(); - while (nextStart < width && row->get(nextStart)) { - nextStart++; - } - if (!row->isRange(nextStart, - std::min(width, nextStart + (nextStart - lastStart) / 2), - false)) { - throw ReaderException(""); - } - - // Pull out from sum the value of the penultimate check code - checksumTotal -= multiplier * lastCode; - // lastCode is the checksum then: - if (checksumTotal % 103 != lastCode) { - throw ReaderException(""); - } - - // 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 - // be a printable character. If it was just interpreted as a control code, nothing to remove. - if (resultLength > 0 && lastCharacterWasPrintable) { - if (codeSet == CODE_CODE_C) { - tmpResultString.erase(resultLength - 2, resultLength); - } else { - tmpResultString.erase(resultLength - 1, resultLength); - } - } - - Ref resultString(new String(tmpResultString)); - if (tmpResultString.length() == 0) { - // Almost surely a false positive - throw ReaderException(""); - } - - float left = (float) (startPatternInfo[1] + startPatternInfo[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; - - delete [] startPatternInfo; - ArrayRef resultBytes(1); - return Ref(new Result(resultString, resultBytes, resultPoints, - BarcodeFormat_CODE_128)); - } catch (ReaderException const& re) { - delete [] startPatternInfo; - return Ref(); - } - } - - void Code128Reader::append(char* s, char c){ - int len = strlen(s); - s[len] = c; - s[len + 1] = '\0'; - } - - Code128Reader::~Code128Reader(){ - } - } +namespace { + const int CODE_SHIFT = 98; + + const int CODE_CODE_C = 99; + const int CODE_CODE_B = 100; + const int CODE_CODE_A = 101; + + const int CODE_FNC_1 = 102; + const int CODE_FNC_2 = 97; + const int CODE_FNC_3 = 96; + const int CODE_FNC_4_A = 101; + const int CODE_FNC_4_B = 100; + + const int CODE_START_A = 103; + const int CODE_START_B = 104; + const int CODE_START_C = 105; + const int CODE_STOP = 106; + + const int CODE_PATTERNS_LENGTH = 107; + const int CODE_PATTERNS[CODE_PATTERNS_LENGTH][6] = { + {2, 1, 2, 2, 2, 2}, /* 0 */ + {2, 2, 2, 1, 2, 2}, + {2, 2, 2, 2, 2, 1}, + {1, 2, 1, 2, 2, 3}, + {1, 2, 1, 3, 2, 2}, + {1, 3, 1, 2, 2, 2}, /* 5 */ + {1, 2, 2, 2, 1, 3}, + {1, 2, 2, 3, 1, 2}, + {1, 3, 2, 2, 1, 2}, + {2, 2, 1, 2, 1, 3}, + {2, 2, 1, 3, 1, 2}, /* 10 */ + {2, 3, 1, 2, 1, 2}, + {1, 1, 2, 2, 3, 2}, + {1, 2, 2, 1, 3, 2}, + {1, 2, 2, 2, 3, 1}, + {1, 1, 3, 2, 2, 2}, /* 15 */ + {1, 2, 3, 1, 2, 2}, + {1, 2, 3, 2, 2, 1}, + {2, 2, 3, 2, 1, 1}, + {2, 2, 1, 1, 3, 2}, + {2, 2, 1, 2, 3, 1}, /* 20 */ + {2, 1, 3, 2, 1, 2}, + {2, 2, 3, 1, 1, 2}, + {3, 1, 2, 1, 3, 1}, + {3, 1, 1, 2, 2, 2}, + {3, 2, 1, 1, 2, 2}, /* 25 */ + {3, 2, 1, 2, 2, 1}, + {3, 1, 2, 2, 1, 2}, + {3, 2, 2, 1, 1, 2}, + {3, 2, 2, 2, 1, 1}, + {2, 1, 2, 1, 2, 3}, /* 30 */ + {2, 1, 2, 3, 2, 1}, + {2, 3, 2, 1, 2, 1}, + {1, 1, 1, 3, 2, 3}, + {1, 3, 1, 1, 2, 3}, + {1, 3, 1, 3, 2, 1}, /* 35 */ + {1, 1, 2, 3, 1, 3}, + {1, 3, 2, 1, 1, 3}, + {1, 3, 2, 3, 1, 1}, + {2, 1, 1, 3, 1, 3}, + {2, 3, 1, 1, 1, 3}, /* 40 */ + {2, 3, 1, 3, 1, 1}, + {1, 1, 2, 1, 3, 3}, + {1, 1, 2, 3, 3, 1}, + {1, 3, 2, 1, 3, 1}, + {1, 1, 3, 1, 2, 3}, /* 45 */ + {1, 1, 3, 3, 2, 1}, + {1, 3, 3, 1, 2, 1}, + {3, 1, 3, 1, 2, 1}, + {2, 1, 1, 3, 3, 1}, + {2, 3, 1, 1, 3, 1}, /* 50 */ + {2, 1, 3, 1, 1, 3}, + {2, 1, 3, 3, 1, 1}, + {2, 1, 3, 1, 3, 1}, + {3, 1, 1, 1, 2, 3}, + {3, 1, 1, 3, 2, 1}, /* 55 */ + {3, 3, 1, 1, 2, 1}, + {3, 1, 2, 1, 1, 3}, + {3, 1, 2, 3, 1, 1}, + {3, 3, 2, 1, 1, 1}, + {3, 1, 4, 1, 1, 1}, /* 60 */ + {2, 2, 1, 4, 1, 1}, + {4, 3, 1, 1, 1, 1}, + {1, 1, 1, 2, 2, 4}, + {1, 1, 1, 4, 2, 2}, + {1, 2, 1, 1, 2, 4}, /* 65 */ + {1, 2, 1, 4, 2, 1}, + {1, 4, 1, 1, 2, 2}, + {1, 4, 1, 2, 2, 1}, + {1, 1, 2, 2, 1, 4}, + {1, 1, 2, 4, 1, 2}, /* 70 */ + {1, 2, 2, 1, 1, 4}, + {1, 2, 2, 4, 1, 1}, + {1, 4, 2, 1, 1, 2}, + {1, 4, 2, 2, 1, 1}, + {2, 4, 1, 2, 1, 1}, /* 75 */ + {2, 2, 1, 1, 1, 4}, + {4, 1, 3, 1, 1, 1}, + {2, 4, 1, 1, 1, 2}, + {1, 3, 4, 1, 1, 1}, + {1, 1, 1, 2, 4, 2}, /* 80 */ + {1, 2, 1, 1, 4, 2}, + {1, 2, 1, 2, 4, 1}, + {1, 1, 4, 2, 1, 2}, + {1, 2, 4, 1, 1, 2}, + {1, 2, 4, 2, 1, 1}, /* 85 */ + {4, 1, 1, 2, 1, 2}, + {4, 2, 1, 1, 1, 2}, + {4, 2, 1, 2, 1, 1}, + {2, 1, 2, 1, 4, 1}, + {2, 1, 4, 1, 2, 1}, /* 90 */ + {4, 1, 2, 1, 2, 1}, + {1, 1, 1, 1, 4, 3}, + {1, 1, 1, 3, 4, 1}, + {1, 3, 1, 1, 4, 1}, + {1, 1, 4, 1, 1, 3}, /* 95 */ + {1, 1, 4, 3, 1, 1}, + {4, 1, 1, 1, 1, 3}, + {4, 1, 1, 3, 1, 1}, + {1, 1, 3, 1, 4, 1}, + {1, 1, 4, 1, 3, 1}, /* 100 */ + {3, 1, 1, 1, 4, 1}, + {4, 1, 1, 1, 3, 1}, + {2, 1, 1, 4, 1, 2}, + {2, 1, 1, 2, 1, 4}, + {2, 1, 1, 2, 3, 2}, /* 105 */ + {2, 3, 3, 1, 1, 1} + }; +} + +Code128Reader::Code128Reader(){} + +vector Code128Reader::findStartPattern(Ref row){ + int width = row->getSize(); + int rowOffset = row->getNextSet(0); + + int counterPosition = 0; + vector counters (6, 0); + int patternStart = rowOffset; + bool isWhite = false; + int patternLength = counters.size(); + + for (int i = rowOffset; i < width; i++) { + if (row->get(i) ^ isWhite) { + counters[counterPosition]++; + } else { + if (counterPosition == patternLength - 1) { + int bestVariance = MAX_AVG_VARIANCE; + int bestMatch = -1; + for (int startCode = CODE_START_A; startCode <= CODE_START_C; startCode++) { + int variance = patternMatchVariance(counters, CODE_PATTERNS[startCode], MAX_INDIVIDUAL_VARIANCE); + if (variance < bestVariance) { + bestVariance = variance; + bestMatch = startCode; + } + } + // Look for whitespace before start pattern, >= 50% of width of start pattern + if (bestMatch >= 0 && + row->isRange(std::max(0, patternStart - (i - patternStart) / 2), patternStart, false)) { + vector resultValue (3, 0); + resultValue[0] = patternStart; + resultValue[1] = i; + resultValue[2] = bestMatch; + 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 NotFoundException(); +} + +int Code128Reader::decodeCode(Ref row, vector& counters, int rowOffset) { + recordPattern(row, rowOffset, counters); + int bestVariance = MAX_AVG_VARIANCE; // worst variance we'll accept + int bestMatch = -1; + for (int d = 0; d < CODE_PATTERNS_LENGTH; d++) { + int const* const pattern = CODE_PATTERNS[d]; + int variance = patternMatchVariance(counters, pattern, MAX_INDIVIDUAL_VARIANCE); + if (variance < bestVariance) { + bestVariance = variance; + bestMatch = d; + } + } + // TODO We're overlooking the fact that the STOP pattern has 7 values, not 6. + if (bestMatch >= 0) { + return bestMatch; + } else { + throw NotFoundException(); + } +} + +Ref Code128Reader::decodeRow(int rowNumber, Ref row) { + vector startPatternInfo (findStartPattern(row)); + int startCode = startPatternInfo[2]; + int codeSet; + switch (startCode) { + case CODE_START_A: + codeSet = CODE_CODE_A; + break; + case CODE_START_B: + codeSet = CODE_CODE_B; + break; + case CODE_START_C: + codeSet = CODE_CODE_C; + break; + default: + throw FormatException(); + } + + bool done = false; + bool isNextShifted = false; + + string result; + vector rawCodes(20, 0); + + int lastStart = startPatternInfo[0]; + int nextStart = startPatternInfo[1]; + vector counters (6, 0); + + int lastCode = 0; + int code = 0; + int checksumTotal = startCode; + int multiplier = 0; + bool lastCharacterWasPrintable = true; + + std::ostringstream oss; + + while (!done) { + + bool unshift = isNextShifted; + isNextShifted = false; + + // Save off last code + lastCode = code; + + code = decodeCode(row, counters, nextStart); + + // Remember whether the last code was printable or not (excluding CODE_STOP) + if (code != CODE_STOP) { + lastCharacterWasPrintable = true; + } + + // Add to checksum computation (if not CODE_STOP of course) + if (code != CODE_STOP) { + multiplier++; + checksumTotal += multiplier * code; + } + + // Advance to where the next code will to start + lastStart = nextStart; + for (int i = 0, e = counters.size(); i < e; i++) { + nextStart += counters[i]; + } + + // Take care of illegal start codes + switch (code) { + case CODE_START_A: + case CODE_START_B: + case CODE_START_C: + throw FormatException(); + } + + switch (codeSet) { + + case CODE_CODE_A: + if (code < 64) { + result.append(1, (char) (' ' + code)); + } else if (code < 96) { + result.append(1, (char) (code - 64)); + } else { + // Don't let CODE_STOP, which always appears, affect whether whether we think the + // last code was printable or not. + if (code != CODE_STOP) { + lastCharacterWasPrintable = false; + } + switch (code) { + case CODE_FNC_1: + case CODE_FNC_2: + case CODE_FNC_3: + case CODE_FNC_4_A: + // do nothing? + break; + case CODE_SHIFT: + isNextShifted = true; + codeSet = CODE_CODE_B; + break; + case CODE_CODE_B: + codeSet = CODE_CODE_B; + break; + case CODE_CODE_C: + codeSet = CODE_CODE_C; + break; + case CODE_STOP: + done = true; + break; + } + } + break; + case CODE_CODE_B: + if (code < 96) { + result.append(1, (char) (' ' + code)); + } else { + if (code != CODE_STOP) { + lastCharacterWasPrintable = false; + } + switch (code) { + case CODE_FNC_1: + case CODE_FNC_2: + case CODE_FNC_3: + case CODE_FNC_4_B: + // do nothing? + break; + case CODE_SHIFT: + isNextShifted = true; + codeSet = CODE_CODE_A; + break; + case CODE_CODE_A: + codeSet = CODE_CODE_A; + break; + case CODE_CODE_C: + codeSet = CODE_CODE_C; + break; + case CODE_STOP: + done = true; + break; + } + } + break; + case CODE_CODE_C: + if (code < 100) { + if (code < 10) { + result.append(1, '0'); + } + oss.clear(); + oss.str(""); + oss << code; + result.append(oss.str()); + } else { + if (code != CODE_STOP) { + lastCharacterWasPrintable = false; + } + switch (code) { + case CODE_FNC_1: + // do nothing? + break; + case CODE_CODE_A: + codeSet = CODE_CODE_A; + break; + case CODE_CODE_B: + codeSet = CODE_CODE_B; + break; + case CODE_STOP: + done = true; + break; + } + } + break; + } + + // Unshift back to another code set if we were shifted + if (unshift) { + codeSet = codeSet == CODE_CODE_A ? CODE_CODE_B : CODE_CODE_A; + } + + } + + // Check for ample whitespace following pattern, but, to do this we first need to remember that + // we fudged decoding CODE_STOP since it actually has 7 bars, not 6. There is a black bar left + // to read off. Would be slightly better to properly read. Here we just skip it: + nextStart = row->getNextUnset(nextStart); + if (!row->isRange(nextStart, + std::min(row->getSize(), nextStart + (nextStart - lastStart) / 2), + false)) { + throw NotFoundException(); + } + + // Pull out from sum the value of the penultimate check code + checksumTotal -= multiplier * lastCode; + // lastCode is the checksum then: + if (checksumTotal % 103 != lastCode) { + throw ChecksumException(); + } + + // Need to pull out the check digits from string + int resultLength = result.length(); + if (resultLength == 0) { + // false positive + throw NotFoundException(); + } + + // Only bother if the result had at least one character, and if the checksum digit happened to + // be a printable character. If it was just interpreted as a control code, nothing to remove. + if (resultLength > 0 && lastCharacterWasPrintable) { + if (codeSet == CODE_CODE_C) { + result.erase(resultLength - 2, resultLength); + } else { + result.erase(resultLength - 1, resultLength); + } + } + + float left = (float) (startPatternInfo[1] + startPatternInfo[0]) / 2.0f; + float right = (float) (nextStart + lastStart) / 2.0f; + + int rawCodesSize = rawCodes.size(); + ArrayRef rawBytes (rawCodesSize); + for (int i = 0; i < rawCodesSize; i++) { + rawBytes[i] = rawCodes[i]; + } + + ArrayRef< Ref > resultPoints(2); + resultPoints[0] = + Ref(new OneDResultPoint(left, (float) rowNumber)); + resultPoints[1] = + Ref(new OneDResultPoint(right, (float) rowNumber)); + + return Ref(new Result(Ref(new String(result)), rawBytes, resultPoints, + BarcodeFormat::CODE_128)); +} + +Code128Reader::~Code128Reader(){} + +zxing::BarcodeFormat Code128Reader::getBarcodeFormat(){ + return BarcodeFormat::CODE_128; } diff --git a/cpp/core/src/zxing/oned/Code128Reader.h b/cpp/core/src/zxing/oned/Code128Reader.h index 065bd2f48..43232ec29 100644 --- a/cpp/core/src/zxing/oned/Code128Reader.h +++ b/cpp/core/src/zxing/oned/Code128Reader.h @@ -23,38 +23,26 @@ namespace zxing { namespace oned { - class Code128Reader : public OneDReader { - - private: - enum {MAX_AVG_VARIANCE = (unsigned int) (PATTERN_MATCH_RESULT_SCALE_FACTOR * 250/1000)}; - enum {MAX_INDIVIDUAL_VARIANCE = (int) (PATTERN_MATCH_RESULT_SCALE_FACTOR * 700/1000)}; - static const int CODE_SHIFT = 98; - - static const int CODE_CODE_C = 99; - static const int CODE_CODE_B = 100; - static const int CODE_CODE_A = 101; - - static const int CODE_FNC_1 = 102; - static const int CODE_FNC_2 = 97; - static const int CODE_FNC_3 = 96; - static const int CODE_FNC_4_A = 101; - static const int CODE_FNC_4_B = 100; - - static const int CODE_START_A = 103; - static const int CODE_START_B = 104; - static const int CODE_START_C = 105; - static const int CODE_STOP = 106; - - static int* findStartPattern(Ref row); - static int decodeCode(Ref row, int counters[], int countersCount, int rowOffset); - - void append(char* s, char c); - public: - Ref decodeRow(int rowNumber, Ref row); - Code128Reader(); - ~Code128Reader(); - }; - } + class Code128Reader; + } } +class zxing::oned::Code128Reader : public OneDReader { +private: + static const int MAX_AVG_VARIANCE; + static const int MAX_INDIVIDUAL_VARIANCE; + + static std::vector findStartPattern(Ref row); + static int decodeCode(Ref row, + std::vector& counters, + int rowOffset); + +public: + Ref decodeRow(int rowNumber, Ref row); + Code128Reader(); + ~Code128Reader(); + + BarcodeFormat getBarcodeFormat(); +}; + #endif diff --git a/cpp/core/src/zxing/oned/Code39Reader.cpp b/cpp/core/src/zxing/oned/Code39Reader.cpp index 5f2244edd..33e8086e6 100644 --- a/cpp/core/src/zxing/oned/Code39Reader.cpp +++ b/cpp/core/src/zxing/oned/Code39Reader.cpp @@ -19,14 +19,21 @@ #include #include #include +#include +#include #include #include -namespace zxing { -namespace oned { - - static const char* ALPHABET = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ-. *$/+%"; +using std::vector; +using zxing::Ref; +using zxing::Result; +using zxing::String; +using zxing::NotFoundException; +using zxing::ChecksumException; +using zxing::oned::Code39Reader; +namespace { + const char* ALPHABET = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ-. *$/+%"; /** * These represent the encodings of characters, as patterns of wide and narrow @@ -35,7 +42,7 @@ namespace oned { * and narrow, with 1s representing "wide" and 0s representing narrow. */ const int CHARACTER_ENCODINGS_LEN = 44; - static int CHARACTER_ENCODINGS[CHARACTER_ENCODINGS_LEN] = { + 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 @@ -43,305 +50,269 @@ namespace oned { 0x0A8, 0x0A2, 0x08A, 0x02A // $-% }; - static int ASTERISK_ENCODING = 0x094; - static const char* ALPHABET_STRING = + int ASTERISK_ENCODING = 0x094; + 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) { +} - /** - * 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) { +Code39Reader::Code39Reader(bool usingCheckDigit_, bool extendedMode_) : + alphabet_string(ALPHABET_STRING), + usingCheckDigit(usingCheckDigit_), + extendedMode(extendedMode_) { } - /** - * 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) { + vector counters (9, 0); + vector start (findAsteriskPattern(row, counters)); + // Read off white space + int nextStart = row->getNextSet(start[1]); + int end = row->getSize(); - - Code39Reader::Code39Reader(bool usingCheckDigit_, bool extendedMode_) : - alphabet_string(ALPHABET_STRING), - usingCheckDigit(usingCheckDigit_), - extendedMode(extendedMode_) { - } - - Ref Code39Reader::decodeRow(int rowNumber, Ref row) { - int* start = NULL; - try { - start = findAsteriskPattern(row); - int nextStart = start[1]; - int end = row->getSize(); - - // Read off white space - while (nextStart < end && !row->get(nextStart)) { - nextStart++; - } - - std::string tmpResultString; - - const int countersLen = 9; - int counters[countersLen]; - for (int i = 0; i < countersLen; i++) { - counters[i] = 0; - } - char decodedChar; - int lastStart; - do { - if (!recordPattern(row, nextStart, counters, countersLen)) { - throw ReaderException(""); - } - int pattern = toNarrowWidePattern(counters, countersLen); - if (pattern < 0) { - throw ReaderException("pattern < 0"); - } - decodedChar = patternToChar(pattern); - tmpResultString.append(1, decodedChar); - lastStart = nextStart; - for (int i = 0; i < countersLen; i++) { - nextStart += counters[i]; - } - // Read off white space - while (nextStart < end && !row->get(nextStart)) { - nextStart++; - } - } while (decodedChar != '*'); - tmpResultString.erase(tmpResultString.length()-1, 1);// remove asterisk - - // Look for whitespace after pattern: - int lastPatternSize = 0; - for (int i = 0; i < countersLen; i++) { - lastPatternSize += counters[i]; - } - int whiteSpaceAfterEnd = nextStart - lastStart - lastPatternSize; - // If 50% of last pattern size, following last pattern, is not whitespace, - // fail (but if it's whitespace to the very end of the image, that's OK) - if (nextStart != end && whiteSpaceAfterEnd / 2 < lastPatternSize) { - throw ReaderException("too short end white space"); - } - - if (usingCheckDigit) { - int max = tmpResultString.length() - 1; - unsigned int total = 0; - for (int i = 0; i < max; i++) { - total += alphabet_string.find_first_of(tmpResultString[i], 0); - } - if (total % 43 != alphabet_string.find_first_of(tmpResultString[max], 0)) { - throw ReaderException(""); - } - tmpResultString.erase(max, 1); - } - - Ref resultString(new String(tmpResultString)); - if (extendedMode) { - 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); - - Ref res(new Result( - resultString, resultBytes, resultPoints, BarcodeFormat_CODE_39)); - - delete [] start; - return res; - } catch (ReaderException const& re) { - delete [] start; - return Ref(); + std::string result; + char decodedChar; + int lastStart; + do { + recordPattern(row, nextStart, counters); + int pattern = toNarrowWidePattern(counters); + if (pattern < 0) { + throw NotFoundException();; } + decodedChar = patternToChar(pattern); + result.append(1, decodedChar); + lastStart = nextStart; + for (int i = 0, end=counters.size(); i < end; i++) { + nextStart += counters[i]; + } + // Read off white space + + nextStart = row->getNextSet(nextStart); + } while (decodedChar != '*'); + result.resize(result.length()-1);// remove asterisk + + // Look for whitespace after pattern: + int lastPatternSize = 0; + for (int i = 0, e = counters.size(); i < e; 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 >> 1) < lastPatternSize) { + throw NotFoundException(); } - int* Code39Reader::findAsteriskPattern(Ref row){ - int width = row->getSize(); - int rowOffset = 0; - while (rowOffset < width) { - if (row->get(rowOffset)) { - break; - } - rowOffset++; + if (usingCheckDigit) { + int max = result.length() - 1; + int total = 0; + for (int i = 0; i < max; i++) { + total += alphabet_string.find_first_of(result[i], 0); } - - int counterPosition = 0; - const int countersLen = 9; - int counters[countersLen]; - for (int i = 0; i < countersLen; i++) { - counters[i] = 0; + if (result[max] != ALPHABET[total % 43]) { + throw ChecksumException(); } - int patternStart = rowOffset; - bool isWhite = false; - int patternLength = countersLen; + result.resize(max); + } + + if (result.length() == 0) { + // Almost false positive + throw NotFoundException(); + } + + Ref resultString; + if (extendedMode) { + resultString = decodeExtended(result); + } else { + resultString = Ref(new String(result)); + } - for (int i = rowOffset; i < width; i++) { - bool pixel = row->get(i); - if (pixel ^ isWhite) { - counters[counterPosition]++; + float left = (float) (start[1] + start[0]) / 2.0f; + float right = (float) (nextStart + lastStart) / 2.0f; + + ArrayRef< Ref > resultPoints (2); + resultPoints[0] = + Ref(new OneDResultPoint(left, (float) rowNumber)); + resultPoints[1] = + Ref(new OneDResultPoint(right, (float) rowNumber)); + + return Ref( + new Result(resultString, ArrayRef(), resultPoints, BarcodeFormat::CODE_39) + ); +} + +vector Code39Reader::findAsteriskPattern(Ref row, + vector& counters){ + int width = row->getSize(); + int rowOffset = row->getNextSet(0); + + int counterPosition = 0; + int patternStart = rowOffset; + bool isWhite = false; + int patternLength = counters.size(); + + for (int i = rowOffset; i < width; i++) { + if (row->get(i) ^ isWhite) { + counters[counterPosition]++; + } else { + if (counterPosition == patternLength - 1) { + // Look for whitespace before start pattern, >= 50% of width of + // start pattern. + if (toNarrowWidePattern(counters) == ASTERISK_ENCODING && + row->isRange(std::max(0, patternStart - ((i - patternStart) >> 1)), patternStart, false)) { + vector resultValue (2, 0); + 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 { - if (counterPosition == patternLength - 1) { - // Look for whitespace before start pattern, >= 50% of width of - // start pattern. - if (toNarrowWidePattern(counters, countersLen) == ASTERISK_ENCODING && - row->isRange(std::max(0, patternStart - ((i - patternStart) >> 1)), 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; + counterPosition++; + } + counters[counterPosition] = 1; + isWhite = !isWhite; + } + } + throw NotFoundException(); +} + +// 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(vector& counters){ + int numCounters = counters.size(); + 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; } } - 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; } - maxNarrowCounter = minCounter; - wideCounters = 0; - int totalWideCountersWidth = 0; - int pattern = 0; - for (int i = 0; i < numCounters; i++) { + } + 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) { - 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; - } + 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]; } + return pattern; } - throw ReaderException(""); - } + } while (wideCounters > 3); + return -1; +} - 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; +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(""); } - tmpDecoded.append(1, decodedChar); - // bump up i again since we read two characters - i++; - } else { - tmpDecoded.append(1, c); + 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 decoded(new String(tmpDecoded)); + return decoded; +} diff --git a/cpp/core/src/zxing/oned/Code39Reader.h b/cpp/core/src/zxing/oned/Code39Reader.h index b306008e0..c68204813 100644 --- a/cpp/core/src/zxing/oned/Code39Reader.h +++ b/cpp/core/src/zxing/oned/Code39Reader.h @@ -1,3 +1,4 @@ +// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*- #ifndef __CODE_39_READER_H__ #define __CODE_39_READER_H__ /* @@ -24,35 +25,37 @@ #include namespace zxing { - namespace oned { - - /** - *

Decodes Code 39 barcodes. This does not support "Full ASCII Code 39" yet.

- * Ported form Java (author Sean Owen) - * @author Lukasz Warchol - */ - class Code39Reader : public OneDReader { - - private: - std::string alphabet_string; - - bool usingCheckDigit; - bool extendedMode; - - static int* findAsteriskPattern(Ref row); //throws ReaderException - static int toNarrowWidePattern(int counters[], int countersLen); - static char patternToChar(int pattern); //throws ReaderException - static Ref decodeExtended(std::string encoded); //throws ReaderException - - void append(char* s, char c); - public: - Code39Reader(); - Code39Reader(bool usingCheckDigit_); - Code39Reader(bool usingCheckDigit_, bool extendedMode_); - - Ref decodeRow(int rowNumber, Ref row); - }; - } + namespace oned { + class Code39Reader; + } } +/** + *

Decodes Code 39 barcodes. This does not support "Full ASCII Code 39" yet.

+ * Ported form Java (author Sean Owen) + * @author Lukasz Warchol + */ +class zxing::oned::Code39Reader : public OneDReader { + +private: + std::string alphabet_string; + + bool usingCheckDigit; + bool extendedMode; + + static std::vector findAsteriskPattern(Ref row, + std::vector& counters); + static int toNarrowWidePattern(std::vector& counters); + static char patternToChar(int pattern); + static Ref decodeExtended(std::string encoded); + + void append(char* s, char c); +public: + Code39Reader(); + Code39Reader(bool usingCheckDigit_); + Code39Reader(bool usingCheckDigit_, bool extendedMode_); + + Ref decodeRow(int rowNumber, Ref row); +}; + #endif diff --git a/cpp/core/src/zxing/oned/Code93Reader.cpp b/cpp/core/src/zxing/oned/Code93Reader.cpp new file mode 100644 index 000000000..abbc3b50f --- /dev/null +++ b/cpp/core/src/zxing/oned/Code93Reader.cpp @@ -0,0 +1,268 @@ +// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*- +/* + * 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 "Code93Reader.h" +#include +#include +#include +#include +#include +#include +#include +#include + +using std::vector; +using std::string; +using zxing::Ref; +using zxing::Result; +using zxing::String; +using zxing::NotFoundException; +using zxing::ChecksumException; +using zxing::oned::Code93Reader; + +namespace { + char const ALPHABET[] = + "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ-. $/+%abcd*"; + string ALPHABET_STRING (ALPHABET); + + /** + * 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. + */ + int const CHARACTER_ENCODINGS[] = { + 0x114, 0x148, 0x144, 0x142, 0x128, 0x124, 0x122, 0x150, 0x112, 0x10A, // 0-9 + 0x1A8, 0x1A4, 0x1A2, 0x194, 0x192, 0x18A, 0x168, 0x164, 0x162, 0x134, // A-J + 0x11A, 0x158, 0x14C, 0x146, 0x12C, 0x116, 0x1B4, 0x1B2, 0x1AC, 0x1A6, // K-T + 0x196, 0x19A, 0x16C, 0x166, 0x136, 0x13A, // U-Z + 0x12E, 0x1D4, 0x1D2, 0x1CA, 0x16E, 0x176, 0x1AE, // - - % + 0x126, 0x1DA, 0x1D6, 0x132, 0x15E, // Control chars? $-* + }; + int const CHARACTER_ENCODINGS_LENGTH = + (int)sizeof(CHARACTER_ENCODINGS)/sizeof(CHARACTER_ENCODINGS[0]); + const int ASTERISK_ENCODING = CHARACTER_ENCODINGS[47]; +} + +Ref Code93Reader::decodeRow(int rowNumber, Ref row) { + Range start (findAsteriskPattern(row)); + // Read off white space + int nextStart = row->getNextSet(start[1]); + int end = row->getSize(); + + string result; + vector counters (6, 0); + char decodedChar; + int lastStart; + do { + recordPattern(row, nextStart, counters); + int pattern = toPattern(counters); + if (pattern < 0) { + throw NotFoundException::getNotFoundInstance(); + } + decodedChar = patternToChar(pattern); + result.append(1, decodedChar); + lastStart = nextStart; + for(int i=0, e=counters.size(); i < e; ++i) { + nextStart += counters[i]; + } + // Read off white space + nextStart = row->getNextSet(nextStart); + } while (decodedChar != '*'); + result.resize(result.length() - 1); // remove asterisk + + // Should be at least one more black module + if (nextStart == end || !row->get(nextStart)) { + throw NotFoundException::getNotFoundInstance(); + } + + if (result.length() < 2) { + // false positive -- need at least 2 checksum digits + throw NotFoundException::getNotFoundInstance(); + } + + checkChecksums(result); + // Remove checksum digits + result.resize(result.length() - 2); + + Ref resultString = decodeExtended(result); + + float left = (float) (start[1] + start[0]) / 2.0f; + float right = (float) (nextStart + lastStart) / 2.0f; + + ArrayRef< Ref > resultPoints (2); + resultPoints[0] = + Ref(new OneDResultPoint(left, (float) rowNumber)); + resultPoints[1] = + Ref(new OneDResultPoint(right, (float) rowNumber)); + + return Ref(new Result( + resultString, + ArrayRef(), + resultPoints, + BarcodeFormat::CODE_93)); +} + +Code93Reader::Range Code93Reader::findAsteriskPattern(Ref row) { + int width = row->getSize(); + int rowOffset = row->getNextSet(0); + + int counterPosition = 0; + vector counters (6, 0); + int patternStart = rowOffset; + bool isWhite = false; + int patternLength = counters.size(); + + for (int i = rowOffset; i < width; i++) { + if (row->get(i) ^ isWhite) { + counters[counterPosition]++; + } else { + if (counterPosition == patternLength - 1) { + if (toPattern(counters) == ASTERISK_ENCODING) { + return Range(patternStart, i); + } + 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 NotFoundException::getNotFoundInstance(); +} + +int Code93Reader::toPattern(vector& counters) { + int max = counters.size(); + int sum = 0; + for(int i=0, e=counters.size(); i> INTEGER_MATH_SHIFT; + if ((scaledShifted & 0xFF) > 0x7F) { + scaledUnshifted++; + } + if (scaledUnshifted < 1 || scaledUnshifted > 4) { + return -1; + } + if ((i & 0x01) == 0) { + for (int j = 0; j < scaledUnshifted; j++) { + pattern = (pattern << 1) | 0x01; + } + } else { + pattern <<= scaledUnshifted; + } + } + return pattern; +} + +char Code93Reader::patternToChar(int pattern) { + for (int i = 0; i < CHARACTER_ENCODINGS_LENGTH; i++) { + if (CHARACTER_ENCODINGS[i] == pattern) { + return ALPHABET[i]; + } + } + throw NotFoundException::getNotFoundInstance(); +} + +Ref Code93Reader::decodeExtended(string const& encoded) { + int length = encoded.length(); + string decoded; + for (int i = 0; i < length; i++) { + char c = encoded[i]; + if (c >= 'a' && c <= 'd') { + if (i >= length - 1) { + throw FormatException::getFormatInstance(); + } + char next = encoded[i + 1]; + char decodedChar = '\0'; + switch (c) { + case 'd': + // +A to +Z map to a to z + if (next >= 'A' && next <= 'Z') { + decodedChar = (char) (next + 32); + } else { + throw FormatException::getFormatInstance(); + } + break; + case 'a': + // $A to $Z map to control codes SH to SB + if (next >= 'A' && next <= 'Z') { + decodedChar = (char) (next - 64); + } else { + throw FormatException::getFormatInstance(); + } + break; + case 'b': + // %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 FormatException::getFormatInstance(); + } + break; + case 'c': + // /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 FormatException::getFormatInstance(); + } + break; + } + decoded.append(1, decodedChar); + // bump up i again since we read two characters + i++; + } else { + decoded.append(1, c); + } + } + return Ref(new String(decoded)); +} + +void Code93Reader::checkChecksums(string const& result) { + int length = result.length(); + checkOneChecksum(result, length - 2, 20); + checkOneChecksum(result, length - 1, 15); +} + +void Code93Reader::checkOneChecksum(string const& result, + int checkPosition, + int weightMax) { + int weight = 1; + int total = 0; + for (int i = checkPosition - 1; i >= 0; i--) { + total += weight * ALPHABET_STRING.find_first_of(result[i]); + if (++weight > weightMax) { + weight = 1; + } + } + if (result[checkPosition] != ALPHABET[total % 47]) { + throw ChecksumException::getChecksumInstance(); + } +} diff --git a/cpp/core/src/zxing/oned/Code93Reader.h b/cpp/core/src/zxing/oned/Code93Reader.h new file mode 100644 index 000000000..e5e0e62cc --- /dev/null +++ b/cpp/core/src/zxing/oned/Code93Reader.h @@ -0,0 +1,53 @@ +// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*- +#ifndef __CODE_93_READER_H__ +#define __CODE_93_READER_H__ +/* + * Code93Reader.h + * ZXing + * + * 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 oned { + class Code93Reader; + } +} + +/** + *

Decodes Code 93 barcodes. This does not support "Full ASCII Code 93" yet.

+ * Ported form Java (author Sean Owen) + * @author Lukasz Warchol + */ +class zxing::oned::Code93Reader : public OneDReader { +public: + Ref decodeRow(int rowNumber, Ref row); + +private: + static Range findAsteriskPattern(Ref row); + static int toPattern(std::vector& counters); + static char patternToChar(int pattern); + static Ref decodeExtended(std::string const& encoded); + static void checkChecksums(std::string const& result); + static void checkOneChecksum(std::string const& result, + int checkPosition, + int weightMax); +}; + +#endif diff --git a/cpp/core/src/zxing/oned/EAN13Reader.cpp b/cpp/core/src/zxing/oned/EAN13Reader.cpp index 48f440321..9907f46d3 100644 --- a/cpp/core/src/zxing/oned/EAN13Reader.cpp +++ b/cpp/core/src/zxing/oned/EAN13Reader.cpp @@ -16,79 +16,76 @@ */ #include "EAN13Reader.h" -#include +#include -namespace zxing { - namespace oned { +using std::vector; +using zxing::Ref; +using zxing::BitArray; +using zxing::oned::EAN13Reader; - static const int FIRST_DIGIT_ENCODINGS[10] = { - 0x00, 0x0B, 0x0D, 0xE, 0x13, 0x19, 0x1C, 0x15, 0x16, 0x1A - }; +namespace { + const int FIRST_DIGIT_ENCODINGS[10] = { + 0x00, 0x0B, 0x0D, 0xE, 0x13, 0x19, 0x1C, 0x15, 0x16, 0x1A + }; +} - EAN13Reader::EAN13Reader() { } +EAN13Reader::EAN13Reader() : decodeMiddleCounters(4, 0) { } - int EAN13Reader::decodeMiddle(Ref row, int startGuardBegin, int startGuardEnd, - std::string& resultString) { - (void)startGuardBegin; - const int countersLen = 4; - int counters[countersLen] = { 0, 0, 0, 0 }; +int EAN13Reader::decodeMiddle(Ref row, + Range const& startRange, + std::string& resultString) { + if (false) { + std::cerr << "ba " + << startRange[0] << " " + << startRange[1] << " " + << *row << std::endl; + } + vector& counters (decodeMiddleCounters); + counters.clear(); + counters.resize(4); + int end = row->getSize(); + int rowOffset = startRange[1]; - int end = row->getSize(); - int rowOffset = startGuardEnd; - int lgPatternFound = 0; + int lgPatternFound = 0; - for (int x = 0; x < 6 && rowOffset < end; x++) { - int bestMatch = decodeDigit(row, counters, countersLen, rowOffset, - UPC_EAN_PATTERNS_L_AND_G_PATTERNS); - if (bestMatch < 0) { - return -1; - } - resultString.append(1, (char) ('0' + bestMatch % 10)); - for (int i = 0; i < countersLen; i++) { - rowOffset += counters[i]; - } - if (bestMatch >= 10) { - lgPatternFound |= 1 << (5 - x); - } - } - - if (!determineFirstDigit(resultString, lgPatternFound)) { - return -1; - } - - int middleRangeStart; - int middleRangeEnd; - if (findGuardPattern(row, rowOffset, true, (int*)getMIDDLE_PATTERN(), - getMIDDLE_PATTERN_LEN(), &middleRangeStart, &middleRangeEnd)) { - rowOffset = middleRangeEnd; - for (int x = 0; x < 6 && rowOffset < end; x++) { - int bestMatch = decodeDigit(row, counters, countersLen, rowOffset, - UPC_EAN_PATTERNS_L_PATTERNS); - if (bestMatch < 0) { - return -1; - } - resultString.append(1, (char) ('0' + bestMatch)); - for (int i = 0; i < countersLen; i++) { - rowOffset += counters[i]; - } - } - return rowOffset; - } - return -1; + for (int x = 0; x < 6 && rowOffset < end; x++) { + int bestMatch = decodeDigit(row, counters, rowOffset, L_AND_G_PATTERNS); + resultString.append(1, (char) ('0' + bestMatch % 10)); + for (int i = 0, end = counters.size(); i = 10) { + lgPatternFound |= 1 << (5 - x); } } + + determineFirstDigit(resultString, lgPatternFound); + + Range middleRange = findGuardPattern(row, rowOffset, true, MIDDLE_PATTERN) ; + rowOffset = middleRange[1]; + + for (int x = 0; x < 6 && rowOffset < end; x++) { + int bestMatch = + decodeDigit(row, counters, rowOffset, L_PATTERNS); + resultString.append(1, (char) ('0' + bestMatch)); + for (int i = 0, end = counters.size(); i < end; i++) { + rowOffset += counters[i]; + } + } + return rowOffset; +} + +void EAN13Reader::determineFirstDigit(std::string& resultString, int lgPatternFound) { + // std::cerr << "K " << resultString << " " << lgPatternFound << " " < row, int startGuardBegin, int startGuardEnd, - std::string& resultString); - - BarcodeFormat getBarcodeFormat(); - }; + class EAN13Reader; } } +class zxing::oned::EAN13Reader : public UPCEANReader { +private: + std::vector decodeMiddleCounters; + static void determineFirstDigit(std::string& resultString, + int lgPatternFound); + +public: + EAN13Reader(); + + int decodeMiddle(Ref row, + Range const& startRange, + std::string& resultString); + + BarcodeFormat getBarcodeFormat(); +}; + #endif diff --git a/cpp/core/src/zxing/oned/EAN8Reader.cpp b/cpp/core/src/zxing/oned/EAN8Reader.cpp index 2568948cb..9849e3d5f 100644 --- a/cpp/core/src/zxing/oned/EAN8Reader.cpp +++ b/cpp/core/src/zxing/oned/EAN8Reader.cpp @@ -18,55 +18,44 @@ #include "EAN8Reader.h" #include -namespace zxing { - namespace oned { +using std::vector; +using zxing::oned::EAN8Reader; - EAN8Reader::EAN8Reader(){ } +EAN8Reader::EAN8Reader() : decodeMiddleCounters(4, 0) { } - int EAN8Reader::decodeMiddle(Ref row, int startGuardBegin, int startGuardEnd, - std::string& resultString){ - (void)startGuardBegin; - const int countersLen = 4; - int counters[countersLen] = { 0, 0, 0, 0 }; +int EAN8Reader::decodeMiddle(Ref row, + Range const& startRange, + std::string& result){ + vector& counters (decodeMiddleCounters); + counters[0] = 0; + counters[1] = 0; + counters[2] = 0; + counters[3] = 0; - int end = row->getSize(); - int rowOffset = startGuardEnd; + int end = row->getSize(); + int rowOffset = startRange[1]; - for (int x = 0; x < 4 && rowOffset < end; x++) { - int bestMatch = decodeDigit(row, counters, countersLen, rowOffset, - UPC_EAN_PATTERNS_L_PATTERNS); - if (bestMatch < 0) { - return -1; - } - resultString.append(1, (char) ('0' + bestMatch)); - for (int i = 0; i < countersLen; i++) { - rowOffset += counters[i]; - } - } - - int middleRangeStart; - int middleRangeEnd; - if (findGuardPattern(row, rowOffset, true, (int*)getMIDDLE_PATTERN(), - getMIDDLE_PATTERN_LEN(), &middleRangeStart, &middleRangeEnd)) { - rowOffset = middleRangeEnd; - for (int x = 0; x < 4 && rowOffset < end; x++) { - int bestMatch = decodeDigit(row, counters, countersLen, rowOffset, - UPC_EAN_PATTERNS_L_PATTERNS); - if (bestMatch < 0) { - return -1; - } - resultString.append(1, (char) ('0' + bestMatch)); - for (int i = 0; i < countersLen; i++) { - rowOffset += counters[i]; - } - } - return rowOffset; - } - return -1; - } - - BarcodeFormat EAN8Reader::getBarcodeFormat(){ - return BarcodeFormat_EAN_8; + for (int x = 0; x < 4 && rowOffset < end; x++) { + int bestMatch = decodeDigit(row, counters, rowOffset, L_PATTERNS); + result.append(1, (char) ('0' + bestMatch)); + for (int i = 0, end = counters.size(); i < end; i++) { + rowOffset += counters[i]; } } + + Range middleRange = + findGuardPattern(row, rowOffset, true, MIDDLE_PATTERN); + rowOffset = middleRange[1]; + for (int x = 0; x < 4 && rowOffset < end; x++) { + int bestMatch = decodeDigit(row, counters, rowOffset, L_PATTERNS); + result.append(1, (char) ('0' + bestMatch)); + for (int i = 0, end = counters.size(); i < end; i++) { + rowOffset += counters[i]; + } + } + return rowOffset; +} + +zxing::BarcodeFormat EAN8Reader::getBarcodeFormat(){ + return BarcodeFormat::EAN_8; } diff --git a/cpp/core/src/zxing/oned/EAN8Reader.h b/cpp/core/src/zxing/oned/EAN8Reader.h index 4db52fba8..99ae97785 100644 --- a/cpp/core/src/zxing/oned/EAN8Reader.h +++ b/cpp/core/src/zxing/oned/EAN8Reader.h @@ -1,3 +1,4 @@ +// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*- #ifndef __EAN_8_READER_H__ #define __EAN_8_READER_H__ @@ -25,17 +26,21 @@ namespace zxing { namespace oned { - class EAN8Reader : public UPCEANReader { - - public: - EAN8Reader(); - - int decodeMiddle(Ref row, int startGuardBegin, int startGuardEnd, - std::string& resultString); - - BarcodeFormat getBarcodeFormat(); - }; + class EAN8Reader; } } +class zxing::oned::EAN8Reader : public UPCEANReader { + std::vector decodeMiddleCounters; + +public: + EAN8Reader(); + + int decodeMiddle(Ref row, + Range const& startRange, + std::string& resultString); + + BarcodeFormat getBarcodeFormat(); +}; + #endif diff --git a/cpp/core/src/zxing/oned/ITFReader.cpp b/cpp/core/src/zxing/oned/ITFReader.cpp index 1fa72673e..d8a5abe9e 100644 --- a/cpp/core/src/zxing/oned/ITFReader.cpp +++ b/cpp/core/src/zxing/oned/ITFReader.cpp @@ -19,227 +19,216 @@ #include #include #include +#include +#include #include -namespace zxing { - namespace oned { +using std::vector; +using zxing::Ref; +using zxing::ArrayRef; +using zxing::Array; +using zxing::Result; +using zxing::FormatException; +using zxing::NotFoundException; +using zxing::oned::ITFReader; - static const int W = 3; // Pixel width of a wide line - static const int N = 1; // Pixed width of a narrow line +#define VECTOR_INIT(v) v, v + sizeof(v)/sizeof(v[0]) - const int DEFAULT_ALLOWED_LENGTHS_LEN = 10; - const int DEFAULT_ALLOWED_LENGTHS[DEFAULT_ALLOWED_LENGTHS_LEN] = { 44, 24, 20, 18, 16, 14, 12, 10, 8, 6 }; +namespace { - /** - * Start/end guard pattern. - * - * Note: The end pattern is reversed because the row is reversed before - * searching for the END_PATTERN - */ - static const int START_PATTERN_LEN = 4; - static const int START_PATTERN[START_PATTERN_LEN] = {N, N, N, N}; + const int W = 3; // Pixel width of a wide line + const int N = 1; // Pixed width of a narrow line - static const int END_PATTERN_REVERSED_LEN = 3; - static const int END_PATTERN_REVERSED[END_PATTERN_REVERSED_LEN] = {N, N, W}; + const int DEFAULT_ALLOWED_LENGTHS_LEN = 10; + const int DEFAULT_ALLOWED_LENGTHS_[DEFAULT_ALLOWED_LENGTHS_LEN] = { 44, 24, 20, 18, 16, 14, 12, 10, 8, 6 }; + const ArrayRef DEFAULT_ALLOWED_LENGTHS (new Array(DEFAULT_ALLOWED_LENGTHS_, + DEFAULT_ALLOWED_LENGTHS_LEN )); - /** - * Patterns of Wide / Narrow lines to indicate each digit - */ - static const int PATTERNS_LEN = 10; - static const int PATTERNS[PATTERNS_LEN][5] = { - {N, N, W, W, N}, // 0 - {W, N, N, N, W}, // 1 - {N, W, N, N, W}, // 2 - {W, W, N, N, N}, // 3 - {N, N, W, N, W}, // 4 - {W, N, W, N, N}, // 5 - {N, W, W, N, N}, // 6 - {N, N, N, W, W}, // 7 - {W, N, N, W, N}, // 8 - {N, W, N, W, N} // 9 - }; + /** + * Start/end guard pattern. + * + * Note: The end pattern is reversed because the row is reversed before + * searching for the END_PATTERN + */ + const int START_PATTERN_LEN = 4; + const int START_PATTERN_[START_PATTERN_LEN] = {N, N, N, N}; + const vector START_PATTERN (VECTOR_INIT(START_PATTERN_)); + + const int END_PATTERN_REVERSED_LEN = 3; + const int END_PATTERN_REVERSED_[END_PATTERN_REVERSED_LEN] = {N, N, W}; + const vector END_PATTERN_REVERSED (VECTOR_INIT(END_PATTERN_REVERSED_)); + + /** + * Patterns of Wide / Narrow lines to indicate each digit + */ + const int PATTERNS_LEN = 10; + const int PATTERNS[PATTERNS_LEN][5] = { + {N, N, W, W, N}, // 0 + {W, N, N, N, W}, // 1 + {N, W, N, N, W}, // 2 + {W, W, N, N, N}, // 3 + {N, N, W, N, W}, // 4 + {W, N, W, N, N}, // 5 + {N, W, W, N, N}, // 6 + {N, N, N, W, W}, // 7 + {W, N, N, W, N}, // 8 + {N, W, N, W, N} // 9 + }; + +} + +ITFReader::ITFReader() : narrowLineWidth(-1) { +} - ITFReader::ITFReader() : narrowLineWidth(-1) { +Ref ITFReader::decodeRow(int rowNumber, Ref row) { + // Find out where the Middle section (payload) starts & ends + + Range startRange = decodeStart(row); + Range endRange = decodeEnd(row); + + std::string result; + decodeMiddle(row, startRange[1], endRange[0], result); + Ref resultString(new String(result)); + + ArrayRef allowedLengths; + // Java hints stuff missing + if (!allowedLengths) { + allowedLengths = DEFAULT_ALLOWED_LENGTHS; + } + + // To avoid false positives with 2D barcodes (and other patterns), make + // an assumption that the decoded string must be 6, 10 or 14 digits. + int length = resultString->size(); + bool lengthOK = false; + for (int i = 0, e = allowedLengths->size(); i < e; i++) { + if (length == allowedLengths[i]) { + lengthOK = true; + break; + } + } + if (!lengthOK) { + throw FormatException(); + } + + ArrayRef< Ref > resultPoints(2); + resultPoints[0] = Ref(new OneDResultPoint(startRange[1], (float) rowNumber)); + resultPoints[1] = Ref(new OneDResultPoint(endRange[0], (float) rowNumber)); + return Ref(new Result(resultString, ArrayRef(), resultPoints, BarcodeFormat::ITF)); +} + +/** + * @param row row of black/white values to search + * @param payloadStart offset of start pattern + * @param resultString {@link StringBuffer} to append decoded chars to + * @throws ReaderException if decoding could not complete successfully + */ +void ITFReader::decodeMiddle(Ref row, + int payloadStart, + int payloadEnd, + std::string& resultString) { + // Digits are interleaved in pairs - 5 black lines for one digit, and the + // 5 + // interleaved white lines for the second digit. + // Therefore, need to scan 10 lines and then + // split these into two arrays + vector counterDigitPair(10, 0); + vector counterBlack(5, 0); + vector counterWhite(5, 0); + + while (payloadStart < payloadEnd) { + + // Get 10 runs of black/white. + recordPattern(row, payloadStart, counterDigitPair); + // Split them into each array + for (int k = 0; k < 5; k++) { + int twoK = k << 1; + counterBlack[k] = counterDigitPair[twoK]; + counterWhite[k] = counterDigitPair[twoK + 1]; } + int bestMatch = decodeDigit(counterBlack); + resultString.append(1, (char) ('0' + bestMatch)); + bestMatch = decodeDigit(counterWhite); + resultString.append(1, (char) ('0' + bestMatch)); - Ref ITFReader::decodeRow(int rowNumber, Ref row) { - int* startRange = 0; - int* endRange = 0; - try { - // Find out where the Middle section (payload) starts & ends - startRange = decodeStart(row); - endRange = decodeEnd(row); - - std::string tmpResult; - decodeMiddle(row, startRange[1], endRange[0], tmpResult); - - // To avoid false positives with 2D barcodes (and other patterns), make - // an assumption that the decoded string must be a known length - int length = tmpResult.length(); - bool lengthOK = false; - for (int i = 0; i < DEFAULT_ALLOWED_LENGTHS_LEN; i++) { - if (length == DEFAULT_ALLOWED_LENGTHS[i]) { - lengthOK = true; - break; - } - } - if (!lengthOK) { - throw ReaderException("not enough characters count"); - } - - Ref resultString(new String(tmpResult)); - - std::vector< Ref > resultPoints(2); - Ref resultPoint1(new OneDResultPoint(startRange[1], (float) rowNumber)); - Ref resultPoint2(new OneDResultPoint(endRange[0], (float) rowNumber)); - resultPoints[0] = resultPoint1; - resultPoints[1] = resultPoint2; - - delete [] startRange; - delete [] endRange; - ArrayRef resultBytes(1); - return Ref(new Result(resultString, resultBytes, resultPoints, BarcodeFormat_ITF)); - } catch (ReaderException const& re) { - delete [] startRange; - delete [] endRange; - return Ref(); - } + for (int i = 0, e = counterDigitPair.size(); i < e; i++) { + payloadStart += counterDigitPair[i]; } + } +} - /** - * @param row row of black/white values to search - * @param payloadStart offset of start pattern - * @param resultString {@link StringBuffer} to append decoded chars to - * @throws ReaderException if decoding could not complete successfully - */ - void ITFReader::decodeMiddle(Ref row, int payloadStart, int payloadEnd, - std::string& resultString) { - // Digits are interleaved in pairs - 5 black lines for one digit, and the - // 5 - // interleaved white lines for the second digit. - // Therefore, need to scan 10 lines and then - // split these into two arrays - int counterDigitPairLen = 10; - int counterDigitPair[counterDigitPairLen]; - for (int i=0; i row) { + int endStart = skipWhiteSpace(row); + Range startPattern = findGuardPattern(row, endStart, START_PATTERN); - int counterBlack[5]; - int counterWhite[5]; - for (int i=0; i<5; i++) { - counterBlack[i] = 0; - counterWhite[i] = 0; - } + // Determine the width of a narrow line in pixels. We can do this by + // getting the width of the start pattern and dividing by 4 because its + // made up of 4 narrow lines. + narrowLineWidth = (startPattern[1] - startPattern[0]) >> 2; - while (payloadStart < payloadEnd) { - // Get 10 runs of black/white. - if (!recordPattern(row, payloadStart, counterDigitPair, counterDigitPairLen)) { - throw ReaderException(""); - } - // Split them into each array - for (int k = 0; k < 5; k++) { - int twoK = k << 1; - counterBlack[k] = counterDigitPair[twoK]; - counterWhite[k] = counterDigitPair[twoK + 1]; - } + validateQuietZone(row, startPattern[0]); + return startPattern; +} - int bestMatch = decodeDigit(counterBlack, 5); - resultString.append(1, (char) ('0' + bestMatch)); - bestMatch = decodeDigit(counterWhite, 5); - resultString.append(1, (char) ('0' + bestMatch)); +/** + * Identify where the end of the middle / payload section ends. + * + * @param row row of black/white values to search + * @return Array, containing index of start of 'end block' and end of 'end + * block' + * @throws ReaderException + */ - for (int i = 0; i < counterDigitPairLen; i++) { - payloadStart += counterDigitPair[i]; - } - } - } +ITFReader::Range ITFReader::decodeEnd(Ref row) { + // For convenience, reverse the row and then + // search from 'the start' for the end block + BitArray::Reverse r (row); - /** - * Identify where the start of the middle / payload section starts. - * - * @param row row of black/white values to search - * @return Array, containing index of start of 'start block' and end of - * 'start block' - * @throws ReaderException - */ - int* ITFReader::decodeStart(Ref row) { - int endStart = skipWhiteSpace(row); - int* startPattern = 0; - try { - startPattern = findGuardPattern(row, endStart, START_PATTERN, START_PATTERN_LEN); + int endStart = skipWhiteSpace(row); + Range endPattern = findGuardPattern(row, endStart, END_PATTERN_REVERSED); - // Determine the width of a narrow line in pixels. We can do this by - // getting the width of the start pattern and dividing by 4 because its - // made up of 4 narrow lines. - narrowLineWidth = (startPattern[1] - startPattern[0]) >> 2; - validateQuietZone(row, startPattern[0]); - return startPattern; - } catch (ReaderException const& re) { - delete [] startPattern; - throw re; - } - } + // The start & end patterns must be pre/post fixed by a quiet zone. This + // zone must be at least 10 times the width of a narrow line. + // ref: http://www.barcode-1.net/i25code.html + validateQuietZone(row, endPattern[0]); - /** - * Identify where the end of the middle / payload section ends. - * - * @param row row of black/white values to search - * @return Array, containing index of start of 'end block' and end of 'end - * block' - * @throws ReaderException - */ + // Now recalculate the indices of where the 'endblock' starts & stops to + // accommodate + // the reversed nature of the search + int temp = endPattern[0]; + endPattern[0] = row->getSize() - endPattern[1]; + endPattern[1] = row->getSize() - temp; + + return endPattern; +} - int* ITFReader::decodeEnd(Ref row) { - // For convenience, reverse the row and then - // search from 'the start' for the end block - row->reverse(); - int* endPattern = 0; - try { - int endStart = skipWhiteSpace(row); - endPattern = findGuardPattern(row, endStart, END_PATTERN_REVERSED, END_PATTERN_REVERSED_LEN); - - // The start & end patterns must be pre/post fixed by a quiet zone. This - // zone must be at least 10 times the width of a narrow line. - // ref: http://www.barcode-1.net/i25code.html - validateQuietZone(row, endPattern[0]); - - // Now recalculate the indices of where the 'endblock' starts & stops to - // accommodate - // the reversed nature of the search - int temp = endPattern[0]; - endPattern[0] = row->getSize() - endPattern[1]; - endPattern[1] = row->getSize() - temp; - - row->reverse(); - return endPattern; - } catch (ReaderException const& re) { - delete [] endPattern; - row->reverse(); - throw re; - } - } - - /** - * The start & end patterns must be pre/post fixed by a quiet zone. This - * zone must be at least 10 times the width of a narrow line. Scan back until - * we either get to the start of the barcode or match the necessary number of - * quiet zone pixels. - * - * Note: Its assumed the row is reversed when using this method to find - * quiet zone after the end pattern. - * - * ref: http://www.barcode-1.net/i25code.html - * - * @param row bit array representing the scanned barcode. - * @param startPattern index into row of the start or end pattern. - * @throws ReaderException if the quiet zone cannot be found, a ReaderException is thrown. - */ - void ITFReader::validateQuietZone(Ref row, int startPattern) { - (void)row; - (void)startPattern; +/** + * The start & end patterns must be pre/post fixed by a quiet zone. This + * zone must be at least 10 times the width of a narrow line. Scan back until + * we either get to the start of the barcode or match the necessary number of + * quiet zone pixels. + * + * Note: Its assumed the row is reversed when using this method to find + * quiet zone after the end pattern. + * + * ref: http://www.barcode-1.net/i25code.html + * + * @param row bit array representing the scanned barcode. + * @param startPattern index into row of the start or end pattern. + * @throws ReaderException if the quiet zone cannot be found, a ReaderException is thrown. + */ +void ITFReader::validateQuietZone(Ref row, int startPattern) { + (void)row; + (void)startPattern; //#pragma mark needs some corrections // int quietCount = narrowLineWidth * 10; // expect to find this many pixels of quiet zone // @@ -253,115 +242,102 @@ namespace zxing { // // Unable to find the necessary number of quiet zone pixels. // throw ReaderException("Unable to find the necessary number of quiet zone pixels"); // } +} + +/** + * Skip all whitespace until we get to the first black line. + * + * @param row row of black/white values to search + * @return index of the first black line. + * @throws ReaderException Throws exception if no black lines are found in the row + */ +int ITFReader::skipWhiteSpace(Ref row) { + int width = row->getSize(); + int endStart = 0; + while (endStart < width) { + if (row->get(endStart)) { + break; } + endStart++; + } + if (endStart == width) { + throw ReaderException(""); + } + return endStart; +} - /** - * Skip all whitespace until we get to the first black line. - * - * @param row row of black/white values to search - * @return index of the first black line. - * @throws ReaderException Throws exception if no black lines are found in the row - */ - int ITFReader::skipWhiteSpace(Ref row) { - int width = row->getSize(); - int endStart = 0; - while (endStart < width) { - if (row->get(endStart)) { - break; - } - endStart++; - } - if (endStart == width) { - throw ReaderException(""); - } - return endStart; - } +/** + * @param row row of black/white values to search + * @param rowOffset position to start search + * @param pattern pattern of counts of number of black and white pixels that are + * being searched for as a pattern + * @return start/end horizontal offset of guard pattern, as an array of two + * ints + * @throws ReaderException if pattern is not found + */ +ITFReader::Range ITFReader::findGuardPattern(Ref row, + int rowOffset, + vector const& pattern) { + // TODO: This is very similar to implementation in UPCEANReader. Consider if they can be + // merged to a single method. + int patternLength = pattern.size(); + vector counters(patternLength, 0); + int width = row->getSize(); + bool isWhite = false; - /** - * @param row row of black/white values to search - * @param rowOffset position to start search - * @param pattern pattern of counts of number of black and white pixels that are - * being searched for as a pattern - * @return start/end horizontal offset of guard pattern, as an array of two - * ints - * @throws ReaderException if pattern is not found - */ - int* ITFReader::findGuardPattern(Ref row, int rowOffset, const int pattern[], - int patternLen) { - // TODO: This is very similar to implementation in UPCEANReader. Consider if they can be - // merged to a single method. - int patternLength = patternLen; - int counters[patternLength]; - for (int i=0; igetSize(); - bool isWhite = false; - - int counterPosition = 0; - int patternStart = rowOffset; - for (int x = rowOffset; x < width; x++) { - bool pixel = row->get(x); - if (pixel ^ isWhite) { - counters[counterPosition]++; - } else { - if (counterPosition == patternLength - 1) { - if (patternMatchVariance(counters, patternLength, pattern, - MAX_INDIVIDUAL_VARIANCE) < MAX_AVG_VARIANCE) { - int* resultValue = new int[2]; - resultValue[0] = patternStart; - resultValue[1] = x; - return resultValue; - } - patternStart += counters[0] + counters[1]; - for (int y = 2; y < patternLength; y++) { - counters[y - 2] = counters[y]; - } - counters[patternLength - 2] = 0; - counters[patternLength - 1] = 0; - counterPosition--; - } else { - counterPosition++; - } - counters[counterPosition] = 1; - isWhite = !isWhite; + int counterPosition = 0; + int patternStart = rowOffset; + for (int x = rowOffset; x < width; x++) { + if (row->get(x) ^ isWhite) { + counters[counterPosition]++; + } else { + if (counterPosition == patternLength - 1) { + if (patternMatchVariance(counters, &pattern[0], MAX_INDIVIDUAL_VARIANCE) < MAX_AVG_VARIANCE) { + return Range(patternStart, x); } - } - throw ReaderException(""); - } - - /** - * Attempts to decode a sequence of ITF black/white lines into single - * digit. - * - * @param counters the counts of runs of observed black/white/black/... values - * @return The decoded digit - * @throws ReaderException if digit cannot be decoded - */ - int ITFReader::decodeDigit(int counters[], int countersLen){ - unsigned int bestVariance = MAX_AVG_VARIANCE; // worst variance we'll accept - int bestMatch = -1; - int max = PATTERNS_LEN; - for (int i = 0; i < max; i++) { - int pattern[countersLen]; - for(int ind = 0; ind= 0) { - return bestMatch; + counters[patternLength - 2] = 0; + counters[patternLength - 1] = 0; + counterPosition--; } else { - throw ReaderException("digit didint found"); + counterPosition++; } - } - - ITFReader::~ITFReader(){ + counters[counterPosition] = 1; + isWhite = !isWhite; } } + throw NotFoundException(); } + +/** + * Attempts to decode a sequence of ITF black/white lines into single + * digit. + * + * @param counters the counts of runs of observed black/white/black/... values + * @return The decoded digit + * @throws ReaderException if digit cannot be decoded + */ +int ITFReader::decodeDigit(vector& counters){ + + int bestVariance = MAX_AVG_VARIANCE; // worst variance we'll accept + int bestMatch = -1; + int max = PATTERNS_LEN; + for (int i = 0; i < max; i++) { + int const* pattern = PATTERNS[i]; + int variance = patternMatchVariance(counters, pattern, MAX_INDIVIDUAL_VARIANCE); + if (variance < bestVariance) { + bestVariance = variance; + bestMatch = i; + } + } + if (bestMatch >= 0) { + return bestMatch; + } else { + throw NotFoundException(); + } +} + +ITFReader::~ITFReader(){} diff --git a/cpp/core/src/zxing/oned/ITFReader.h b/cpp/core/src/zxing/oned/ITFReader.h index 29bba0c00..847b00069 100644 --- a/cpp/core/src/zxing/oned/ITFReader.h +++ b/cpp/core/src/zxing/oned/ITFReader.h @@ -24,30 +24,32 @@ namespace zxing { namespace oned { - class ITFReader : public OneDReader { - - private: - enum {MAX_AVG_VARIANCE = (unsigned int) (PATTERN_MATCH_RESULT_SCALE_FACTOR * 420/1000)}; - enum {MAX_INDIVIDUAL_VARIANCE = (int) (PATTERN_MATCH_RESULT_SCALE_FACTOR * 800/1000)}; - // Stores the actual narrow line width of the image being decoded. - int narrowLineWidth; - - int* decodeStart(Ref row); //throws ReaderException - int* decodeEnd(Ref row); //throws ReaderException - static void decodeMiddle(Ref row, int payloadStart, int payloadEnd, std::string& resultString); //throws ReaderException - void validateQuietZone(Ref row, int startPattern); //throws ReaderException - static int skipWhiteSpace(Ref row); //throws ReaderException - - static int* findGuardPattern(Ref row, int rowOffset, const int pattern[], int patternLen); //throws ReaderException - static int decodeDigit(int counters[], int countersLen); //throws ReaderException - - void append(char* s, char c); - public: - Ref decodeRow(int rowNumber, Ref row); ///throws ReaderException - ITFReader(); - ~ITFReader(); - }; - } + class ITFReader; + } } +class zxing::oned::ITFReader : public OneDReader { + +private: + enum {MAX_AVG_VARIANCE = (unsigned int) (PATTERN_MATCH_RESULT_SCALE_FACTOR * 420/1000)}; + enum {MAX_INDIVIDUAL_VARIANCE = (int) (PATTERN_MATCH_RESULT_SCALE_FACTOR * 800/1000)}; + // Stores the actual narrow line width of the image being decoded. + int narrowLineWidth; + + Range decodeStart(Ref row); + Range decodeEnd(Ref row); + static void decodeMiddle(Ref row, int payloadStart, int payloadEnd, std::string& resultString); + void validateQuietZone(Ref row, int startPattern); + static int skipWhiteSpace(Ref row); + + static Range findGuardPattern(Ref row, int rowOffset, std::vector const& pattern); + static int decodeDigit(std::vector& counters); + + void append(char* s, char c); +public: + Ref decodeRow(int rowNumber, Ref row); + ITFReader(); + ~ITFReader(); +}; + #endif diff --git a/cpp/core/src/zxing/oned/MultiFormatOneDReader.cpp b/cpp/core/src/zxing/oned/MultiFormatOneDReader.cpp index 01792061a..a608dd1b0 100644 --- a/cpp/core/src/zxing/oned/MultiFormatOneDReader.cpp +++ b/cpp/core/src/zxing/oned/MultiFormatOneDReader.cpp @@ -1,3 +1,4 @@ +// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*- /* * MultiFormatOneDReader.cpp * ZXing @@ -22,45 +23,76 @@ #include #include #include +#include +#include #include #include +#include -namespace zxing { - namespace oned { - MultiFormatOneDReader::MultiFormatOneDReader(DecodeHints hints) : readers() { - if (hints.containsFormat(BarcodeFormat_EAN_13) || - hints.containsFormat(BarcodeFormat_EAN_8) || - hints.containsFormat(BarcodeFormat_UPC_A) || - hints.containsFormat(BarcodeFormat_UPC_E)) { - readers.push_back(Ref(new MultiFormatUPCEANReader(hints))); - } - if (hints.containsFormat(BarcodeFormat_CODE_39)) { - readers.push_back(Ref(new Code39Reader())); - } - if (hints.containsFormat(BarcodeFormat_CODE_128)) { - readers.push_back(Ref(new Code128Reader())); - } - if (hints.containsFormat(BarcodeFormat_ITF)) { - readers.push_back(Ref(new ITFReader())); - } - if (readers.size() == 0) { - readers.push_back(Ref(new MultiFormatUPCEANReader(hints))); - readers.push_back(Ref(new Code39Reader())); - readers.push_back(Ref(new Code128Reader())); - readers.push_back(Ref(new ITFReader())); - } - } +using zxing::Ref; +using zxing::Result; +using zxing::oned::MultiFormatOneDReader; - Ref MultiFormatOneDReader::decodeRow(int rowNumber, Ref row) { - int size = readers.size(); - for (int i = 0; i < size; i++) { - OneDReader* reader = readers[i]; - Ref result = reader->decodeRow(rowNumber, row); - if (!result.empty()) { - return result; - } - } - return Ref(); - } +MultiFormatOneDReader::MultiFormatOneDReader(DecodeHints hints) : readers() { + if (hints.containsFormat(BarcodeFormat::EAN_13) || + hints.containsFormat(BarcodeFormat::EAN_8) || + hints.containsFormat(BarcodeFormat::UPC_A) || + hints.containsFormat(BarcodeFormat::UPC_E)) { + readers.push_back(Ref(new MultiFormatUPCEANReader(hints))); + } + if (hints.containsFormat(BarcodeFormat::CODE_39)) { + readers.push_back(Ref(new Code39Reader())); + } + if (hints.containsFormat(BarcodeFormat::CODE_93)) { + readers.push_back(Ref(new Code93Reader())); + } + if (hints.containsFormat(BarcodeFormat::CODE_128)) { + readers.push_back(Ref(new Code128Reader())); + } + if (hints.containsFormat(BarcodeFormat::ITF)) { + readers.push_back(Ref(new ITFReader())); + } + if (hints.containsFormat(BarcodeFormat::CODABAR)) { + readers.push_back(Ref(new CodaBarReader())); + } +/* + if (hints.containsFormat(BarcodeFormat::RSS_14)) { + readers.push_back(Ref(new RSS14Reader())); + } +*/ +/* + if (hints.containsFormat(BarcodeFormat::RSS_EXPANDED)) { + readers.push_back(Ref(new RSS14ExpandedReader())); + } +*/ + if (readers.size() == 0) { + readers.push_back(Ref(new MultiFormatUPCEANReader(hints))); + readers.push_back(Ref(new Code39Reader())); + readers.push_back(Ref(new CodaBarReader())); + readers.push_back(Ref(new Code93Reader())); + readers.push_back(Ref(new Code128Reader())); + readers.push_back(Ref(new ITFReader())); + // readers.push_back(Ref(new RSS14Reader())); + // readers.push_back(Ref(new RSS14ExpandedReader())); } } + +#include + +Ref MultiFormatOneDReader::decodeRow(int rowNumber, Ref row) { + int size = readers.size(); + for (int i = 0; i < size; i++) { + OneDReader* reader = readers[i]; + try { + // std::cerr << "v 1 " << typeid(*reader).name() << " " << rowNumber << std::endl; + Ref result = reader->decodeRow(rowNumber, row); + // std::cerr << "^ 1 " << typeid(*reader).name() << " " << rowNumber << std::endl; + return result; + } catch (ReaderException const& re) { + // std::cerr << "^ * " << typeid(*reader).name() << " " << rowNumber << std::endl; + // continue + } + } + // std::cerr << "throwing nfe" << std::endl; + throw NotFoundException(); +} diff --git a/cpp/core/src/zxing/oned/MultiFormatUPCEANReader.cpp b/cpp/core/src/zxing/oned/MultiFormatUPCEANReader.cpp index a5582f026..c7dce1eff 100644 --- a/cpp/core/src/zxing/oned/MultiFormatUPCEANReader.cpp +++ b/cpp/core/src/zxing/oned/MultiFormatUPCEANReader.cpp @@ -1,3 +1,4 @@ +// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*- /* * MultiFormatUPCEANReader.cpp * ZXing @@ -25,63 +26,81 @@ #include #include #include +#include #include -namespace zxing { - namespace oned { - - MultiFormatUPCEANReader::MultiFormatUPCEANReader(DecodeHints hints) : readers() { - if (hints.containsFormat(BarcodeFormat_EAN_13)) { - readers.push_back(Ref(new EAN13Reader())); - } else if (hints.containsFormat(BarcodeFormat_UPC_A)) { - readers.push_back(Ref(new UPCAReader())); - } - if (hints.containsFormat(BarcodeFormat_EAN_8)) { - readers.push_back(Ref(new EAN8Reader())); - } - if (hints.containsFormat(BarcodeFormat_UPC_E)) { - readers.push_back(Ref(new UPCEReader())); - } - if (readers.size() == 0) { - readers.push_back(Ref(new EAN13Reader())); - // UPC-A is covered by EAN-13 - 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(); - for (int i = 0; i < size; i++) { - Ref reader = readers[i]; - Ref result = reader->decodeRow(rowNumber, row); - if (result.empty()) { - continue; - } - - // Special case: a 12-digit code encoded in UPC-A is identical to a "0" - // followed by those 12 digits encoded as EAN-13. Each will recognize such a code, - // UPC-A as a 12-digit string and EAN-13 as a 13-digit string starting with "0". - // Individually these are correct and their readers will both read such a code - // and correctly call it EAN-13, or UPC-A, respectively. - // - // In this case, if we've been looking for both types, we'd like to call it - // a UPC-A code. But for efficiency we only run the EAN-13 decoder to also read - // 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) { - 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)); - return res; - } - } - return result; - } - return Ref(); - } +using zxing::NotFoundException; +using zxing::Ref; +using zxing::Result; +using zxing::oned::MultiFormatUPCEANReader; + +MultiFormatUPCEANReader::MultiFormatUPCEANReader(DecodeHints hints) : readers() { + if (hints.containsFormat(BarcodeFormat::EAN_13)) { + readers.push_back(Ref(new EAN13Reader())); + } else if (hints.containsFormat(BarcodeFormat::UPC_A)) { + readers.push_back(Ref(new UPCAReader())); + } + if (hints.containsFormat(BarcodeFormat::EAN_8)) { + readers.push_back(Ref(new EAN8Reader())); + } + if (hints.containsFormat(BarcodeFormat::UPC_E)) { + readers.push_back(Ref(new UPCEReader())); + } + if (readers.size() == 0) { + readers.push_back(Ref(new EAN13Reader())); + // UPC-A is covered by EAN-13 + readers.push_back(Ref(new EAN8Reader())); + readers.push_back(Ref(new UPCEReader())); } } + +#include + +Ref MultiFormatUPCEANReader::decodeRow(int rowNumber, Ref row) { + // Compute this location once and reuse it on multiple implementations + UPCEANReader::Range startGuardPattern = UPCEANReader::findStartGuardPattern(row); + // std::cerr << "sgp " << startGuardPattern[0] << " " << startGuardPattern[1] << std::endl; + for (int i = 0, e = readers.size(); i < e; i++) { + Ref reader = readers[i]; + Ref result; + try { + // std::cerr << typeid(*reader).name() << " " << rowNumber << std::endl; + result = reader->decodeRow(rowNumber, row, startGuardPattern); + } catch (ReaderException const& re) { + continue; + } + + // Special case: a 12-digit code encoded in UPC-A is identical + // to a "0" followed by those 12 digits encoded as EAN-13. Each + // will recognize such a code, UPC-A as a 12-digit string and + // EAN-13 as a 13-digit string starting with "0". Individually + // these are correct and their readers will both read such a + // code and correctly call it EAN-13, or UPC-A, respectively. + // + // In this case, if we've been looking for both types, we'd like + // to call it a UPC-A code. But for efficiency we only run the + // EAN-13 decoder to also read UPC-A. So we special case it + // here, and convert an EAN-13 result to a UPC-A result if + // appropriate. + bool ean13MayBeUPCA = + result->getBarcodeFormat() == BarcodeFormat::EAN_13 && + result->getText()->charAt(0) == '0'; + + // Note: doesn't match Java which uses hints + + bool canReturnUPCA = true; + + if (ean13MayBeUPCA && canReturnUPCA) { + // Transfer the metdata across + Ref resultUPCA (new Result(result->getText()->substring(1), + result->getRawBytes(), + result->getResultPoints(), + BarcodeFormat::UPC_A)); + // needs java metadata stuff + return resultUPCA; + } + return result; + } + + throw NotFoundException(); +} diff --git a/cpp/core/src/zxing/oned/MultiFormatUPCEANReader.h b/cpp/core/src/zxing/oned/MultiFormatUPCEANReader.h index 30e5c4df7..016216cb5 100644 --- a/cpp/core/src/zxing/oned/MultiFormatUPCEANReader.h +++ b/cpp/core/src/zxing/oned/MultiFormatUPCEANReader.h @@ -1,3 +1,4 @@ +// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*- #ifndef __MULTI_FORMAT_UPC_EAN_READER_H__ #define __MULTI_FORMAT_UPC_EAN_READER_H__ /* @@ -23,16 +24,17 @@ namespace zxing { namespace oned { - class MultiFormatUPCEANReader : public OneDReader { - - private: - std::vector > readers; - public: - MultiFormatUPCEANReader(DecodeHints hints); - - Ref decodeRow(int rowNumber, Ref row); - }; + class UPCEANReader; + class MultiFormatUPCEANReader; } } +class zxing::oned::MultiFormatUPCEANReader : public OneDReader { +private: + std::vector< Ref > readers; +public: + MultiFormatUPCEANReader(DecodeHints hints); + Ref decodeRow(int rowNumber, Ref row); +}; + #endif diff --git a/cpp/core/src/zxing/oned/OneDReader.cpp b/cpp/core/src/zxing/oned/OneDReader.cpp index 8ef7a23ac..8e42c7e1d 100644 --- a/cpp/core/src/zxing/oned/OneDReader.cpp +++ b/cpp/core/src/zxing/oned/OneDReader.cpp @@ -21,187 +21,202 @@ #include "OneDReader.h" #include #include +#include #include #include -namespace zxing { - namespace oned { - using namespace std; +using std::vector; +using zxing::Ref; +using zxing::Result; +using zxing::NotFoundException; +using zxing::oned::OneDReader; - OneDReader::OneDReader() { - } +OneDReader::OneDReader() {} - Ref OneDReader::decode(Ref image, DecodeHints hints) { - Ref result = doDecode(image, hints); - if (result.empty() && hints.getTryHarder() && image->isRotateSupported()) { - Ref rotatedImage(image->rotateCounterClockwise()); - result = doDecode(rotatedImage, hints); - if (!result.empty()) { - /* - // Record that we found it rotated 90 degrees CCW / 270 degrees CW - Hashtable metadata = result.getResultMetadata(); - int orientation = 270; - if (metadata != null && metadata.containsKey(ResultMetadataType.ORIENTATION)) { - // But if we found it reversed in doDecode(), add in that result here: - orientation = (orientation + - ((Integer) metadata.get(ResultMetadataType.ORIENTATION)).intValue()) % 360; - } - result.putMetadata(ResultMetadataType.ORIENTATION, new Integer(orientation)); - */ - // Update result points - std::vector >& points (result->getResultPoints()); - int height = rotatedImage->getHeight(); - for (size_t i = 0; i < points.size(); i++) { - points[i].reset(new OneDResultPoint(height - points[i]->getY() - 1, points[i]->getX())); - } +Ref OneDReader::decode(Ref image, DecodeHints hints) { + try { + return doDecode(image, hints); + } catch (NotFoundException const& nfe) { + // std::cerr << "trying harder" << std::endl; + bool tryHarder = hints.getTryHarder(); + if (tryHarder && image->isRotateSupported()) { + // std::cerr << "v rotate" << std::endl; + Ref rotatedImage(image->rotateCounterClockwise()); + // std::cerr << "^ rotate" << std::endl; + Ref result = doDecode(rotatedImage, hints); + // Doesn't have java metadata stuff + ArrayRef< Ref >& points (result->getResultPoints()); + if (points && !points->empty()) { + int height = rotatedImage->getHeight(); + for (int i = 0; i < points.size(); i++) { + points[i].reset(new OneDResultPoint(height - points[i]->getY() - 1, points[i]->getX())); } } - if (result.empty()) { - throw ReaderException(""); - } + // std::cerr << "tried harder" << std::endl; return result; - } - - Ref OneDReader::doDecode(Ref image, DecodeHints hints) { - int width = image->getWidth(); - int height = image->getHeight(); - Ref row(new BitArray(width)); - int middle = height >> 1; - bool tryHarder = hints.getTryHarder(); - int rowStep = (int)fmax(1, height >> (tryHarder ? 8 : 5)); - int maxLines; - if (tryHarder) { - maxLines = height; // Look at the whole image, not just the center - } else { - maxLines = 15; // 15 rows spaced 1/32 apart is roughly the middle half of the image - } - - for (int x = 0; x < maxLines; x++) { - // Scanning from the middle out. Determine which row we're looking at next: - int rowStepsAboveOrBelow = (x + 1) >> 1; - bool isAbove = (x & 0x01) == 0; // i.e. is x even? - int rowNumber = middle + rowStep * (isAbove ? rowStepsAboveOrBelow : -rowStepsAboveOrBelow); - if (rowNumber < 0 || rowNumber >= height) { - // Oops, if we run off the top or bottom, stop - break; - } - - // Estimate black point for this row and load it: - try { - row = image->getBlackRow(rowNumber, row); - } catch (ReaderException const& re) { - continue; - } catch (IllegalArgumentException const& re) { - continue; - } - - // While we have the image data in a BitArray, it's fairly cheap to reverse it in place to - // handle decoding upside down barcodes. - for (int attempt = 0; attempt < 2; attempt++) { - if (attempt == 1) { - row->reverse(); // reverse the row and continue - } - - // Look for a barcode - Ref result = decodeRow(rowNumber, row); - // We found our barcode - if (!result.empty()) { - if (attempt == 1) { - // But it was upside down, so note that - // result.putMetadata(ResultMetadataType.ORIENTATION, new Integer(180)); - // And remember to flip the result points horizontally. - std::vector > points(result->getResultPoints()); - // if there's exactly two points (which there should be), flip the x coordinate - // if there's not exactly 2, I don't know what do do with it - 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; - } - } - } - return Ref(); - } - - unsigned int OneDReader::patternMatchVariance(int counters[], int countersSize, - const int pattern[], int maxIndividualVariance) { - int numCounters = countersSize; - unsigned int total = 0; - unsigned int patternLength = 0; - for (int i = 0; i < numCounters; i++) { - total += counters[i]; - patternLength += pattern[i]; - } - if (total < patternLength) { - // If we don't even have one pixel per unit of bar width, assume this is too small - // to reliably match, so fail: - return INT_MAX; - } - // 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" - unsigned int unitBarWidth = (total << INTEGER_MATH_SHIFT) / patternLength; - maxIndividualVariance = (maxIndividualVariance * unitBarWidth) >> INTEGER_MATH_SHIFT; - - unsigned int totalVariance = 0; - for (int x = 0; x < numCounters; x++) { - int counter = counters[x] << INTEGER_MATH_SHIFT; - int scaledPattern = pattern[x] * unitBarWidth; - int variance = counter > scaledPattern ? counter - scaledPattern : scaledPattern - counter; - if (variance > maxIndividualVariance) { - return INT_MAX; - } - totalVariance += variance; - } - return totalVariance / total; - } - - bool OneDReader::recordPattern(Ref row, int start, int counters[], int countersCount) { - int numCounters = countersCount;//sizeof(counters) / sizeof(int); - for (int i = 0; i < numCounters; i++) { - counters[i] = 0; - } - int end = row->getSize(); - if (start >= end) { - return false; - } - bool isWhite = !row->get(start); - int counterPosition = 0; - int i = start; - while (i < end) { - bool pixel = row->get(i); - if (pixel ^ isWhite) { // that is, exactly one is true - counters[counterPosition]++; - } else { - counterPosition++; - if (counterPosition == numCounters) { - break; - } else { - counters[counterPosition] = 1; - isWhite ^= true; // isWhite = !isWhite; - } - } - i++; - } - // If we read fully the last section of pixels and filled up our counters -- or filled - // the last counter but ran off the side of the image, OK. Otherwise, a problem. - if (!(counterPosition == numCounters || (counterPosition == numCounters - 1 && i == end))) { - return false; - } - return true; - } - - OneDReader::~OneDReader() { + } else { + // std::cerr << "tried harder nfe" << std::endl; + throw nfe; } } } + +#include + +Ref OneDReader::doDecode(Ref image, DecodeHints hints) { + int width = image->getWidth(); + int height = image->getHeight(); + Ref row(new BitArray(width)); + + int middle = height >> 1; + bool tryHarder = hints.getTryHarder(); + int rowStep = std::max(1, height >> (tryHarder ? 8 : 5)); + using namespace std; + // cerr << "rS " << rowStep << " " << height << " " << tryHarder << endl; + int maxLines; + if (tryHarder) { + maxLines = height; // Look at the whole image, not just the center + } else { + maxLines = 15; // 15 rows spaced 1/32 apart is roughly the middle half of the image + } + + for (int x = 0; x < maxLines; x++) { + + // Scanning from the middle out. Determine which row we're looking at next: + int rowStepsAboveOrBelow = (x + 1) >> 1; + bool isAbove = (x & 0x01) == 0; // i.e. is x even? + int rowNumber = middle + rowStep * (isAbove ? rowStepsAboveOrBelow : -rowStepsAboveOrBelow); + if (false) { + std::cerr << "rN " + << rowNumber << " " + << height << " " + << middle << " " + << rowStep << " " + << isAbove << " " + << rowStepsAboveOrBelow + << std::endl; + } + if (rowNumber < 0 || rowNumber >= height) { + // Oops, if we run off the top or bottom, stop + break; + } + + // Estimate black point for this row and load it: + try { + row = image->getBlackRow(rowNumber, row); + } catch (NotFoundException const& nfe) { + continue; + } + + // While we have the image data in a BitArray, it's fairly cheap to reverse it in place to + // handle decoding upside down barcodes. + for (int attempt = 0; attempt < 2; attempt++) { + if (attempt == 1) { + row->reverse(); // reverse the row and continue + } + + // Java hints stuff missing + + try { + // Look for a barcode + // std::cerr << "rn " << rowNumber << " " << typeid(*this).name() << std::endl; + Ref result = decodeRow(rowNumber, row); + // We found our barcode + if (attempt == 1) { + // But it was upside down, so note that + // result.putMetadata(ResultMetadataType.ORIENTATION, new Integer(180)); + // And remember to flip the result points horizontally. + ArrayRef< Ref > points(result->getResultPoints()); + if (points) { + points[0] = Ref(new OneDResultPoint(width - points[0]->getX() - 1, + points[0]->getY())); + points[1] = Ref(new OneDResultPoint(width - points[1]->getX() - 1, + points[1]->getY())); + + } + } + return result; + } catch (ReaderException const& re) { + continue; + } + } + } + throw NotFoundException(); +} + +int OneDReader::patternMatchVariance(vector& counters, + vector const& pattern, + int maxIndividualVariance) { + return patternMatchVariance(counters, &pattern[0], maxIndividualVariance); +} + +int OneDReader::patternMatchVariance(vector& counters, + int const pattern[], + int maxIndividualVariance) { + int numCounters = counters.size(); + unsigned int total = 0; + unsigned int patternLength = 0; + for (int i = 0; i < numCounters; i++) { + total += counters[i]; + patternLength += pattern[i]; + } + if (total < patternLength) { + // If we don't even have one pixel per unit of bar width, assume this is too small + // to reliably match, so fail: + return INT_MAX; + } + // 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; + maxIndividualVariance = (maxIndividualVariance * unitBarWidth) >> INTEGER_MATH_SHIFT; + + int totalVariance = 0; + for (int x = 0; x < numCounters; x++) { + int counter = counters[x] << INTEGER_MATH_SHIFT; + int scaledPattern = pattern[x] * unitBarWidth; + int variance = counter > scaledPattern ? counter - scaledPattern : scaledPattern - counter; + if (variance > maxIndividualVariance) { + return INT_MAX; + } + totalVariance += variance; + } + return totalVariance / total; +} + +void OneDReader::recordPattern(Ref row, + int start, + vector& counters) { + int numCounters = counters.size(); + for (int i = 0; i < numCounters; i++) { + counters[i] = 0; + } + int end = row->getSize(); + if (start >= end) { + throw NotFoundException(); + } + bool isWhite = !row->get(start); + int counterPosition = 0; + int i = start; + while (i < end) { + if (row->get(i) ^ isWhite) { // that is, exactly one is true + counters[counterPosition]++; + } else { + counterPosition++; + if (counterPosition == numCounters) { + break; + } else { + counters[counterPosition] = 1; + isWhite = !isWhite; + } + } + i++; + } + // If we read fully the last section of pixels and filled up our counters -- or filled + // the last counter but ran off the side of the image, OK. Otherwise, a problem. + if (!(counterPosition == numCounters || (counterPosition == numCounters - 1 && i == end))) { + throw NotFoundException(); + } +} + +OneDReader::~OneDReader() {} diff --git a/cpp/core/src/zxing/oned/OneDReader.h b/cpp/core/src/zxing/oned/OneDReader.h index fdd1d023a..6552a1afc 100644 --- a/cpp/core/src/zxing/oned/OneDReader.h +++ b/cpp/core/src/zxing/oned/OneDReader.h @@ -1,3 +1,4 @@ +// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*- #ifndef __ONED_READER_H__ #define __ONED_READER_H__ @@ -23,28 +24,58 @@ #include namespace zxing { - namespace oned { - class OneDReader : public Reader { - private: - static const int INTEGER_MATH_SHIFT = 8; - - Ref doDecode(Ref image, DecodeHints hints); - public: - static const int PATTERN_MATCH_RESULT_SCALE_FACTOR = 1 << INTEGER_MATH_SHIFT; - - OneDReader(); - virtual Ref decode(Ref image, DecodeHints hints); - - // Implementations must not throw any exceptions. If a barcode is not found on this row, - // a empty ref should be returned e.g. return Ref(); - virtual Ref decodeRow(int rowNumber, Ref row) = 0; - - static unsigned int patternMatchVariance(int counters[], int countersSize, - const int pattern[], int maxIndividualVariance); - static bool recordPattern(Ref row, int start, int counters[], int countersCount); - virtual ~OneDReader(); - }; - } + namespace oned { + class OneDReader; + } } +class zxing::oned::OneDReader : public Reader { +private: + Ref doDecode(Ref image, DecodeHints hints); + +protected: + static const int INTEGER_MATH_SHIFT = 8; + + struct Range { + private: + int data[2]; + public: + Range() {} + Range(int zero, int one) { + data[0] = zero; + data[1] = one; + } + int& operator [] (int index) { + return data[index]; + } + int const& operator [] (int index) const { + return data[index]; + } + }; + + static int patternMatchVariance(std::vector& counters, + std::vector const& pattern, + int maxIndividualVariance); + static int patternMatchVariance(std::vector& counters, + int const pattern[], + int maxIndividualVariance); + +protected: + static const int PATTERN_MATCH_RESULT_SCALE_FACTOR = 1 << INTEGER_MATH_SHIFT; + +public: + + OneDReader(); + virtual Ref decode(Ref image, DecodeHints hints); + + // Implementations must not throw any exceptions. If a barcode is not found on this row, + // a empty ref should be returned e.g. return Ref(); + virtual Ref decodeRow(int rowNumber, Ref row) = 0; + + static void recordPattern(Ref row, + int start, + std::vector& counters); + virtual ~OneDReader(); +}; + #endif diff --git a/cpp/core/src/zxing/oned/UPCAReader.cpp b/cpp/core/src/zxing/oned/UPCAReader.cpp index 1eb2b6f39..a33330107 100644 --- a/cpp/core/src/zxing/oned/UPCAReader.cpp +++ b/cpp/core/src/zxing/oned/UPCAReader.cpp @@ -1,3 +1,4 @@ +// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*- /* * UPCAReader.cpp * ZXing @@ -20,46 +21,47 @@ #include "UPCAReader.h" #include -namespace zxing { - namespace oned { - UPCAReader::UPCAReader() : ean13Reader() { - } +using zxing::oned::UPCAReader; +using zxing::Ref; +using zxing::Result; - Ref UPCAReader::decodeRow(int rowNumber, Ref row) { - return maybeReturnResult(ean13Reader.decodeRow(rowNumber, row)); - } - - Ref UPCAReader::decodeRow(int rowNumber, Ref row, int startGuardBegin, - int startGuardEnd) { - return maybeReturnResult(ean13Reader.decodeRow(rowNumber, row, startGuardBegin, - startGuardEnd)); - } - - Ref UPCAReader::decode(Ref image, DecodeHints hints) { - return maybeReturnResult(ean13Reader.decode(image, hints)); - } - - int UPCAReader::decodeMiddle(Ref row, int startGuardBegin, int startGuardEnd, - std::string& resultString) { - return ean13Reader.decodeMiddle(row, startGuardBegin, startGuardEnd, resultString); - } - - Ref UPCAReader::maybeReturnResult(Ref result) { - if (result.empty()) { - return result; - } - 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)); - return res; - } - return Ref(); - } - - BarcodeFormat UPCAReader::getBarcodeFormat(){ - return BarcodeFormat_UPC_A; - } - } +UPCAReader::UPCAReader() : ean13Reader() { +} + +Ref UPCAReader::decodeRow(int rowNumber, Ref row) { + return maybeReturnResult(ean13Reader.decodeRow(rowNumber, row)); +} + +Ref UPCAReader::decodeRow(int rowNumber, + Ref row, + Range const& startGuardRange) { + return maybeReturnResult(ean13Reader.decodeRow(rowNumber, row, startGuardRange)); +} + +Ref UPCAReader::decode(Ref image, DecodeHints hints) { + return maybeReturnResult(ean13Reader.decode(image, hints)); +} + +int UPCAReader::decodeMiddle(Ref row, + Range const& startRange, + std::string& resultString) { + return ean13Reader.decodeMiddle(row, startRange, resultString); +} + +Ref UPCAReader::maybeReturnResult(Ref result) { + if (result.empty()) { + return result; + } + 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)); + return res; + } + return Ref(); +} + +zxing::BarcodeFormat UPCAReader::getBarcodeFormat(){ + return BarcodeFormat::UPC_A; } diff --git a/cpp/core/src/zxing/oned/UPCAReader.h b/cpp/core/src/zxing/oned/UPCAReader.h index 7c61cf113..d5b00171a 100644 --- a/cpp/core/src/zxing/oned/UPCAReader.h +++ b/cpp/core/src/zxing/oned/UPCAReader.h @@ -1,3 +1,4 @@ +// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*- #ifndef __UPCA_READER_H__ #define __UPCA_READER_H__ /* @@ -24,26 +25,26 @@ namespace zxing { namespace oned { - class UPCAReader : public UPCEANReader { - - private: - EAN13Reader ean13Reader; - static Ref maybeReturnResult(Ref result); - - public: - UPCAReader(); - - int decodeMiddle(Ref row, int startGuardBegin, int startGuardEnd, - std::string& resultString); - - Ref decodeRow(int rowNumber, Ref row); - Ref decodeRow(int rowNumber, Ref row, int startGuardBegin, - int startGuardEnd); - Ref decode(Ref image, DecodeHints hints); - - BarcodeFormat getBarcodeFormat(); - }; + class UPCAReader; } } +class zxing::oned::UPCAReader : public UPCEANReader { + +private: + EAN13Reader ean13Reader; + static Ref maybeReturnResult(Ref result); + +public: + UPCAReader(); + + int decodeMiddle(Ref row, Range const& startRange, std::string& resultString); + + Ref decodeRow(int rowNumber, Ref row); + Ref decodeRow(int rowNumber, Ref row, Range const& startGuardRange); + Ref decode(Ref image, DecodeHints hints); + + BarcodeFormat getBarcodeFormat(); +}; + #endif diff --git a/cpp/core/src/zxing/oned/UPCEANReader.cpp b/cpp/core/src/zxing/oned/UPCEANReader.cpp index 962d71ae7..923950458 100644 --- a/cpp/core/src/zxing/oned/UPCEANReader.cpp +++ b/cpp/core/src/zxing/oned/UPCEANReader.cpp @@ -1,3 +1,4 @@ +// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*- /* * UPCEANReader.cpp * ZXing @@ -20,292 +21,280 @@ #include "UPCEANReader.h" #include #include +#include +#include -namespace zxing { - namespace oned { +using zxing::Ref; +using zxing::Result; +using zxing::NotFoundException; +using zxing::ChecksumException; +using zxing::oned::UPCEANReader; +using namespace std; // remove - /** - * Start/end guard pattern. - */ - static const int START_END_PATTERN[3] = {1, 1, 1}; +#define LEN(v) ((int)(sizeof(v)/sizeof(v[0]))) - /** - * Pattern marking the middle of a UPC/EAN pattern, separating the two halves. - */ - static const int MIDDLE_PATTERN_LEN = 5; - static const int MIDDLE_PATTERN[MIDDLE_PATTERN_LEN] = {1, 1, 1, 1, 1}; +namespace { - /** - * "Odd", or "L" patterns used to encode UPC/EAN digits. - */ - const int L_PATTERNS_LEN = 10; - const int L_PATTERNS_SUB_LEN = 4; - const int L_PATTERNS[L_PATTERNS_LEN][L_PATTERNS_SUB_LEN] = { - {3, 2, 1, 1}, // 0 - {2, 2, 2, 1}, // 1 - {2, 1, 2, 2}, // 2 - {1, 4, 1, 1}, // 3 - {1, 1, 3, 2}, // 4 - {1, 2, 3, 1}, // 5 - {1, 1, 1, 4}, // 6 - {1, 3, 1, 2}, // 7 - {1, 2, 1, 3}, // 8 - {3, 1, 1, 2} // 9 - }; + /** + * Start/end guard pattern. + */ + const int START_END_PATTERN_[] = {1, 1, 1}; + const int START_END_PATTERN_LEN = LEN(START_END_PATTERN_); - /** - * As above but also including the "even", or "G" patterns used to encode UPC/EAN digits. - */ - const int L_AND_G_PATTERNS_LEN = 20; - const int L_AND_G_PATTERNS_SUB_LEN = 4; - const int L_AND_G_PATTERNS[L_AND_G_PATTERNS_LEN][L_AND_G_PATTERNS_SUB_LEN] = { - {3, 2, 1, 1}, // 0 - {2, 2, 2, 1}, // 1 - {2, 1, 2, 2}, // 2 - {1, 4, 1, 1}, // 3 - {1, 1, 3, 2}, // 4 - {1, 2, 3, 1}, // 5 - {1, 1, 1, 4}, // 6 - {1, 3, 1, 2}, // 7 - {1, 2, 1, 3}, // 8 - {3, 1, 1, 2}, // 9 - {1, 1, 2, 3}, // 10 reversed 0 - {1, 2, 2, 2}, // 11 reversed 1 - {2, 2, 1, 2}, // 12 reversed 2 - {1, 1, 4, 1}, // 13 reversed 3 - {2, 3, 1, 1}, // 14 reversed 4 - {1, 3, 2, 1}, // 15 reversed 5 - {4, 1, 1, 1}, // 16 reversed 6 - {2, 1, 3, 1}, // 17 reversed 7 - {3, 1, 2, 1}, // 18 reversed 8 - {2, 1, 1, 3} // 19 reversed 9 - }; + /** + * Pattern marking the middle of a UPC/EAN pattern, separating the two halves. + */ + const int MIDDLE_PATTERN_[] = {1, 1, 1, 1, 1}; + const int MIDDLE_PATTERN_LEN = LEN(MIDDLE_PATTERN_); + /** + * "Odd", or "L" patterns used to encode UPC/EAN digits. + */ + const int L_PATTERNS_[][4] = { + {3, 2, 1, 1}, // 0 + {2, 2, 2, 1}, // 1 + {2, 1, 2, 2}, // 2 + {1, 4, 1, 1}, // 3 + {1, 1, 3, 2}, // 4 + {1, 2, 3, 1}, // 5 + {1, 1, 1, 4}, // 6 + {1, 3, 1, 2}, // 7 + {1, 2, 1, 3}, // 8 + {3, 1, 1, 2} // 9 + }; + const int L_PATTERNS_LEN = LEN(L_PATTERNS_); - int UPCEANReader::getMIDDLE_PATTERN_LEN() { - return MIDDLE_PATTERN_LEN; + /** + * As above but also including the "even", or "G" patterns used to encode UPC/EAN digits. + */ + const int L_AND_G_PATTERNS_[][4] = { + {3, 2, 1, 1}, // 0 + {2, 2, 2, 1}, // 1 + {2, 1, 2, 2}, // 2 + {1, 4, 1, 1}, // 3 + {1, 1, 3, 2}, // 4 + {1, 2, 3, 1}, // 5 + {1, 1, 1, 4}, // 6 + {1, 3, 1, 2}, // 7 + {1, 2, 1, 3}, // 8 + {3, 1, 1, 2}, // 9 + {1, 1, 2, 3}, // 10 reversed 0 + {1, 2, 2, 2}, // 11 reversed 1 + {2, 2, 1, 2}, // 12 reversed 2 + {1, 1, 4, 1}, // 13 reversed 3 + {2, 3, 1, 1}, // 14 reversed 4 + {1, 3, 2, 1}, // 15 reversed 5 + {4, 1, 1, 1}, // 16 reversed 6 + {2, 1, 3, 1}, // 17 reversed 7 + {3, 1, 2, 1}, // 18 reversed 8 + {2, 1, 1, 3} // 19 reversed 9 + }; + const int L_AND_G_PATTERNS_LEN = LEN(L_AND_G_PATTERNS_); +} + +const int UPCEANReader::MAX_AVG_VARIANCE = (int)(PATTERN_MATCH_RESULT_SCALE_FACTOR * 0.48f); +const int UPCEANReader::MAX_INDIVIDUAL_VARIANCE = (int)(PATTERN_MATCH_RESULT_SCALE_FACTOR * 0.7f); + +#define VECTOR_INIT(v) v, v + sizeof(v)/sizeof(v[0]) + +const vector +UPCEANReader::START_END_PATTERN (VECTOR_INIT(START_END_PATTERN_)); + +const vector +UPCEANReader::MIDDLE_PATTERN (VECTOR_INIT(MIDDLE_PATTERN_)); +const vector +UPCEANReader::L_PATTERNS (VECTOR_INIT(L_PATTERNS_)); +const vector +UPCEANReader::L_AND_G_PATTERNS (VECTOR_INIT(L_AND_G_PATTERNS_)); + +UPCEANReader::UPCEANReader() {} + +Ref UPCEANReader::decodeRow(int rowNumber, Ref row) { + return decodeRow(rowNumber, row, findStartGuardPattern(row)); +} + +Ref UPCEANReader::decodeRow(int rowNumber, + Ref row, + Range const& startGuardRange) { + if (false) { + std::cerr << "dR " << rowNumber << " " << *row << " " + << startGuardRange[0] << " " << startGuardRange[1] << std::endl; + } + string& result = decodeRowStringBuffer; + result.clear(); + // cerr << "drx " << rowNumber << endl; + int endStart = decodeMiddle(row, startGuardRange, result); + + Range endRange = decodeEnd(row, endStart); + + // Make sure there is a quiet zone at least as big as the end pattern after the barcode. + // The spec might want more whitespace, but in practice this is the maximum we can count on. + + int end = endRange[1]; + int quietEnd = end + (end - endRange[0]); + if (quietEnd >= row->getSize() || !row->isRange(end, quietEnd, false)) { + throw NotFoundException(); + } + + Ref resultString (new String(result)); + if (!checkChecksum(resultString)) { + throw ChecksumException(); + } + + float left = (float) (startGuardRange[1] + startGuardRange[0]) / 2.0f; + float right = (float) (endRange[1] + endRange[0]) / 2.0f; + BarcodeFormat format = getBarcodeFormat(); + ArrayRef< Ref > resultPoints(2); + resultPoints[0] = Ref(new OneDResultPoint(left, (float) rowNumber)); + resultPoints[1] = Ref(new OneDResultPoint(right, (float) rowNumber)); + Ref decodeResult (new Result(resultString, ArrayRef(), resultPoints, format)); + // Java extension and man stuff + return decodeResult; +} + +UPCEANReader::Range UPCEANReader::findStartGuardPattern(Ref row) { + bool foundStart = false; + Range startRange; + int nextStart = 0; + vector counters(START_END_PATTERN.size(), 0); + // std::cerr << "fsgp " << *row << std::endl; + while (!foundStart) { + for(int i=0; i < (int)START_END_PATTERN.size(); ++i) { + counters[i] = 0; } - - const int* UPCEANReader::getMIDDLE_PATTERN() { - return MIDDLE_PATTERN; - } - - UPCEANReader::UPCEANReader() { - } - - - Ref UPCEANReader::decodeRow(int rowNumber, Ref row) { - int rangeStart; - int rangeEnd; - if (findStartGuardPattern(row, &rangeStart, &rangeEnd)) { - try { - return decodeRow(rowNumber, row, rangeStart, rangeEnd); - } catch (ReaderException const& re) { - } - } - return Ref(); - } - - Ref UPCEANReader::decodeRow(int rowNumber, Ref row, int startGuardBegin, - int startGuardEnd) { - std::string tmpResultString; - std::string& tmpResultStringRef = tmpResultString; - int endStart = decodeMiddle(row, startGuardBegin, startGuardEnd, tmpResultStringRef); - if (endStart < 0) { - return Ref(); - } - - int endGuardBegin; - int endGuardEnd; - if (!decodeEnd(row, endStart, &endGuardBegin, &endGuardEnd)) { - return Ref(); - } - - // Make sure there is a quiet zone at least as big as the end pattern after the barcode. - // The spec might want more whitespace, but in practice this is the maximum we can count on. - size_t quietEnd = endGuardEnd + (endGuardEnd - endGuardBegin); - if (quietEnd >= row->getSize() || !row->isRange(endGuardEnd, quietEnd, false)) { - return Ref(); - } - - if (!checkChecksum(tmpResultString)) { - return Ref(); - } - - Ref resultString(new String(tmpResultString)); - float left = (float) (startGuardBegin + startGuardEnd) / 2.0f; - float right = (float) (endGuardBegin + endGuardEnd) / 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); - return Ref(new Result(resultString, resultBytes, resultPoints, getBarcodeFormat())); - } - - bool UPCEANReader::findStartGuardPattern(Ref row, int* rangeStart, int* rangeEnd) { - int nextStart = 0; - while (findGuardPattern(row, nextStart, false, START_END_PATTERN, - sizeof(START_END_PATTERN) / sizeof(int), rangeStart, rangeEnd)) { - int start = *rangeStart; - nextStart = *rangeEnd; - // Make sure there is a quiet zone at least as big as the start pattern before the barcode. - // If this check would run off the left edge of the image, do not accept this barcode, - // as it is very likely to be a false positive. - int quietStart = start - (nextStart - start); - if (quietStart >= 0 && row->isRange(quietStart, start, false)) { - return true; - } - } - return false; - } - - bool UPCEANReader::findGuardPattern(Ref row, int rowOffset, bool whiteFirst, - const int pattern[], int patternLen, int* start, int* end) { - int patternLength = patternLen; - int counters[patternLength]; - int countersCount = sizeof(counters) / sizeof(int); - for (int i = 0; i < countersCount; i++) { - counters[i] = 0; - } - int width = row->getSize(); - bool isWhite = false; - while (rowOffset < width) { - isWhite = !row->get(rowOffset); - if (whiteFirst == isWhite) { - break; - } - rowOffset++; - } - - int counterPosition = 0; - int patternStart = rowOffset; - for (int x = rowOffset; x < width; x++) { - bool pixel = row->get(x); - if (pixel ^ isWhite) { - counters[counterPosition]++; - } else { - if (counterPosition == patternLength - 1) { - if (patternMatchVariance(counters, countersCount, pattern, - MAX_INDIVIDUAL_VARIANCE) < MAX_AVG_VARIANCE) { - *start = patternStart; - *end = x; - return true; - } - 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; - } - } - return false; - } - - bool UPCEANReader::decodeEnd(Ref row, int endStart, int* endGuardBegin, - int* endGuardEnd) { - return findGuardPattern(row, endStart, false, START_END_PATTERN, - sizeof(START_END_PATTERN) / sizeof(int), endGuardBegin, endGuardEnd); - } - - int UPCEANReader::decodeDigit(Ref row, int counters[], int countersLen, int rowOffset, - UPC_EAN_PATTERNS patternType) { - if (!recordPattern(row, rowOffset, counters, countersLen)) { - return -1; - } - unsigned int bestVariance = MAX_AVG_VARIANCE; // worst variance we'll accept - int bestMatch = -1; - - int max = 0; - switch (patternType) { - case UPC_EAN_PATTERNS_L_PATTERNS: - max = L_PATTERNS_LEN; - for (int i = 0; i < max; i++) { - int pattern[countersLen]; - for(int j = 0; j< countersLen; j++){ - pattern[j] = L_PATTERNS[i][j]; - } - - unsigned int variance = patternMatchVariance(counters, countersLen, pattern, - MAX_INDIVIDUAL_VARIANCE); - if (variance < bestVariance) { - bestVariance = variance; - bestMatch = i; - } - } - break; - case UPC_EAN_PATTERNS_L_AND_G_PATTERNS: - max = L_AND_G_PATTERNS_LEN; - for (int i = 0; i < max; i++) { - int pattern[countersLen]; - for(int j = 0; j< countersLen; j++){ - pattern[j] = L_AND_G_PATTERNS[i][j]; - } - - unsigned int variance = patternMatchVariance(counters, countersLen, pattern, - MAX_INDIVIDUAL_VARIANCE); - if (variance < bestVariance) { - bestVariance = variance; - bestMatch = i; - } - } - break; - default: - break; - } - return bestMatch; - } - - /** - * @return {@link #checkStandardUPCEANChecksum(String)} - */ - bool UPCEANReader::checkChecksum(std::string s) { - return checkStandardUPCEANChecksum(s); - } - - /** - * Computes the UPC/EAN checksum on a string of digits, and reports - * whether the checksum is correct or not. - * - * @param s string of digits to check - * @return true iff string of digits passes the UPC/EAN checksum algorithm - */ - bool UPCEANReader::checkStandardUPCEANChecksum(std::string s) { - int length = s.length(); - if (length == 0) { - return false; - } - - int sum = 0; - for (int i = length - 2; i >= 0; i -= 2) { - int digit = (int) s[i] - (int) '0'; - if (digit < 0 || digit > 9) { - return false; - } - sum += digit; - } - sum *= 3; - for (int i = length - 1; i >= 0; i -= 2) { - int digit = (int) s[i] - (int) '0'; - if (digit < 0 || digit > 9) { - return false; - } - sum += digit; - } - return sum % 10 == 0; - } - - UPCEANReader::~UPCEANReader() { + startRange = findGuardPattern(row, nextStart, false, START_END_PATTERN, counters); + // std::cerr << "sr " << startRange[0] << " " << startRange[1] << std::endl; + int start = startRange[0]; + nextStart = startRange[1]; + // Make sure there is a quiet zone at least as big as the start pattern before the barcode. + // If this check would run off the left edge of the image, do not accept this barcode, + // as it is very likely to be a false positive. + int quietStart = start - (nextStart - start); + if (quietStart >= 0) { + foundStart = row->isRange(quietStart, start, false); } } + return startRange; +} + +UPCEANReader::Range UPCEANReader::findGuardPattern(Ref row, + int rowOffset, + bool whiteFirst, + vector const& pattern) { + vector counters (pattern.size(), 0); + return findGuardPattern(row, rowOffset, whiteFirst, pattern, counters); +} + +UPCEANReader::Range UPCEANReader::findGuardPattern(Ref row, + int rowOffset, + bool whiteFirst, + vector const& pattern, + vector& counters) { + // cerr << "fGP " << rowOffset << " " << whiteFirst << endl; + if (false) { + for(int i=0; i < (int)pattern.size(); ++i) { + std::cerr << pattern[i]; + } + std::cerr << std::endl; + } + int patternLength = pattern.size(); + int width = row->getSize(); + bool isWhite = whiteFirst; + rowOffset = whiteFirst ? row->getNextUnset(rowOffset) : row->getNextSet(rowOffset); + int counterPosition = 0; + int patternStart = rowOffset; + for (int x = rowOffset; x < width; x++) { + // std::cerr << "rg " << x << " " << row->get(x) << std::endl; + if (row->get(x) ^ isWhite) { + counters[counterPosition]++; + } else { + if (counterPosition == patternLength - 1) { + if (patternMatchVariance(counters, pattern, MAX_INDIVIDUAL_VARIANCE) < MAX_AVG_VARIANCE) { + return Range(patternStart, x); + } + 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 NotFoundException(); +} + +UPCEANReader::Range UPCEANReader::decodeEnd(Ref row, int endStart) { + return findGuardPattern(row, endStart, false, START_END_PATTERN); +} + +int UPCEANReader::decodeDigit(Ref row, + vector & counters, + int rowOffset, + vector const& patterns) { + recordPattern(row, rowOffset, counters); + int bestVariance = MAX_AVG_VARIANCE; // worst variance we'll accept + int bestMatch = -1; + int max = patterns.size(); + for (int i = 0; i < max; i++) { + int const* pattern (patterns[i]); + int variance = patternMatchVariance(counters, pattern, MAX_INDIVIDUAL_VARIANCE); + if (variance < bestVariance) { + bestVariance = variance; + bestMatch = i; + } + } + if (bestMatch >= 0) { + return bestMatch; + } else { + throw NotFoundException(); + } +} + +/** + * @return {@link #checkStandardUPCEANChecksum(String)} + */ +bool UPCEANReader::checkChecksum(Ref const& s) { + return checkStandardUPCEANChecksum(s); +} + +/** + * Computes the UPC/EAN checksum on a string of digits, and reports + * whether the checksum is correct or not. + * + * @param s string of digits to check + * @return true iff string of digits passes the UPC/EAN checksum algorithm + */ +bool UPCEANReader::checkStandardUPCEANChecksum(Ref const& s_) { + std::string const& s (s_->getText()); + int length = s.length(); + if (length == 0) { + return false; + } + + int sum = 0; + for (int i = length - 2; i >= 0; i -= 2) { + int digit = (int) s[i] - (int) '0'; + if (digit < 0 || digit > 9) { + return false; + } + sum += digit; + } + sum *= 3; + for (int i = length - 1; i >= 0; i -= 2) { + int digit = (int) s[i] - (int) '0'; + if (digit < 0 || digit > 9) { + return false; + } + sum += digit; + } + return sum % 10 == 0; +} + +UPCEANReader::~UPCEANReader() { } diff --git a/cpp/core/src/zxing/oned/UPCEANReader.h b/cpp/core/src/zxing/oned/UPCEANReader.h index 36d0ce0ab..951903176 100644 --- a/cpp/core/src/zxing/oned/UPCEANReader.h +++ b/cpp/core/src/zxing/oned/UPCEANReader.h @@ -22,54 +22,67 @@ #include #include -typedef enum UPC_EAN_PATTERNS { - UPC_EAN_PATTERNS_L_PATTERNS = 0, - UPC_EAN_PATTERNS_L_AND_G_PATTERNS -} UPC_EAN_PATTERNS; - namespace zxing { namespace oned { - class UPCEANReader : public OneDReader { - - private: - enum {MAX_AVG_VARIANCE = (unsigned int) (PATTERN_MATCH_RESULT_SCALE_FACTOR * 420/1000)}; - enum {MAX_INDIVIDUAL_VARIANCE = (int) (PATTERN_MATCH_RESULT_SCALE_FACTOR * 700/1000)}; - - static bool findStartGuardPattern(Ref row, int* rangeStart, int* rangeEnd); - - virtual bool decodeEnd(Ref row, int endStart, int* endGuardBegin, int* endGuardEnd); - - static bool checkStandardUPCEANChecksum(std::string s); - protected: - static bool findGuardPattern(Ref row, int rowOffset, bool whiteFirst, - const int pattern[], int patternLen, int* start, int* end); - - virtual int getMIDDLE_PATTERN_LEN(); - virtual const int* getMIDDLE_PATTERN(); - - public: - UPCEANReader(); - - // Returns < 0 on failure, >= 0 on success. - virtual int decodeMiddle(Ref row, int startGuardBegin, int startGuardEnd, - std::string& resultString) = 0; - - Ref decodeRow(int rowNumber, Ref row); - - // TODO(dswitkin): Should this be virtual so that UPCAReader can override it? - Ref decodeRow(int rowNumber, Ref row, int startGuardBegin, - int startGuardEnd); - - // Returns < 0 on failure, >= 0 on success. - static int decodeDigit(Ref row, int counters[], int countersLen, int rowOffset, - UPC_EAN_PATTERNS patternType); - - virtual bool checkChecksum(std::string s); - - virtual BarcodeFormat getBarcodeFormat() = 0; - virtual ~UPCEANReader(); - }; - } + class MultiFormatUPCEANReader; + class UPCEANReader; + } } +class zxing::oned::UPCEANReader : public OneDReader { + friend class MultiFormatUPCEANReader; +private: + std::string decodeRowStringBuffer; + // UPCEANExtensionSupport extensionReader; + // EANManufacturerOrgSupport eanManSupport; + + static const int MAX_AVG_VARIANCE; + static const int MAX_INDIVIDUAL_VARIANCE; + + static Range findStartGuardPattern(Ref row); + + virtual Range decodeEnd(Ref row, int endStart); + + static bool checkStandardUPCEANChecksum(Ref const& s); + + static Range findGuardPattern(Ref row, + int rowOffset, + bool whiteFirst, + std::vector const& pattern, + std::vector& counters); + + +protected: + static const std::vector START_END_PATTERN; + static const std::vector MIDDLE_PATTERN; + + static const std::vector L_PATTERNS; + static const std::vector L_AND_G_PATTERNS; + + static Range findGuardPattern(Ref row, + int rowOffset, + bool whiteFirst, + std::vector const& pattern); + +public: + UPCEANReader(); + + virtual int decodeMiddle(Ref row, + Range const& startRange, + std::string& resultString) = 0; + + virtual Ref decodeRow(int rowNumber, Ref row); + virtual Ref decodeRow(int rowNumber, Ref row, Range const& range); + + static int decodeDigit(Ref row, + std::vector& counters, + int rowOffset, + std::vector const& patterns); + + virtual bool checkChecksum(Ref const& s); + + virtual BarcodeFormat getBarcodeFormat() = 0; + virtual ~UPCEANReader(); +}; + #endif diff --git a/cpp/core/src/zxing/oned/UPCEReader.cpp b/cpp/core/src/zxing/oned/UPCEReader.cpp index b052dbda9..6a6b963f8 100644 --- a/cpp/core/src/zxing/oned/UPCEReader.cpp +++ b/cpp/core/src/zxing/oned/UPCEReader.cpp @@ -18,125 +18,125 @@ #include "UPCEReader.h" #include -namespace zxing { - namespace oned { +using std::string; +using std::vector; +using zxing::Ref; +using zxing::String; +using zxing::oned::UPCEReader; - /** - * The pattern that marks the middle, and end, of a UPC-E pattern. - * There is no "second half" to a UPC-E barcode. - */ - static const int MIDDLE_END_PATTERN[6] = {1, 1, 1, 1, 1, 1}; +#define VECTOR_INIT(v) v, v + sizeof(v)/sizeof(v[0]) - /** - * See {@link #L_AND_G_PATTERNS}; these values similarly represent patterns of - * even-odd parity encodings of digits that imply both the number system (0 or 1) - * used, and the check digit. - */ - static const int NUMSYS_AND_CHECK_DIGIT_PATTERNS[2][10] = { - {0x38, 0x34, 0x32, 0x31, 0x2C, 0x26, 0x23, 0x2A, 0x29, 0x25}, - {0x07, 0x0B, 0x0D, 0x0E, 0x13, 0x19, 0x1C, 0x15, 0x16, 0x1A} - }; +namespace { + /** + * The pattern that marks the middle, and end, of a UPC-E pattern. + * There is no "second half" to a UPC-E barcode. + */ + const int MIDDLE_END_PATTERN_[6] = {1, 1, 1, 1, 1, 1}; + const vector MIDDLE_END_PATTERN (VECTOR_INIT(MIDDLE_END_PATTERN_)); + - UPCEReader::UPCEReader() { + /** + * See {@link #L_AND_G_PATTERNS}; these values similarly represent patterns of + * even-odd parity encodings of digits that imply both the number system (0 or 1) + * used, and the check digit. + */ + const int NUMSYS_AND_CHECK_DIGIT_PATTERNS[2][10] = { + {0x38, 0x34, 0x32, 0x31, 0x2C, 0x26, 0x23, 0x2A, 0x29, 0x25}, + {0x07, 0x0B, 0x0D, 0x0E, 0x13, 0x19, 0x1C, 0x15, 0x16, 0x1A} + }; +} + +UPCEReader::UPCEReader() { +} + +int UPCEReader::decodeMiddle(Ref row, Range const& startRange, string& result) { + vector& counters (decodeMiddleCounters); + counters.clear(); + counters.resize(4); + int end = row->getSize(); + int rowOffset = startRange[1]; + + int lgPatternFound = 0; + + for (int x = 0; x < 6 && rowOffset < end; x++) { + int bestMatch = decodeDigit(row, counters, rowOffset, L_AND_G_PATTERNS); + result.append(1, (char) ('0' + bestMatch % 10)); + for (int i = 0, e = counters.size(); i < e; i++) { + rowOffset += counters[i]; } - - int UPCEReader::decodeMiddle(Ref row, int startGuardBegin, int startGuardEnd, - std::string& resultString) { - (void)startGuardBegin; - const int countersLen = 4; - int counters[countersLen] = { 0, 0, 0, 0 }; - - int end = row->getSize(); - int rowOffset = startGuardEnd; - int lgPatternFound = 0; - - for (int x = 0; x < 6 && rowOffset < end; x++) { - int bestMatch = decodeDigit(row, counters, countersLen, rowOffset, - UPC_EAN_PATTERNS_L_AND_G_PATTERNS); - if (bestMatch < 0) { - return -1; - } - resultString.append(1, (char) ('0' + bestMatch % 10)); - for (int i = 0; i < countersLen; i++) { - rowOffset += counters[i]; - } - if (bestMatch >= 10) { - lgPatternFound |= 1 << (5 - x); - } - } - - if (!determineNumSysAndCheckDigit(resultString, lgPatternFound)) { - return -1; - } - return rowOffset; - } - - bool UPCEReader::decodeEnd(Ref row, int endStart, int* endGuardBegin, - int* endGuardEnd) { - return findGuardPattern(row, endStart, true, MIDDLE_END_PATTERN, - sizeof(MIDDLE_END_PATTERN) / sizeof(int), endGuardBegin, endGuardEnd); - } - - bool UPCEReader::checkChecksum(std::string s){ - return UPCEANReader::checkChecksum(convertUPCEtoUPCA(s)); - } - - - bool UPCEReader::determineNumSysAndCheckDigit(std::string& resultString, int lgPatternFound) { - for (int numSys = 0; numSys <= 1; numSys++) { - for (int d = 0; d < 10; d++) { - if (lgPatternFound == NUMSYS_AND_CHECK_DIGIT_PATTERNS[numSys][d]) { - resultString.insert(0, 1, (char) ('0' + numSys)); - resultString.append(1, (char) ('0' + d)); - return true; - } - } - } - return false; - } - - /** - * Expands a UPC-E value back into its full, equivalent UPC-A code value. - * - * @param upce UPC-E code as string of digits - * @return equivalent UPC-A code as string of digits - */ - std::string UPCEReader::convertUPCEtoUPCA(std::string upce) { - std::string result; - result.append(1, upce[0]); - char lastChar = upce[6]; - switch (lastChar) { - case '0': - case '1': - case '2': - result.append(upce.substr(1,2)); - result.append(1, lastChar); - result.append("0000"); - result.append(upce.substr(3,3)); - break; - case '3': - result.append(upce.substr(1,3)); - result.append("00000"); - result.append(upce.substr(4,2)); - break; - case '4': - result.append(upce.substr(1,4)); - result.append("00000"); - result.append(1, upce[5]); - break; - default: - result.append(upce.substr(1,5)); - result.append("0000"); - result.append(1, lastChar); - break; - } - result.append(1, upce[7]); - return result; - } - - - BarcodeFormat UPCEReader::getBarcodeFormat() { - return BarcodeFormat_UPC_E; + if (bestMatch >= 10) { + lgPatternFound |= 1 << (5 - x); } } + + determineNumSysAndCheckDigit(result, lgPatternFound); + + return rowOffset; +} + +UPCEReader::Range UPCEReader::decodeEnd(Ref row, int endStart) { + return findGuardPattern(row, endStart, true, MIDDLE_END_PATTERN); +} + +bool UPCEReader::checkChecksum(Ref const& s){ + return UPCEANReader::checkChecksum(convertUPCEtoUPCA(s)); +} + + +bool UPCEReader::determineNumSysAndCheckDigit(std::string& resultString, int lgPatternFound) { + for (int numSys = 0; numSys <= 1; numSys++) { + for (int d = 0; d < 10; d++) { + if (lgPatternFound == NUMSYS_AND_CHECK_DIGIT_PATTERNS[numSys][d]) { + resultString.insert(0, 1, (char) ('0' + numSys)); + resultString.append(1, (char) ('0' + d)); + return true; + } + } + } + return false; +} + +/** + * Expands a UPC-E value back into its full, equivalent UPC-A code value. + * + * @param upce UPC-E code as string of digits + * @return equivalent UPC-A code as string of digits + */ +Ref UPCEReader::convertUPCEtoUPCA(Ref const& upce_) { + string const& upce(upce_->getText()); + string result; + result.append(1, upce[0]); + char lastChar = upce[6]; + switch (lastChar) { + case '0': + case '1': + case '2': + result.append(upce.substr(1,2)); + result.append(1, lastChar); + result.append("0000"); + result.append(upce.substr(3,3)); + break; + case '3': + result.append(upce.substr(1,3)); + result.append("00000"); + result.append(upce.substr(4,2)); + break; + case '4': + result.append(upce.substr(1,4)); + result.append("00000"); + result.append(1, upce[5]); + break; + default: + result.append(upce.substr(1,5)); + result.append("0000"); + result.append(1, lastChar); + break; + } + result.append(1, upce[7]); + return Ref(new String(result)); +} + + +zxing::BarcodeFormat UPCEReader::getBarcodeFormat() { + return BarcodeFormat::UPC_E; } diff --git a/cpp/core/src/zxing/oned/UPCEReader.h b/cpp/core/src/zxing/oned/UPCEReader.h index a6303b19e..cb836d478 100644 --- a/cpp/core/src/zxing/oned/UPCEReader.h +++ b/cpp/core/src/zxing/oned/UPCEReader.h @@ -1,3 +1,4 @@ +// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*- #ifndef __UPC_E_READER_H__ #define __UPC_E_READER_H__ @@ -22,23 +23,25 @@ namespace zxing { namespace oned { - class UPCEReader : public UPCEANReader { - - private: - static bool determineNumSysAndCheckDigit(std::string& resultString, int lgPatternFound); - protected: - bool decodeEnd(Ref row, int endStart, int* endGuardBegin, int* endGuardEnd); - bool checkChecksum(std::string s); - public: - UPCEReader(); - - int decodeMiddle(Ref row, int startGuardBegin, int startGuardEnd, - std::string& resultString); - static std::string convertUPCEtoUPCA(std::string upce); - - BarcodeFormat getBarcodeFormat(); - }; + class UPCEReader; } } +class zxing::oned::UPCEReader : public UPCEANReader { +private: + std::vector decodeMiddleCounters; + static bool determineNumSysAndCheckDigit(std::string& resultString, int lgPatternFound); + +protected: + Range decodeEnd(Ref row, int endStart); + bool checkChecksum(Ref const& s); +public: + UPCEReader(); + + int decodeMiddle(Ref row, Range const& startRange, std::string& resultString); + static Ref convertUPCEtoUPCA(Ref const& upce); + + BarcodeFormat getBarcodeFormat(); +}; + #endif diff --git a/cpp/core/src/zxing/qrcode/FormatInformation.cpp b/cpp/core/src/zxing/qrcode/FormatInformation.cpp index 6f04de890..a2b653c1d 100644 --- a/cpp/core/src/zxing/qrcode/FormatInformation.cpp +++ b/cpp/core/src/zxing/qrcode/FormatInformation.cpp @@ -39,19 +39,18 @@ int FormatInformation::N_FORMAT_INFO_DECODE_LOOKUPS = 32; int FormatInformation::BITS_SET_IN_HALF_BYTE[] = { 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4 }; FormatInformation::FormatInformation(int formatInfo) : - errorCorrectionLevel_(ErrorCorrectionLevel::forBits((formatInfo >> 3) & 0x03)), dataMask_( - (unsigned char)(formatInfo & 0x07)) { + errorCorrectionLevel_(ErrorCorrectionLevel::forBits((formatInfo >> 3) & 0x03)), dataMask_((char)(formatInfo & 0x07)) { } ErrorCorrectionLevel& FormatInformation::getErrorCorrectionLevel() { return errorCorrectionLevel_; } -unsigned char FormatInformation::getDataMask() { +char FormatInformation::getDataMask() { return dataMask_; } -int FormatInformation::numBitsDiffering(unsigned int a, unsigned int b) { +int FormatInformation::numBitsDiffering(int a, int b) { a ^= b; return BITS_SET_IN_HALF_BYTE[a & 0x0F] + BITS_SET_IN_HALF_BYTE[(a >> 4 & 0x0F)] + BITS_SET_IN_HALF_BYTE[(a >> 8 & 0x0F)] + BITS_SET_IN_HALF_BYTE[(a >> 12 & 0x0F)] + BITS_SET_IN_HALF_BYTE[(a >> 16 & 0x0F)] diff --git a/cpp/core/src/zxing/qrcode/FormatInformation.h b/cpp/core/src/zxing/qrcode/FormatInformation.h index 5a07bbbca..7770472c7 100644 --- a/cpp/core/src/zxing/qrcode/FormatInformation.h +++ b/cpp/core/src/zxing/qrcode/FormatInformation.h @@ -35,16 +35,16 @@ private: static int BITS_SET_IN_HALF_BYTE[]; ErrorCorrectionLevel &errorCorrectionLevel_; - unsigned char dataMask_; + char dataMask_; FormatInformation(int formatInfo); public: - static int numBitsDiffering(unsigned int a, unsigned int b); + static int numBitsDiffering(int a, int b); static Ref decodeFormatInformation(int maskedFormatInfo1, int maskedFormatInfo2); static Ref doDecodeFormatInformation(int maskedFormatInfo1, int maskedFormatInfo2); ErrorCorrectionLevel &getErrorCorrectionLevel(); - unsigned char getDataMask(); + char getDataMask(); friend bool operator==(const FormatInformation &a, const FormatInformation &b); friend std::ostream& operator<<(std::ostream& out, const FormatInformation& fi); }; diff --git a/cpp/core/src/zxing/qrcode/QRCodeReader.cpp b/cpp/core/src/zxing/qrcode/QRCodeReader.cpp index e79a3e06e..77d131cf4 100644 --- a/cpp/core/src/zxing/qrcode/QRCodeReader.cpp +++ b/cpp/core/src/zxing/qrcode/QRCodeReader.cpp @@ -49,8 +49,7 @@ namespace zxing { cout << "(2) detected, have detectorResult " << detectorResult.object_ << "\n" << flush; #endif - std::vector > points(detectorResult->getPoints()); - + ArrayRef< Ref > points (detectorResult->getPoints()); #ifdef DEBUG cout << "(3) extracted points " << &points << "\n" << flush; @@ -68,7 +67,7 @@ namespace zxing { #endif Ref result( - new Result(decoderResult->getText(), decoderResult->getRawBytes(), points, BarcodeFormat_QR_CODE)); + new Result(decoderResult->getText(), decoderResult->getRawBytes(), points, BarcodeFormat::QR_CODE)); #ifdef DEBUG cout << "(5) created result " << result.object_ << ", returning\n" << flush; #endif diff --git a/cpp/core/src/zxing/qrcode/decoder/BitMatrixParser.cpp b/cpp/core/src/zxing/qrcode/decoder/BitMatrixParser.cpp index 8554a1cd3..ea80bd58e 100644 --- a/cpp/core/src/zxing/qrcode/decoder/BitMatrixParser.cpp +++ b/cpp/core/src/zxing/qrcode/decoder/BitMatrixParser.cpp @@ -116,7 +116,7 @@ Version *BitMatrixParser::readVersion() { throw ReaderException("Could not decode version"); } -ArrayRef BitMatrixParser::readCodewords() { +ArrayRef BitMatrixParser::readCodewords() { Ref formatInfo = readFormatInformation(); Version *version = readVersion(); @@ -141,7 +141,7 @@ ArrayRef BitMatrixParser::readCodewords() { // cout << *functionPattern << endl; bool readingUp = true; - ArrayRef result(version->getTotalCodewords()); + ArrayRef result(version->getTotalCodewords()); int resultOffset = 0; int currentByte = 0; int bitsRead = 0; @@ -166,7 +166,7 @@ ArrayRef BitMatrixParser::readCodewords() { } // If we've made a whole byte, save it off if (bitsRead == 8) { - result[resultOffset++] = (unsigned char)currentByte; + result[resultOffset++] = (char)currentByte; bitsRead = 0; currentByte = 0; } diff --git a/cpp/core/src/zxing/qrcode/decoder/BitMatrixParser.h b/cpp/core/src/zxing/qrcode/decoder/BitMatrixParser.h index 50d170ab4..877d8958c 100644 --- a/cpp/core/src/zxing/qrcode/decoder/BitMatrixParser.h +++ b/cpp/core/src/zxing/qrcode/decoder/BitMatrixParser.h @@ -42,7 +42,7 @@ public: BitMatrixParser(Ref bitMatrix); Ref readFormatInformation(); Version *readVersion(); - ArrayRef readCodewords(); + ArrayRef readCodewords(); private: BitMatrixParser(const BitMatrixParser&); diff --git a/cpp/core/src/zxing/qrcode/decoder/DataBlock.cpp b/cpp/core/src/zxing/qrcode/decoder/DataBlock.cpp index 1ea6602d7..a03aa94cf 100644 --- a/cpp/core/src/zxing/qrcode/decoder/DataBlock.cpp +++ b/cpp/core/src/zxing/qrcode/decoder/DataBlock.cpp @@ -26,7 +26,7 @@ namespace qrcode { using namespace std; -DataBlock::DataBlock(int numDataCodewords, ArrayRef codewords) : +DataBlock::DataBlock(int numDataCodewords, ArrayRef codewords) : numDataCodewords_(numDataCodewords), codewords_(codewords) { } @@ -34,12 +34,12 @@ int DataBlock::getNumDataCodewords() { return numDataCodewords_; } -ArrayRef DataBlock::getCodewords() { +ArrayRef DataBlock::getCodewords() { return codewords_; } -std::vector > DataBlock::getDataBlocks(ArrayRef rawCodewords, Version *version, +std::vector > DataBlock::getDataBlocks(ArrayRef rawCodewords, Version *version, ErrorCorrectionLevel &ecLevel) { @@ -63,7 +63,7 @@ std::vector > DataBlock::getDataBlocks(ArrayRef ra for (int i = 0; i < ecBlock->getCount(); i++) { int numDataCodewords = ecBlock->getDataCodewords(); int numBlockCodewords = ecBlocks.getECCodewords() + numDataCodewords; - ArrayRef buffer(numBlockCodewords); + ArrayRef buffer(numBlockCodewords); Ref blockRef(new DataBlock(numDataCodewords, buffer)); result[numResultBlocks++] = blockRef; } @@ -107,7 +107,7 @@ std::vector > DataBlock::getDataBlocks(ArrayRef ra } } - if ((size_t)rawCodewordsOffset != rawCodewords.size()) { + if (rawCodewordsOffset != rawCodewords.size()) { throw IllegalArgumentException("rawCodewordsOffset != rawCodewords.length"); } diff --git a/cpp/core/src/zxing/qrcode/decoder/DataBlock.h b/cpp/core/src/zxing/qrcode/decoder/DataBlock.h index 6c8b462a2..f314530f0 100644 --- a/cpp/core/src/zxing/qrcode/decoder/DataBlock.h +++ b/cpp/core/src/zxing/qrcode/decoder/DataBlock.h @@ -32,16 +32,16 @@ namespace qrcode { class DataBlock : public Counted { private: int numDataCodewords_; - ArrayRef codewords_; + ArrayRef codewords_; - DataBlock(int numDataCodewords, ArrayRef codewords); + DataBlock(int numDataCodewords, ArrayRef codewords); public: static std::vector > - getDataBlocks(ArrayRef rawCodewords, Version *version, ErrorCorrectionLevel &ecLevel); + getDataBlocks(ArrayRef rawCodewords, Version *version, ErrorCorrectionLevel &ecLevel); int getNumDataCodewords(); - ArrayRef getCodewords(); + ArrayRef getCodewords(); }; } diff --git a/cpp/core/src/zxing/qrcode/decoder/DecodedBitStreamParser.cpp b/cpp/core/src/zxing/qrcode/decoder/DecodedBitStreamParser.cpp index b3571ed7b..10ad1f4df 100644 --- a/cpp/core/src/zxing/qrcode/decoder/DecodedBitStreamParser.cpp +++ b/cpp/core/src/zxing/qrcode/decoder/DecodedBitStreamParser.cpp @@ -55,11 +55,11 @@ namespace {int GB2312_SUBSET = 1;} void DecodedBitStreamParser::append(std::string &result, string const& in, const char *src) { - append(result, (unsigned char const*)in.c_str(), in.length(), src); + append(result, (char const*)in.c_str(), in.length(), src); } void DecodedBitStreamParser::append(std::string &result, - const unsigned char *bufIn, + const char *bufIn, size_t nIn, const char *src) { #ifndef NO_ICONV @@ -74,7 +74,7 @@ void DecodedBitStreamParser::append(std::string &result, } const int maxOut = 4 * nIn + 1; - unsigned char* bufOut = new unsigned char[maxOut]; + char* bufOut = new char[maxOut]; ICONV_CONST char *fromPtr = (ICONV_CONST char *)bufIn; size_t nFrom = nIn; @@ -112,7 +112,7 @@ void DecodedBitStreamParser::decodeHanziSegment(Ref bits_, // Each character will require 2 bytes. Read the characters as 2-byte pairs // and decode as GB2312 afterwards size_t nBytes = 2 * count; - unsigned char* buffer = new unsigned char[nBytes]; + char* buffer = new char[nBytes]; int offset = 0; while (count > 0) { // Each 13 bits encodes a 2-byte character @@ -125,8 +125,8 @@ void DecodedBitStreamParser::decodeHanziSegment(Ref bits_, // In the 0xB0A1 to 0xFAFE range assembledTwoBytes += 0x0A6A1; } - buffer[offset] = (unsigned char) ((assembledTwoBytes >> 8) & 0xFF); - buffer[offset + 1] = (unsigned char) (assembledTwoBytes & 0xFF); + buffer[offset] = (char) ((assembledTwoBytes >> 8) & 0xFF); + buffer[offset + 1] = (char) (assembledTwoBytes & 0xFF); offset += 2; count--; } @@ -145,7 +145,7 @@ void DecodedBitStreamParser::decodeKanjiSegment(Ref bits, std::string // Each character will require 2 bytes. Read the characters as 2-byte pairs // and decode as Shift_JIS afterwards size_t nBytes = 2 * count; - unsigned char* buffer = new unsigned char[nBytes]; + char* buffer = new char[nBytes]; int offset = 0; while (count > 0) { // Each 13 bits encodes a 2-byte character @@ -159,8 +159,8 @@ void DecodedBitStreamParser::decodeKanjiSegment(Ref bits, std::string // In the 0xE040 to 0xEBBF range assembledTwoBytes += 0x0C140; } - buffer[offset] = (unsigned char)(assembledTwoBytes >> 8); - buffer[offset + 1] = (unsigned char)assembledTwoBytes; + buffer[offset] = (char)(assembledTwoBytes >> 8); + buffer[offset + 1] = (char)assembledTwoBytes; offset += 2; count--; } @@ -173,7 +173,7 @@ void DecodedBitStreamParser::decodeByteSegment(Ref bits_, string& result, int count, CharacterSetECI* currentCharacterSetECI, - ArrayRef< ArrayRef >& byteSegments, + ArrayRef< ArrayRef >& byteSegments, Hashtable const& hints) { int nBytes = count; BitSource& bits (*bits_); @@ -182,10 +182,10 @@ void DecodedBitStreamParser::decodeByteSegment(Ref bits_, throw FormatException(); } - ArrayRef bytes_ (count); - unsigned char* readBytes = &(*bytes_)[0]; + ArrayRef bytes_ (count); + char* readBytes = &(*bytes_)[0]; for (int i = 0; i < count; i++) { - readBytes[i] = (unsigned char) bits.readBits(8); + readBytes[i] = (char) bits.readBits(8); } string encoding; if (currentCharacterSetECI == 0) { @@ -208,7 +208,7 @@ void DecodedBitStreamParser::decodeByteSegment(Ref bits_, void DecodedBitStreamParser::decodeNumericSegment(Ref bits, std::string &result, int count) { int nBytes = count; - unsigned char* bytes = new unsigned char[nBytes]; + char* bytes = new char[nBytes]; int i = 0; // Read three digits at a time while (count >= 3) { @@ -335,7 +335,7 @@ namespace { } Ref -DecodedBitStreamParser::decode(ArrayRef bytes, +DecodedBitStreamParser::decode(ArrayRef bytes, Version* version, ErrorCorrectionLevel const& ecLevel, Hashtable const& hints) { @@ -344,7 +344,7 @@ DecodedBitStreamParser::decode(ArrayRef bytes, string result; CharacterSetECI* currentCharacterSetECI = 0; bool fc1InEffect = false; - ArrayRef< ArrayRef > byteSegments (size_t(0)); + ArrayRef< ArrayRef > byteSegments (0); Mode* mode = 0; do { // While still another segment to read... diff --git a/cpp/core/src/zxing/qrcode/decoder/DecodedBitStreamParser.h b/cpp/core/src/zxing/qrcode/decoder/DecodedBitStreamParser.h index 086c31c96..6f4d7d3e5 100644 --- a/cpp/core/src/zxing/qrcode/decoder/DecodedBitStreamParser.h +++ b/cpp/core/src/zxing/qrcode/decoder/DecodedBitStreamParser.h @@ -51,16 +51,16 @@ private: std::string& result, int count, zxing::common::CharacterSetECI* currentCharacterSetECI, - ArrayRef< ArrayRef >& byteSegments, + ArrayRef< ArrayRef >& byteSegments, Hashtable const& hints); static void decodeAlphanumericSegment(Ref bits, std::string &result, int count, bool fc1InEffect); static void decodeNumericSegment(Ref bits, std::string &result, int count); - static void append(std::string &ost, const unsigned char *bufIn, size_t nIn, const char *src); + static void append(std::string &ost, const char *bufIn, size_t nIn, const char *src); static void append(std::string &ost, std::string const& in, const char *src); public: - static Ref decode(ArrayRef bytes, + static Ref decode(ArrayRef bytes, Version *version, ErrorCorrectionLevel const& ecLevel, Hashtable const& hints); diff --git a/cpp/core/src/zxing/qrcode/decoder/Decoder.cpp b/cpp/core/src/zxing/qrcode/decoder/Decoder.cpp index 59610c2ae..67642633e 100644 --- a/cpp/core/src/zxing/qrcode/decoder/Decoder.cpp +++ b/cpp/core/src/zxing/qrcode/decoder/Decoder.cpp @@ -36,7 +36,7 @@ Decoder::Decoder() : rsDecoder_(GenericGF::QR_CODE_FIELD_256) { } -void Decoder::correctErrors(ArrayRef codewordBytes, int numDataCodewords) { +void Decoder::correctErrors(ArrayRef codewordBytes, int numDataCodewords) { int numCodewords = codewordBytes->size(); ArrayRef codewordInts(numCodewords); for (int i = 0; i < numCodewords; i++) { @@ -52,7 +52,7 @@ void Decoder::correctErrors(ArrayRef codewordBytes, int numDataCo } for (int i = 0; i < numDataCodewords; i++) { - codewordBytes[i] = (unsigned char)codewordInts[i]; + codewordBytes[i] = (char)codewordInts[i]; } } @@ -60,12 +60,14 @@ Ref Decoder::decode(Ref bits) { // Construct a parser and read version, error-correction level BitMatrixParser parser(bits); + // std::cerr << *bits << std::endl; + Version *version = parser.readVersion(); ErrorCorrectionLevel &ecLevel = parser.readFormatInformation()->getErrorCorrectionLevel(); // Read codewords - ArrayRef codewords(parser.readCodewords()); + ArrayRef codewords(parser.readCodewords()); // Separate into data blocks @@ -77,14 +79,14 @@ Ref Decoder::decode(Ref bits) { for (size_t i = 0; i < dataBlocks.size(); i++) { totalBytes += dataBlocks[i]->getNumDataCodewords(); } - ArrayRef resultBytes(totalBytes); + ArrayRef resultBytes(totalBytes); int resultOffset = 0; // Error-correct and copy data blocks together into a stream of bytes for (size_t j = 0; j < dataBlocks.size(); j++) { Ref dataBlock(dataBlocks[j]); - ArrayRef codewordBytes = dataBlock->getCodewords(); + ArrayRef codewordBytes = dataBlock->getCodewords(); int numDataCodewords = dataBlock->getNumDataCodewords(); correctErrors(codewordBytes, numDataCodewords); for (int i = 0; i < numDataCodewords; i++) { diff --git a/cpp/core/src/zxing/qrcode/decoder/Decoder.h b/cpp/core/src/zxing/qrcode/decoder/Decoder.h index bbfd9b72d..31ca6bd9a 100644 --- a/cpp/core/src/zxing/qrcode/decoder/Decoder.h +++ b/cpp/core/src/zxing/qrcode/decoder/Decoder.h @@ -33,7 +33,7 @@ class Decoder { private: ReedSolomonDecoder rsDecoder_; - void correctErrors(ArrayRef bytes, int numDataCodewords); + void correctErrors(ArrayRef bytes, int numDataCodewords); public: Decoder(); diff --git a/cpp/core/src/zxing/qrcode/detector/Detector.cpp b/cpp/core/src/zxing/qrcode/detector/Detector.cpp index fa1d8bc43..5cbd47782 100644 --- a/cpp/core/src/zxing/qrcode/detector/Detector.cpp +++ b/cpp/core/src/zxing/qrcode/detector/Detector.cpp @@ -111,7 +111,7 @@ Ref Detector::processFinderPatternInfo(Ref in Ref transform = createTransform(topLeft, topRight, bottomLeft, alignmentPattern, dimension); Ref bits(sampleGrid(image_, dimension, transform)); - std::vector > points(alignmentPattern == 0 ? 3 : 4); + ArrayRef< Ref > points(new Array< Ref >(alignmentPattern == 0 ? 3 : 4)); points[0].reset(bottomLeft); points[1].reset(topLeft); points[2].reset(topRight); diff --git a/cpp/core/src/zxing/qrcode/detector/FinderPattern.cpp b/cpp/core/src/zxing/qrcode/detector/FinderPattern.cpp index 32c64da7f..1701ff5b3 100644 --- a/cpp/core/src/zxing/qrcode/detector/FinderPattern.cpp +++ b/cpp/core/src/zxing/qrcode/detector/FinderPattern.cpp @@ -28,10 +28,13 @@ namespace zxing { FinderPattern::FinderPattern(float posX, float posY, float estimatedModuleSize) : ResultPoint(posX,posY), estimatedModuleSize_(estimatedModuleSize), count_(1) { + // cerr << "fpc " << getX() << " " << getY() << " " << count_ << endl; + // cerr << "fp " << getX() << " " << getY() << endl; } FinderPattern::FinderPattern(float posX, float posY, float estimatedModuleSize, int count) : ResultPoint(posX,posY), estimatedModuleSize_(estimatedModuleSize), count_(count) { + // cerr << "fpc " << getX() << " " << getY() << " " << count << endl; } int FinderPattern::getCount() const { @@ -44,6 +47,7 @@ namespace zxing { void FinderPattern::incrementCount() { count_++; + // cerr << "ic " << getX() << " " << getY() << " " << count_ << endl; } /* @@ -61,6 +65,8 @@ namespace zxing { } Ref FinderPattern::combineEstimate(float i, float j, float newModuleSize) const { + // fprintf(stderr, "ce %f %f %f\n", i, j, newModuleSize); + int combinedCount = count_ + 1; float combinedX = (count_ * getX() + j) / combinedCount; float combinedY = (count_ * getY() + i) / combinedCount; diff --git a/cpp/magick/src/MagickBitmapSource.cpp b/cpp/magick/src/MagickBitmapSource.cpp index 16d1ac730..0d913e0eb 100644 --- a/cpp/magick/src/MagickBitmapSource.cpp +++ b/cpp/magick/src/MagickBitmapSource.cpp @@ -1,3 +1,4 @@ +// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*- /* * Copyright 2010-2011 ZXing authors * @@ -20,12 +21,14 @@ using namespace Magick; -namespace zxing { +using zxing::ArrayRef; +using zxing::Ref; +using zxing::LuminanceSource; +using zxing::MagickBitmapSource; MagickBitmapSource::MagickBitmapSource(Image& image) : image_(image) { width = image.columns(); height = image.rows(); - } MagickBitmapSource::~MagickBitmapSource() { @@ -39,35 +42,37 @@ int MagickBitmapSource::getHeight() const { return height; } -unsigned char* MagickBitmapSource::getRow(int y, unsigned char* row) { - const Magick::PixelPacket* pixel_cache = image_.getConstPixels(0, y, width, 1); +ArrayRef MagickBitmapSource::getRow(int y, ArrayRef row) { + const Magick::PixelPacket* pixel_cache = + image_.getConstPixels(0, y, width, 1); + int width = getWidth(); - if (row == NULL) { - row = new unsigned char[width]; + if (!row || row->size() < width) { + row =ArrayRef(width); } for (int x = 0; x < width; x++) { const PixelPacket* p = pixel_cache + x; // We assume 16 bit values here // 0x200 = 1<<9, half an lsb of the result to force rounding - row[x] = (unsigned char)((306 * ((int)p->red >> 8) + 601 * ((int)p->green >> 8) + - 117 * ((int)p->blue >> 8) + 0x200) >> 10); + row[x] = (char)((306 * ((int)p->red >> 8) + 601 * ((int)p->green >> 8) + + 117 * ((int)p->blue >> 8) + 0x200) >> 10); } return row; } /** This is a more efficient implementation. */ -unsigned char* MagickBitmapSource::getMatrix() { +ArrayRef MagickBitmapSource::getMatrix() { const Magick::PixelPacket* pixel_cache = image_.getConstPixels(0, 0, width, height); int width = getWidth(); int height = getHeight(); - unsigned char* matrix = new unsigned char[width*height]; - unsigned char* m = matrix; + ArrayRef matrix = ArrayRef(width*height); + char* m = &matrix[0]; const Magick::PixelPacket* p = pixel_cache; for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { *m = (unsigned char)((306 * ((int)p->red >> 8) + 601 * ((int)p->green >> 8) + - 117 * ((int)p->blue >> 8) + 0x200) >> 10); + 117 * ((int)p->blue >> 8) + 0x200) >> 10); m++; p++; } @@ -100,6 +105,3 @@ Ref MagickBitmapSource::crop(int left, int top, int width, int copy.syncPixels(); return Ref(new MagickBitmapSource(copy)); } - -} - diff --git a/cpp/magick/src/MagickBitmapSource.h b/cpp/magick/src/MagickBitmapSource.h index ed556007d..dd7fd3a97 100644 --- a/cpp/magick/src/MagickBitmapSource.h +++ b/cpp/magick/src/MagickBitmapSource.h @@ -1,3 +1,4 @@ +// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*- #ifndef __MAGICK_BITMAP_SOURCE_H_ #define __MAGICK_BITMAP_SOURCE_H_ /* @@ -20,8 +21,10 @@ #include namespace zxing { + class MagickBitmapSource; +} -class MagickBitmapSource : public LuminanceSource { +class zxing::MagickBitmapSource : public LuminanceSource { private: Magick::Image image_; int width; @@ -34,14 +37,12 @@ public: int getWidth() const; int getHeight() const; - unsigned char* getRow(int y, unsigned char* row); - unsigned char* getMatrix(); + ArrayRef getRow(int y, ArrayRef row); + ArrayRef getMatrix(); bool isCropSupported() const; Ref crop(int left, int top, int width, int height); bool isRotateSupported() const; Ref rotateCounterClockwise(); }; -} - #endif /* MAGICKMONOCHROMEBITMAPSOURCE_H_ */ diff --git a/cpp/magick/src/main.cpp b/cpp/magick/src/main.cpp index 6c4ea8bb2..14bdf2087 100644 --- a/cpp/magick/src/main.cpp +++ b/cpp/magick/src/main.cpp @@ -96,7 +96,7 @@ int test_image(Image& image, bool hybrid, string expected = "") { Ref binary(new BinaryBitmap(binarizer)); Ref result(decode(binary, hints)); cell_result = result->getText()->getText(); - result_format = barcodeFormatNames[result->getBarcodeFormat()]; + result_format = BarcodeFormat::barcodeFormatNames[result->getBarcodeFormat()]; res = 0; } catch (ReaderException e) { cell_result = "zxing::ReaderException: " + string(e.what()); @@ -183,7 +183,7 @@ int test_image_multi(Image& image, bool hybrid){ for (unsigned int i = 0; i < results.size(); i++){ cout << " "<getText()->getText(); if (show_format) { - cout << " " << barcodeFormatNames[results[i]->getBarcodeFormat()]; + cout << " " << BarcodeFormat::barcodeFormatNames[results[i]->getBarcodeFormat()]; } cout << endl; }