C++ 1D/cleanup first pass

git-svn-id: https://zxing.googlecode.com/svn/trunk@2603 59b500cc-1b3d-0410-9834-0bbf25fbcc57
This commit is contained in:
smparkes@smparkes.net 2013-04-01 05:59:09 +00:00
parent 4e0a75346d
commit 4d28115073
108 changed files with 4092 additions and 2984 deletions

1
cpp/.gdbinit Normal file
View file

@ -0,0 +1 @@
set history save on

View file

@ -1,14 +1,12 @@
{ {
zxing::common::CharacterSetECI::init_tables dlsym
Memcheck:Leak Memcheck:Value8
fun:malloc fun:_simple_salloc
... fun:_ZN4dyld9mkstringfEPKcz
fun:_ZN5zxing6common15CharacterSetECI11init_tablesEv
}
}
{ {
ImageMagick dlsym
Memcheck:Leak Memcheck:Cond
... fun:_ZN4dyld9mkstringfEPKcz
fun:AcquireImage
} }

34
cpp/core/src/zxing/BarcodeFormat.cpp Executable file → Normal file
View file

@ -18,20 +18,22 @@
#include <zxing/BarcodeFormat.h> #include <zxing/BarcodeFormat.h>
namespace zxing { const char* zxing::BarcodeFormat::barcodeFormatNames[] = {
"AZTEC",
const char *barcodeFormatNames[] = { "CODABAR",
"None", "CODE_39",
"QR_CODE", "CODE_93",
"DATA_MATRIX", "CODE_128",
"UPC_E", "DATA_MATRIX",
"UPC_A", "EAN_8",
"EAN_8", "EAN_13",
"EAN_13", "ITF",
"CODE_128", "MAXICODE",
"CODE_39", "PDF_417",
"ITF", "QR_CODE",
"AZTEC" "RSS_14",
"RSS_EXPANDED",
"UPC_A",
"UPC_E",
"UPC_EAN_EXTENSION",
}; };
}

View file

@ -22,23 +22,41 @@
*/ */
namespace zxing { namespace zxing {
class BarcodeFormat;
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;
/* if you update the enum, please update the name in BarcodeFormat.cpp */ class zxing::BarcodeFormat {
extern const char *barcodeFormatNames[]; 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__ #endif // __BARCODE_FORMAT_H__

View file

@ -1,3 +1,4 @@
// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*-
/* /*
* BinaryBitmap.cpp * BinaryBitmap.cpp
* zxing * zxing
@ -19,49 +20,51 @@
#include <zxing/BinaryBitmap.h> #include <zxing/BinaryBitmap.h>
namespace zxing { using zxing::Ref;
using zxing::BitArray;
using zxing::BitMatrix;
using zxing::LuminanceSource;
using zxing::BinaryBitmap;
BinaryBitmap::BinaryBitmap(Ref<Binarizer> binarizer) : binarizer_(binarizer) { BinaryBitmap::BinaryBitmap(Ref<Binarizer> binarizer) : binarizer_(binarizer) {
}
}
BinaryBitmap::~BinaryBitmap() {
BinaryBitmap::~BinaryBitmap() { }
}
Ref<BitArray> BinaryBitmap::getBlackRow(int y, Ref<BitArray> row) {
Ref<BitArray> BinaryBitmap::getBlackRow(int y, Ref<BitArray> row) { return binarizer_->getBlackRow(y, row);
return binarizer_->getBlackRow(y, row); }
}
Ref<BitMatrix> BinaryBitmap::getBlackMatrix() {
Ref<BitMatrix> BinaryBitmap::getBlackMatrix() { return binarizer_->getBlackMatrix();
return binarizer_->getBlackMatrix(); }
}
int BinaryBitmap::getWidth() const {
int BinaryBitmap::getWidth() const { return getLuminanceSource()->getWidth();
return getLuminanceSource()->getWidth(); }
}
int BinaryBitmap::getHeight() const {
int BinaryBitmap::getHeight() const { return getLuminanceSource()->getHeight();
return getLuminanceSource()->getHeight(); }
}
Ref<LuminanceSource> BinaryBitmap::getLuminanceSource() const {
Ref<LuminanceSource> BinaryBitmap::getLuminanceSource() const { return binarizer_->getLuminanceSource();
return binarizer_->getLuminanceSource(); }
}
bool BinaryBitmap::isCropSupported() const {
bool BinaryBitmap::isCropSupported() const { return getLuminanceSource()->isCropSupported();
return getLuminanceSource()->isCropSupported(); }
}
Ref<BinaryBitmap> BinaryBitmap::crop(int left, int top, int width, int height) {
Ref<BinaryBitmap> BinaryBitmap::crop(int left, int top, int width, int height) { return Ref<BinaryBitmap> (new BinaryBitmap(binarizer_->createBinarizer(getLuminanceSource()->crop(left, top, width, height))));
return Ref<BinaryBitmap> (new BinaryBitmap(binarizer_->createBinarizer(getLuminanceSource()->crop(left, top, width, height)))); }
}
bool BinaryBitmap::isRotateSupported() const {
bool BinaryBitmap::isRotateSupported() const { return getLuminanceSource()->isRotateSupported();
return getLuminanceSource()->isRotateSupported(); }
}
Ref<BinaryBitmap> BinaryBitmap::rotateCounterClockwise() {
Ref<BinaryBitmap> BinaryBitmap::rotateCounterClockwise() { return Ref<BinaryBitmap> (new BinaryBitmap(binarizer_->createBinarizer(getLuminanceSource()->rotateCounterClockwise())));
return Ref<BinaryBitmap> (new BinaryBitmap(binarizer_->createBinarizer(getLuminanceSource()->rotateCounterClockwise())));
}
} }

View file

@ -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 <zxing/ChecksumException.h>
namespace zxing {
ChecksumException::ChecksumException() {}
ChecksumException::ChecksumException(const char *msg) :
ReaderException(msg) {
}
ChecksumException::~ChecksumException() throw() {
}
ChecksumException const&
ChecksumException::getChecksumInstance() {
static ChecksumException instance;
return instance;
}
}

View file

@ -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 <zxing/ReaderException.h>
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__

View file

@ -1,3 +1,4 @@
// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*-
/* /*
* DecodeHintType.cpp * DecodeHintType.cpp
* zxing * zxing
@ -19,36 +20,37 @@
#include <zxing/DecodeHints.h> #include <zxing/DecodeHints.h>
#include <zxing/common/IllegalArgumentException.h> #include <zxing/common/IllegalArgumentException.h>
namespace zxing {
using zxing::Ref;
using zxing::ResultPointCallback;
using zxing::DecodeHintType;
using zxing::DecodeHints;
const DecodeHintType DecodeHints::CHARACTER_SET; const DecodeHintType DecodeHints::CHARACTER_SET;
const DecodeHints DecodeHints::PRODUCT_HINT( const DecodeHints DecodeHints::PRODUCT_HINT(
BARCODEFORMAT_UPC_E_HINT | UPC_A_HINT |
BARCODEFORMAT_UPC_A_HINT | UPC_E_HINT |
BARCODEFORMAT_EAN_8_HINT | EAN_13_HINT |
BARCODEFORMAT_EAN_13_HINT); EAN_8_HINT |
RSS_14_HINT
);
const DecodeHints DecodeHints::ONED_HINT( const DecodeHints DecodeHints::ONED_HINT(
BARCODEFORMAT_UPC_E_HINT | CODE_39_HINT |
BARCODEFORMAT_UPC_A_HINT | CODE_93_HINT |
BARCODEFORMAT_EAN_8_HINT | CODE_128_HINT |
BARCODEFORMAT_EAN_13_HINT | ITF_HINT |
BARCODEFORMAT_CODE_128_HINT | CODABAR_HINT |
BARCODEFORMAT_CODE_39_HINT | DecodeHints::PRODUCT_HINT
BARCODEFORMAT_ITF_HINT); );
const DecodeHints DecodeHints::DEFAULT_HINT( const DecodeHints DecodeHints::DEFAULT_HINT(
BARCODEFORMAT_UPC_E_HINT | ONED_HINT |
BARCODEFORMAT_UPC_A_HINT | QR_CODE_HINT |
BARCODEFORMAT_EAN_8_HINT | DATA_MATRIX_HINT |
BARCODEFORMAT_EAN_13_HINT | AZTEC_HINT
BARCODEFORMAT_CODE_128_HINT | );
BARCODEFORMAT_CODE_39_HINT |
BARCODEFORMAT_ITF_HINT |
BARCODEFORMAT_DATA_MATRIX_HINT |
BARCODEFORMAT_AZTEC_HINT |
BARCODEFORMAT_QR_CODE_HINT);
DecodeHints::DecodeHints() { DecodeHints::DecodeHints() {
hints = 0; hints = 0;
@ -60,34 +62,46 @@ DecodeHints::DecodeHints(DecodeHintType init) {
void DecodeHints::addFormat(BarcodeFormat toadd) { void DecodeHints::addFormat(BarcodeFormat toadd) {
switch (toadd) { switch (toadd) {
case BarcodeFormat_AZTEC: hints |= BARCODEFORMAT_AZTEC_HINT; break; case BarcodeFormat::AZTEC: hints |= AZTEC_HINT; break;
case BarcodeFormat_QR_CODE: hints |= BARCODEFORMAT_QR_CODE_HINT; break; case BarcodeFormat::CODABAR: hints |= CODABAR_HINT; break;
case BarcodeFormat_DATA_MATRIX: hints |= BARCODEFORMAT_DATA_MATRIX_HINT; break; case BarcodeFormat::CODE_39: hints |= CODE_39_HINT; break;
case BarcodeFormat_UPC_E: hints |= BARCODEFORMAT_UPC_E_HINT; break; case BarcodeFormat::CODE_93: hints |= CODE_93_HINT; break;
case BarcodeFormat_UPC_A: hints |= BARCODEFORMAT_UPC_A_HINT; break; case BarcodeFormat::CODE_128: hints |= CODE_128_HINT; break;
case BarcodeFormat_EAN_8: hints |= BARCODEFORMAT_EAN_8_HINT; break; case BarcodeFormat::DATA_MATRIX: hints |= DATA_MATRIX_HINT; break;
case BarcodeFormat_EAN_13: hints |= BARCODEFORMAT_EAN_13_HINT; break; case BarcodeFormat::EAN_8: hints |= EAN_8_HINT; break;
case BarcodeFormat_CODE_128: hints |= BARCODEFORMAT_CODE_128_HINT; break; case BarcodeFormat::EAN_13: hints |= EAN_13_HINT; break;
case BarcodeFormat_CODE_39: hints |= BARCODEFORMAT_CODE_39_HINT; break; case BarcodeFormat::ITF: hints |= ITF_HINT; break;
case BarcodeFormat_ITF: hints |= BARCODEFORMAT_ITF_HINT; break; case BarcodeFormat::MAXICODE: hints |= MAXICODE_HINT; break;
default: throw IllegalArgumentException("Unrecognizd barcode format"); 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 { bool DecodeHints::containsFormat(BarcodeFormat tocheck) const {
DecodeHintType checkAgainst; DecodeHintType checkAgainst = 0;
switch (tocheck) { switch (tocheck) {
case BarcodeFormat_AZTEC: checkAgainst = BARCODEFORMAT_AZTEC_HINT; break; case BarcodeFormat::AZTEC: checkAgainst |= AZTEC_HINT; break;
case BarcodeFormat_QR_CODE: checkAgainst = BARCODEFORMAT_QR_CODE_HINT; break; case BarcodeFormat::CODABAR: checkAgainst |= CODABAR_HINT; break;
case BarcodeFormat_DATA_MATRIX: checkAgainst = BARCODEFORMAT_DATA_MATRIX_HINT; break; case BarcodeFormat::CODE_39: checkAgainst |= CODE_39_HINT; break;
case BarcodeFormat_UPC_E: checkAgainst = BARCODEFORMAT_UPC_E_HINT; break; case BarcodeFormat::CODE_93: checkAgainst |= CODE_93_HINT; break;
case BarcodeFormat_UPC_A: checkAgainst = BARCODEFORMAT_UPC_A_HINT; break; case BarcodeFormat::CODE_128: checkAgainst |= CODE_128_HINT; break;
case BarcodeFormat_EAN_8: checkAgainst = BARCODEFORMAT_EAN_8_HINT; break; case BarcodeFormat::DATA_MATRIX: checkAgainst |= DATA_MATRIX_HINT; break;
case BarcodeFormat_EAN_13: checkAgainst = BARCODEFORMAT_EAN_13_HINT; break; case BarcodeFormat::EAN_8: checkAgainst |= EAN_8_HINT; break;
case BarcodeFormat_CODE_128: checkAgainst = BARCODEFORMAT_CODE_128_HINT; break; case BarcodeFormat::EAN_13: checkAgainst |= EAN_13_HINT; break;
case BarcodeFormat_CODE_39: checkAgainst = BARCODEFORMAT_CODE_39_HINT; break; case BarcodeFormat::ITF: checkAgainst |= ITF_HINT; break;
case BarcodeFormat_ITF: checkAgainst = BARCODEFORMAT_ITF_HINT; break; case BarcodeFormat::MAXICODE: checkAgainst |= MAXICODE_HINT; break;
default: throw IllegalArgumentException("Unrecognizd barcode format"); 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); return (hints & checkAgainst);
} }
@ -105,11 +119,18 @@ bool DecodeHints::getTryHarder() const {
} }
void DecodeHints::setResultPointCallback(Ref<ResultPointCallback> const& _callback) { void DecodeHints::setResultPointCallback(Ref<ResultPointCallback> const& _callback) {
callback = _callback; callback = _callback;
} }
Ref<ResultPointCallback> DecodeHints::getResultPointCallback() const { Ref<ResultPointCallback> 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;
}

View file

@ -1,3 +1,4 @@
// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*-
#ifndef __DECODEHINTS_H_ #ifndef __DECODEHINTS_H_
#define __DECODEHINTS_H_ #define __DECODEHINTS_H_
/* /*
@ -23,29 +24,35 @@
#include <zxing/ResultPointCallback.h> #include <zxing/ResultPointCallback.h>
namespace zxing { namespace zxing {
typedef unsigned int DecodeHintType;
class DecodeHints;
DecodeHints operator | (DecodeHints const&, DecodeHints const&);
}
typedef unsigned int DecodeHintType; class zxing::DecodeHints {
class DecodeHints {
private: private:
DecodeHintType hints; DecodeHintType hints;
Ref<ResultPointCallback> callback; Ref<ResultPointCallback> callback;
public: 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 CHARACTER_SET = 1 << 30;
static const DecodeHintType TRYHARDER_HINT = 1 << 31; static const DecodeHintType TRYHARDER_HINT = 1 << 31;
@ -64,8 +71,7 @@ class DecodeHints {
void setResultPointCallback(Ref<ResultPointCallback> const&); void setResultPointCallback(Ref<ResultPointCallback> const&);
Ref<ResultPointCallback> getResultPointCallback() const; Ref<ResultPointCallback> getResultPointCallback() const;
friend DecodeHints operator | (DecodeHints const&, DecodeHints const&);
}; };
}
#endif #endif

View file

@ -32,4 +32,10 @@ FormatException::FormatException(const char *msg) :
FormatException::~FormatException() throw() { FormatException::~FormatException() throw() {
} }
FormatException const&
FormatException::getFormatInstance() {
static FormatException instance;
return instance;
}
} }

View file

@ -29,6 +29,8 @@ public:
FormatException(); FormatException();
FormatException(const char *msg); FormatException(const char *msg);
~FormatException() throw(); ~FormatException() throw();
static FormatException const& getFormatInstance();
}; };
} }

View file

@ -22,7 +22,8 @@
#include <zxing/LuminanceSource.h> #include <zxing/LuminanceSource.h>
#include <zxing/common/IllegalArgumentException.h> #include <zxing/common/IllegalArgumentException.h>
namespace zxing { using zxing::Ref;
using zxing::LuminanceSource;
LuminanceSource::LuminanceSource() { LuminanceSource::LuminanceSource() {
} }
@ -51,7 +52,7 @@ Ref<LuminanceSource> LuminanceSource::rotateCounterClockwise() {
} }
LuminanceSource::operator std::string() { LuminanceSource::operator std::string() {
unsigned char* row = 0; ArrayRef<char> row;
std::ostringstream oss; std::ostringstream oss;
for (int y = 0; y < getHeight(); y++) { for (int y = 0; y < getHeight(); y++) {
row = getRow(y, row); row = getRow(y, row);
@ -71,10 +72,5 @@ LuminanceSource::operator std::string() {
} }
oss << '\n'; oss << '\n';
} }
delete [] row;
return oss.str(); return oss.str();
} }
}

View file

@ -21,11 +21,14 @@
*/ */
#include <zxing/common/Counted.h> #include <zxing/common/Counted.h>
#include <zxing/common/Array.h>
#include <string.h> #include <string.h>
namespace zxing { namespace zxing {
class LuminanceSource;
}
class LuminanceSource : public Counted { class zxing::LuminanceSource : public Counted {
public: public:
LuminanceSource(); LuminanceSource();
virtual ~LuminanceSource(); virtual ~LuminanceSource();
@ -34,8 +37,8 @@ public:
virtual int getHeight() const = 0; virtual int getHeight() const = 0;
// Callers take ownership of the returned memory and must call delete [] on it themselves. // 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 ArrayRef<char> getRow(int y, ArrayRef<char> row) = 0;
virtual unsigned char* getMatrix() = 0; virtual ArrayRef<char> getMatrix() = 0;
virtual bool isCropSupported() const; virtual bool isCropSupported() const;
virtual Ref<LuminanceSource> crop(int left, int top, int width, int height); virtual Ref<LuminanceSource> crop(int left, int top, int width, int height);
@ -44,9 +47,7 @@ public:
virtual Ref<LuminanceSource> rotateCounterClockwise(); virtual Ref<LuminanceSource> rotateCounterClockwise();
operator std::string (); // should be const but don't want to make sure a 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_ */ #endif /* LUMINANCESOURCE_H_ */

View file

@ -1,3 +1,4 @@
// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*-
/* /*
* MultiFormatBarcodeReader.cpp * MultiFormatBarcodeReader.cpp
* ZXing * ZXing
@ -27,80 +28,96 @@
#include <zxing/oned/MultiFormatOneDReader.h> #include <zxing/oned/MultiFormatOneDReader.h>
#include <zxing/ReaderException.h> #include <zxing/ReaderException.h>
namespace zxing { using zxing::Ref;
MultiFormatReader::MultiFormatReader() { using zxing::Result;
using zxing::MultiFormatReader;
} MultiFormatReader::MultiFormatReader() {}
Ref<Result> MultiFormatReader::decode(Ref<BinaryBitmap> image) { Ref<Result> MultiFormatReader::decode(Ref<BinaryBitmap> image) {
setHints(DecodeHints::DEFAULT_HINT);
return decodeInternal(image);
}
Ref<Result> MultiFormatReader::decode(Ref<BinaryBitmap> image, DecodeHints hints) {
setHints(hints);
return decodeInternal(image);
}
Ref<Result> MultiFormatReader::decodeWithState(Ref<BinaryBitmap> image) {
// Make sure to set up the default state so we don't crash
if (readers_.size() == 0) {
setHints(DecodeHints::DEFAULT_HINT); setHints(DecodeHints::DEFAULT_HINT);
return decodeInternal(image);
} }
return decodeInternal(image);
}
Ref<Result> MultiFormatReader::decode(Ref<BinaryBitmap> image, DecodeHints hints) { void MultiFormatReader::setHints(DecodeHints hints) {
setHints(hints); hints_ = hints;
return decodeInternal(image); 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<Reader>(new zxing::oned::MultiFormatOneDReader(hints)));
} }
if (hints.containsFormat(BarcodeFormat::QR_CODE)) {
Ref<Result> MultiFormatReader::decodeWithState(Ref<BinaryBitmap> image) { readers_.push_back(Ref<Reader>(new zxing::qrcode::QRCodeReader()));
// 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::DATA_MATRIX)) {
void MultiFormatReader::setHints(DecodeHints hints) { readers_.push_back(Ref<Reader>(new zxing::datamatrix::DataMatrixReader()));
hints_ = hints; }
readers_.clear(); if (hints.containsFormat(BarcodeFormat::AZTEC)) {
bool tryHarder = hints.getTryHarder(); readers_.push_back(Ref<Reader>(new zxing::aztec::AztecReader()));
}
bool addOneDReader = hints.containsFormat(BarcodeFormat_UPC_E) || /*
hints.containsFormat(BarcodeFormat_UPC_A) || if (formats.contains(BarcodeFormat.PDF_417)) {
hints.containsFormat(BarcodeFormat_EAN_8) || readers.add(new PDF417Reader());
hints.containsFormat(BarcodeFormat_EAN_13) || }
hints.containsFormat(BarcodeFormat_CODE_128) || if (formats.contains(BarcodeFormat.MAXICODE)) {
hints.containsFormat(BarcodeFormat_CODE_39) || readers.add(new MaxiCodeReader());
hints.containsFormat(BarcodeFormat_ITF); }
if (addOneDReader && !tryHarder) { */
if (addOneDReader && tryHarder) {
readers_.push_back(Ref<Reader>(new zxing::oned::MultiFormatOneDReader(hints)));
}
if (readers_.size() == 0) {
if (!tryHarder) {
readers_.push_back(Ref<Reader>(new zxing::oned::MultiFormatOneDReader(hints))); readers_.push_back(Ref<Reader>(new zxing::oned::MultiFormatOneDReader(hints)));
} }
if (hints.containsFormat(BarcodeFormat_QR_CODE)) { readers_.push_back(Ref<Reader>(new zxing::qrcode::QRCodeReader()));
readers_.push_back(Ref<Reader>(new zxing::qrcode::QRCodeReader())); readers_.push_back(Ref<Reader>(new zxing::datamatrix::DataMatrixReader()));
} readers_.push_back(Ref<Reader>(new zxing::aztec::AztecReader()));
if (hints.containsFormat(BarcodeFormat_DATA_MATRIX)) { // readers.add(new PDF417Reader());
readers_.push_back(Ref<Reader>(new zxing::datamatrix::DataMatrixReader())); // readers.add(new MaxiCodeReader());
}
if (hints.containsFormat(BarcodeFormat_AZTEC)) { if (tryHarder) {
readers_.push_back(Ref<Reader>(new zxing::aztec::AztecReader()));
}
//TODO: add PDF417 here once PDF417 reader is implemented
if (addOneDReader && tryHarder) {
readers_.push_back(Ref<Reader>(new zxing::oned::MultiFormatOneDReader(hints))); readers_.push_back(Ref<Reader>(new zxing::oned::MultiFormatOneDReader(hints)));
} }
if (readers_.size() == 0) {
if (!tryHarder) {
readers_.push_back(Ref<Reader>(new zxing::oned::MultiFormatOneDReader(hints)));
}
readers_.push_back(Ref<Reader>(new zxing::qrcode::QRCodeReader()));
if (tryHarder) {
readers_.push_back(Ref<Reader>(new zxing::oned::MultiFormatOneDReader(hints)));
}
}
}
Ref<Result> MultiFormatReader::decodeInternal(Ref<BinaryBitmap> image) {
for (unsigned int i = 0; i < readers_.size(); i++) {
try {
return readers_[i]->decode(image, hints_);
} catch (ReaderException const& re) {
// continue
}
}
throw ReaderException("No code detected");
}
MultiFormatReader::~MultiFormatReader() {
} }
} }
Ref<Result> MultiFormatReader::decodeInternal(Ref<BinaryBitmap> 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() {}

View file

@ -28,7 +28,6 @@
namespace zxing { namespace zxing {
class MultiFormatReader : public Reader { class MultiFormatReader : public Reader {
private: private:
Ref<Result> decodeInternal(Ref<BinaryBitmap> image); Ref<Result> decodeInternal(Ref<BinaryBitmap> image);

View file

@ -17,14 +17,18 @@
#include <zxing/NotFoundException.h> #include <zxing/NotFoundException.h>
namespace zxing { using zxing::NotFoundException;
NotFoundException::NotFoundException() {} NotFoundException::NotFoundException() {}
NotFoundException::NotFoundException(const char *msg) NotFoundException::NotFoundException(const char *msg)
: ReaderException(msg) {} : ReaderException(msg) {}
NotFoundException::~NotFoundException() throw() { NotFoundException::~NotFoundException() throw() {}
}
NotFoundException const&
NotFoundException::getNotFoundInstance() {
static NotFoundException instance;
return instance;
} }

View file

@ -28,6 +28,8 @@ namespace zxing {
NotFoundException(); NotFoundException();
NotFoundException(const char *msg); NotFoundException(const char *msg);
~NotFoundException() throw(); ~NotFoundException() throw();
static NotFoundException const& getNotFoundInstance();
}; };
} }

0
cpp/core/src/zxing/Reader.cpp Executable file → Normal file
View file

0
cpp/core/src/zxing/Reader.h Executable file → Normal file
View file

View file

@ -21,10 +21,15 @@
#include <zxing/Result.h> #include <zxing/Result.h>
namespace zxing { using zxing::Result;
using namespace std; using zxing::Ref;
using zxing::ArrayRef;
using zxing::String;
using zxing::ResultPoint;
Result::Result(Ref<String> text, ArrayRef<unsigned char> rawBytes, std::vector<Ref<ResultPoint> > resultPoints, Result::Result(Ref<String> text,
ArrayRef<char> rawBytes,
ArrayRef< Ref<ResultPoint> > resultPoints,
BarcodeFormat format) : BarcodeFormat format) :
text_(text), rawBytes_(rawBytes), resultPoints_(resultPoints), format_(format) { text_(text), rawBytes_(rawBytes), resultPoints_(resultPoints), format_(format) {
} }
@ -36,29 +41,18 @@ Ref<String> Result::getText() {
return text_; return text_;
} }
ArrayRef<unsigned char> Result::getRawBytes() { ArrayRef<char> Result::getRawBytes() {
return rawBytes_; return rawBytes_;
} }
const std::vector<Ref<ResultPoint> >& Result::getResultPoints() const { ArrayRef< Ref<ResultPoint> > const& Result::getResultPoints() const {
return resultPoints_; return resultPoints_;
} }
std::vector<Ref<ResultPoint> >& Result::getResultPoints() { ArrayRef< Ref<ResultPoint> >& Result::getResultPoints() {
return resultPoints_; return resultPoints_;
} }
BarcodeFormat Result::getBarcodeFormat() const { zxing::BarcodeFormat Result::getBarcodeFormat() const {
return format_; return format_;
} }
ostream& operator<<(ostream &out, Result& result) {
if (result.text_ != 0) {
out << result.text_->getText();
} else {
out << "[" << result.rawBytes_->size() << " bytes]";
}
return out;
}
}

View file

@ -21,7 +21,6 @@
*/ */
#include <string> #include <string>
#include <vector>
#include <zxing/common/Array.h> #include <zxing/common/Array.h>
#include <zxing/common/Counted.h> #include <zxing/common/Counted.h>
#include <zxing/common/Str.h> #include <zxing/common/Str.h>
@ -33,18 +32,20 @@ namespace zxing {
class Result : public Counted { class Result : public Counted {
private: private:
Ref<String> text_; Ref<String> text_;
ArrayRef<unsigned char> rawBytes_; ArrayRef<char> rawBytes_;
std::vector<Ref<ResultPoint> > resultPoints_; ArrayRef< Ref<ResultPoint> > resultPoints_;
BarcodeFormat format_; BarcodeFormat format_;
public: public:
Result(Ref<String> text, ArrayRef<unsigned char> rawBytes, std::vector<Ref<ResultPoint> > resultPoints, Result(Ref<String> text,
ArrayRef<char> rawBytes,
ArrayRef< Ref<ResultPoint> > resultPoints,
BarcodeFormat format); BarcodeFormat format);
~Result(); ~Result();
Ref<String> getText(); Ref<String> getText();
ArrayRef<unsigned char> getRawBytes(); ArrayRef<char> getRawBytes();
const std::vector<Ref<ResultPoint> >& getResultPoints() const; ArrayRef< Ref<ResultPoint> > const& getResultPoints() const;
std::vector<Ref<ResultPoint> >& getResultPoints(); ArrayRef< Ref<ResultPoint> >& getResultPoints();
BarcodeFormat getBarcodeFormat() const; BarcodeFormat getBarcodeFormat() const;
friend std::ostream& operator<<(std::ostream &out, Result& result); friend std::ostream& operator<<(std::ostream &out, Result& result);

View file

@ -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 <zxing/Result.h>
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;
}

0
cpp/core/src/zxing/ResultPoint.cpp Executable file → Normal file
View file

View file

@ -21,25 +21,27 @@
#include <zxing/aztec/AztecDetectorResult.h> #include <zxing/aztec/AztecDetectorResult.h>
namespace zxing { using zxing::aztec::AztecDetectorResult;
namespace aztec {
AztecDetectorResult::AztecDetectorResult(Ref<BitMatrix> bits, std::vector<Ref<ResultPoint> > points, bool compact, int nbDatablocks, int nbLayers) AztecDetectorResult::AztecDetectorResult(Ref<BitMatrix> bits,
: DetectorResult(bits, points), ArrayRef< Ref<ResultPoint> > points,
compact_(compact), bool compact,
nbDatablocks_(nbDatablocks), int nbDatablocks,
nbLayers_(nbLayers) { int nbLayers)
}; : DetectorResult(bits, points),
compact_(compact),
nbDatablocks_(nbDatablocks),
nbLayers_(nbLayers) {
};
bool AztecDetectorResult::isCompact() { bool AztecDetectorResult::isCompact() {
return compact_; return compact_;
} }
int AztecDetectorResult::getNBDatablocks() { int AztecDetectorResult::getNBDatablocks() {
return nbDatablocks_; return nbDatablocks_;
} }
int AztecDetectorResult::getNBLayers() { int AztecDetectorResult::getNBLayers() {
return nbLayers_; return nbLayers_;
} }
}
}

View file

@ -31,7 +31,11 @@ namespace zxing {
bool compact_; bool compact_;
int nbDatablocks_, nbLayers_; int nbDatablocks_, nbLayers_;
public: public:
AztecDetectorResult(Ref<BitMatrix> bits, std::vector<Ref<ResultPoint> > points, bool compact, int nbDatablocks, int nbLayers); AztecDetectorResult(Ref<BitMatrix> bits,
ArrayRef< Ref<ResultPoint> > points,
bool compact,
int nbDatablocks,
int nbLayers);
bool isCompact(); bool isCompact();
int getNBDatablocks(); int getNBDatablocks();
int getNBLayers(); int getNBLayers();

View file

@ -23,42 +23,41 @@
#include <zxing/aztec/detector/Detector.h> #include <zxing/aztec/detector/Detector.h>
#include <iostream> #include <iostream>
namespace zxing { using zxing::Ref;
namespace aztec { using zxing::ArrayRef;
using zxing::Result;
using zxing::aztec::AztecReader;
AztecReader::AztecReader() : decoder_() { AztecReader::AztecReader() : decoder_() {
// nothing // nothing
}; };
Ref<Result> AztecReader::decode(Ref<zxing::BinaryBitmap> image) { Ref<Result> AztecReader::decode(Ref<zxing::BinaryBitmap> image) {
Detector detector(image->getBlackMatrix()); Detector detector(image->getBlackMatrix());
Ref<AztecDetectorResult> detectorResult(detector.detect()); Ref<AztecDetectorResult> detectorResult(detector.detect());
std::vector<Ref<ResultPoint> > points(detectorResult->getPoints()); ArrayRef< Ref<ResultPoint> > points(detectorResult->getPoints());
Ref<DecoderResult> decoderResult(decoder_.decode(detectorResult)); Ref<DecoderResult> decoderResult(decoder_.decode(detectorResult));
Ref<Result> result(new Result(decoderResult->getText(), Ref<Result> result(new Result(decoderResult->getText(),
decoderResult->getRawBytes(), decoderResult->getRawBytes(),
points, points,
BarcodeFormat_AZTEC)); BarcodeFormat::AZTEC));
return result; return result;
} }
Ref<Result> AztecReader::decode(Ref<BinaryBitmap> image, DecodeHints) { Ref<Result> AztecReader::decode(Ref<BinaryBitmap> image, DecodeHints) {
//cout << "decoding with hints not supported for aztec" << "\n" << flush; //cout << "decoding with hints not supported for aztec" << "\n" << flush;
return this->decode(image); return this->decode(image);
} }
AztecReader::~AztecReader() { AztecReader::~AztecReader() {
// nothing // nothing
} }
Decoder& AztecReader::getDecoder() { zxing::aztec::Decoder& AztecReader::getDecoder() {
return decoder_; return decoder_;
}
}
} }

View file

@ -40,7 +40,7 @@ using zxing::Ref;
using std::string; using std::string;
namespace { namespace {
void add(string& result, unsigned char character) { void add(string& result, char character) {
#ifndef NO_ICONV #ifndef NO_ICONV
char s[] = { character & 0xff }; char s[] = { character & 0xff };
char* ss = s; char* ss = s;
@ -163,9 +163,9 @@ Ref<DecoderResult> Decoder::decode(Ref<zxing::aztec::AztecDetectorResult> detect
Ref<String> result = getEncodedData(aCorrectedBits); Ref<String> result = getEncodedData(aCorrectedBits);
// std::printf("constructing array\n"); // std::printf("constructing array\n");
ArrayRef<unsigned char> arrayOut(aCorrectedBits->getSize()); ArrayRef<char> arrayOut(aCorrectedBits->getSize());
for (int i = 0; i < aCorrectedBits->count(); i++) { 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"); // std::printf("returning\n");
@ -376,7 +376,7 @@ Ref<BitArray> Decoder::correctBits(Ref<zxing::BitArray> rawbits) {
} }
flag = (unsigned int)flag >> 1; flag = ((unsigned int)flag) >> 1;
} }
} }

View file

@ -29,10 +29,12 @@
#include <zxing/common/detector/math_utils.h> #include <zxing/common/detector/math_utils.h>
#include <zxing/NotFoundException.h> #include <zxing/NotFoundException.h>
using std::vector;
using zxing::aztec::Detector; using zxing::aztec::Detector;
using zxing::aztec::Point; using zxing::aztec::Point;
using zxing::aztec::AztecDetectorResult; using zxing::aztec::AztecDetectorResult;
using zxing::Ref; using zxing::Ref;
using zxing::ArrayRef;
using zxing::ResultPoint; using zxing::ResultPoint;
using zxing::BitArray; using zxing::BitArray;
using zxing::BitMatrix; using zxing::BitMatrix;
@ -52,10 +54,15 @@ Ref<AztecDetectorResult> Detector::detect() {
std::vector<Ref<Point> > bullEyeCornerPoints = getBullEyeCornerPoints(pCenter); std::vector<Ref<Point> > bullEyeCornerPoints = getBullEyeCornerPoints(pCenter);
extractParameters(bullEyeCornerPoints); extractParameters(bullEyeCornerPoints);
ArrayRef< Ref<ResultPoint> > corners = getMatrixCornerPoints(bullEyeCornerPoints);
std::vector<Ref<ResultPoint> > corners = getMatrixCornerPoints(bullEyeCornerPoints); Ref<BitMatrix> bits =
sampleGrid(image_,
Ref<BitMatrix> bits = sampleGrid(image_, corners[shift_%4], corners[(shift_+3)%4], corners[(shift_+2)%4], corners[(shift_+1)%4]); 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_); // 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<Ref<Point> > bullEyeCornerPoints) {
getParameters(parameterData); getParameters(parameterData);
} }
std::vector<Ref<ResultPoint> > Detector::getMatrixCornerPoints(std::vector<Ref<Point> > bullEyeCornerPoints) { ArrayRef< Ref<ResultPoint> >
Detector::getMatrixCornerPoints(std::vector<Ref<Point> > bullEyeCornerPoints) {
float ratio = (2 * nbLayers_ + (nbLayers_ > 4 ? 1 : 0) + (nbLayers_ - 4) / 8) / (2.0f * nbCenterLayers_); float ratio = (2 * nbLayers_ + (nbLayers_ > 4 ? 1 : 0) + (nbLayers_ - 4) / 8) / (2.0f * nbCenterLayers_);
int dx = bullEyeCornerPoints[0]->x - bullEyeCornerPoints[2]->x; int dx = bullEyeCornerPoints[0]->x - bullEyeCornerPoints[2]->x;
@ -157,14 +165,13 @@ std::vector<Ref<ResultPoint> > Detector::getMatrixCornerPoints(std::vector<Ref<P
!isValid(targetdx, targetdy)) { !isValid(targetdx, targetdy)) {
throw ReaderException("matrix extends over image bounds"); throw ReaderException("matrix extends over image bounds");
} }
std::vector<Ref<ResultPoint> > returnValue; Array< Ref<ResultPoint> >* array = new Array< Ref<ResultPoint> >();
vector< Ref<ResultPoint> >& returnValue (array->values());
returnValue.push_back(Ref<ResultPoint>(new ResultPoint(targetax, targetay))); returnValue.push_back(Ref<ResultPoint>(new ResultPoint(targetax, targetay)));
returnValue.push_back(Ref<ResultPoint>(new ResultPoint(targetbx, targetby))); returnValue.push_back(Ref<ResultPoint>(new ResultPoint(targetbx, targetby)));
returnValue.push_back(Ref<ResultPoint>(new ResultPoint(targetcx, targetcy))); returnValue.push_back(Ref<ResultPoint>(new ResultPoint(targetcx, targetcy)));
returnValue.push_back(Ref<ResultPoint>(new ResultPoint(targetdx, targetdy))); returnValue.push_back(Ref<ResultPoint>(new ResultPoint(targetdx, targetdy)));
return ArrayRef< Ref<ResultPoint> >(array);
return returnValue;
} }
void Detector::correctParameterData(Ref<zxing::BitArray> parameterData, bool compact) { void Detector::correctParameterData(Ref<zxing::BitArray> parameterData, bool compact) {

View file

@ -29,57 +29,58 @@
#include <zxing/aztec/AztecDetectorResult.h> #include <zxing/aztec/AztecDetectorResult.h>
namespace zxing { namespace zxing {
namespace aztec { namespace aztec {
class Point;
class Point : public Counted { class Detector;
public: }
int x;
int y;
Ref<ResultPoint> toResultPoint() {
return Ref<ResultPoint>(new ResultPoint(x, y));
}
Point(int ax, int ay):x(ax),y(ay) {};
};
class Detector : public Counted {
private:
Ref<BitMatrix> image_;
bool compact_;
int nbLayers_;
int nbDataBlocks_;
int nbCenterLayers_;
int shift_;
void extractParameters(std::vector<Ref<Point> > bullEyeCornerPoints);
std::vector<Ref<ResultPoint> > getMatrixCornerPoints(std::vector<Ref<Point> > bullEyeCornerPoints);
static void correctParameterData(Ref<BitArray> parameterData, bool compact);
std::vector<Ref<Point> > getBullEyeCornerPoints(Ref<Point> pCenter);
Ref<Point> getMatrixCenter();
Ref<BitMatrix> sampleGrid(Ref<BitMatrix> image,
Ref<ResultPoint> topLeft,
Ref<ResultPoint> bottomLeft,
Ref<ResultPoint> bottomRight,
Ref<ResultPoint> topRight);
void getParameters(Ref<BitArray> parameterData);
Ref<BitArray> sampleLine(Ref<Point> p1, Ref<Point> p2, int size);
bool isWhiteOrBlackRectangle(Ref<Point> p1,
Ref<Point> p2,
Ref<Point> p3,
Ref<Point> p4);
int getColor(Ref<Point> p1, Ref<Point> p2);
Ref<Point> getFirstDifferent(Ref<Point> init, bool color, int dx, int dy);
bool isValid(int x, int y);
static float distance(Ref<Point> a, Ref<Point> b);
public:
Detector(Ref<BitMatrix> image);
Ref<AztecDetectorResult> detect();
};
}
} }
class zxing::aztec::Point : public Counted {
public:
int x;
int y;
Ref<ResultPoint> toResultPoint() {
return Ref<ResultPoint>(new ResultPoint(x, y));
}
Point(int ax, int ay):x(ax),y(ay) {};
};
class zxing::aztec::Detector : public Counted {
private:
Ref<BitMatrix> image_;
bool compact_;
int nbLayers_;
int nbDataBlocks_;
int nbCenterLayers_;
int shift_;
void extractParameters(std::vector<Ref<Point> > bullEyeCornerPoints);
ArrayRef< Ref<ResultPoint> > getMatrixCornerPoints(std::vector<Ref<Point> > bullEyeCornerPoints);
static void correctParameterData(Ref<BitArray> parameterData, bool compact);
std::vector<Ref<Point> > getBullEyeCornerPoints(Ref<Point> pCenter);
Ref<Point> getMatrixCenter();
Ref<BitMatrix> sampleGrid(Ref<BitMatrix> image,
Ref<ResultPoint> topLeft,
Ref<ResultPoint> bottomLeft,
Ref<ResultPoint> bottomRight,
Ref<ResultPoint> topRight);
void getParameters(Ref<BitArray> parameterData);
Ref<BitArray> sampleLine(Ref<Point> p1, Ref<Point> p2, int size);
bool isWhiteOrBlackRectangle(Ref<Point> p1,
Ref<Point> p2,
Ref<Point> p3,
Ref<Point> p4);
int getColor(Ref<Point> p1, Ref<Point> p2);
Ref<Point> getFirstDifferent(Ref<Point> init, bool color, int dx, int dy);
bool isValid(int x, int y);
static float distance(Ref<Point> a, Ref<Point> b);
public:
Detector(Ref<BitMatrix> image);
Ref<AztecDetectorResult> detect();
};

View file

@ -37,13 +37,14 @@ template<typename T> class Array : public Counted {
protected: protected:
public: public:
std::vector<T> values_; std::vector<T> values_;
Array(size_t n) : Array() {}
Array(int n) :
Counted(), values_(n, T()) { Counted(), values_(n, T()) {
} }
Array(T *ts, size_t n) : Array(T const* ts, int n) :
Counted(), values_(ts, ts+n) { Counted(), values_(ts, ts+n) {
} }
Array(T v, size_t n) : Array(T v, int n) :
Counted(), values_(n, v) { Counted(), values_(n, v) {
} }
Array(std::vector<T> &v) : Array(std::vector<T> &v) :
@ -77,16 +78,19 @@ public:
#endif #endif
return *this; return *this;
} }
T operator[](size_t i) const { T operator[](int i) const {
return values_[i]; return values_[i];
} }
T& operator[](size_t i) { T& operator[](int i) {
return values_[i]; return values_[i];
} }
size_t size() const { int size() const {
return values_.size(); return values_.size();
} }
std::vector<T> values() const { bool empty() const {
return values_.size() == 0;
}
std::vector<T> const& values() const {
return values_; return values_;
} }
std::vector<T>& values() { std::vector<T>& values() {
@ -104,14 +108,14 @@ public:
cout << "instantiating empty ArrayRef " << this << "\n"; cout << "instantiating empty ArrayRef " << this << "\n";
#endif #endif
} }
ArrayRef(size_t n) : explicit ArrayRef(int n) :
array_(0) { array_(0) {
#ifdef DEBUG_COUNTING #ifdef DEBUG_COUNTING
cout << "instantiating ArrayRef " << this << "with size " << n << "\n"; cout << "instantiating ArrayRef " << this << "with size " << n << "\n";
#endif #endif
reset(new Array<T> (n)); reset(new Array<T> (n));
} }
ArrayRef(T *ts, size_t n) : ArrayRef(T *ts, int n) :
array_(0) { array_(0) {
#ifdef DEBUG_COUNTING #ifdef DEBUG_COUNTING
cout << "instantiating ArrayRef " << this << "with " << n << " elements at " << (void *)ts << "\n"; cout << "instantiating ArrayRef " << this << "with " << n << " elements at " << (void *)ts << "\n";
@ -160,13 +164,13 @@ public:
array_ = 0; array_ = 0;
} }
T operator[](size_t i) const { T operator[](int i) const {
return (*array_)[i]; return (*array_)[i];
} }
T& operator[](size_t i) { T& operator[](int i) {
return (*array_)[i]; return (*array_)[i];
} }
size_t size() const { int size() const {
return array_->size(); return array_->size();
} }
@ -201,6 +205,12 @@ public:
Array<T>* operator->() { Array<T>* operator->() {
return array_; return array_;
} }
operator bool () const {
return array_ != 0;
}
bool operator ! () const {
return array_ == 0;
}
}; };
} // namespace zxing } // namespace zxing

View file

@ -17,28 +17,26 @@
#include <zxing/common/BitArray.h> #include <zxing/common/BitArray.h>
using namespace std; using std::vector;
using zxing::BitArray;
namespace zxing { int BitArray::wordsForBits(int bits) {
size_t BitArray::wordsForBits(size_t bits) {
int arraySize = (bits + bitsPerWord_ - 1) >> logBits_; int arraySize = (bits + bitsPerWord_ - 1) >> logBits_;
return arraySize; return arraySize;
} }
BitArray::BitArray(size_t size) : BitArray::BitArray(int size) :
size_(size), bits_(wordsForBits(size), (const unsigned int)0) { size_(size), bits_(wordsForBits(size), 0) {
} }
BitArray::~BitArray() { BitArray::~BitArray() {
} }
size_t BitArray::getSize() { int BitArray::getSize() const {
return size_; return size_;
} }
void BitArray::setBulk(size_t i, unsigned int newBits) { void BitArray::setBulk(int i, int newBits) {
bits_[i >> logBits_] = newBits; bits_[i >> logBits_] = newBits;
} }
@ -69,13 +67,13 @@ void BitArray::setRange(int start, int end) {
} }
void BitArray::clear() { void BitArray::clear() {
size_t max = bits_.size(); int max = bits_.size();
for (size_t i = 0; i < max; i++) { for (int i = 0; i < max; i++) {
bits_[i] = 0; 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) { if (end < start) {
throw IllegalArgumentException("end must be after 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 // treat the 'end' as inclusive, rather than exclusive
end--; end--;
size_t firstWord = start >> logBits_; int firstWord = start >> logBits_;
size_t lastWord = end >> logBits_; int lastWord = end >> logBits_;
for (size_t i = firstWord; i <= lastWord; i++) { for (int i = firstWord; i <= lastWord; i++) {
size_t firstBit = i > firstWord ? 0 : start & bitsMask_; int firstBit = i > firstWord ? 0 : start & bitsMask_;
size_t lastBit = i < lastWord ? bitsPerWord_ - 1: end & bitsMask_; int lastBit = i < lastWord ? bitsPerWord_ - 1: end & bitsMask_;
unsigned int mask; int mask;
if (firstBit == 0 && lastBit == bitsPerWord_ - 1) { if (firstBit == 0 && lastBit == bitsPerWord_ - 1) {
mask = numeric_limits<unsigned int>::max(); mask = -1;
} else { } else {
mask = 0; mask = 0;
for (size_t j = firstBit; j <= lastBit; j++) { for (int j = firstBit; j <= lastBit; j++) {
mask |= 1 << j; mask |= 1 << j;
} }
} }
@ -111,17 +109,75 @@ bool BitArray::isRange(size_t start, size_t end, bool value) {
return true; return true;
} }
vector<unsigned int>& BitArray::getBitArray() { vector<int>& BitArray::getBitArray() {
return bits_; return bits_;
} }
void BitArray::reverse() { void BitArray::reverse() {
std::vector<unsigned int> newBits(bits_.size(),(const unsigned int) 0); // std::cerr << "reverse" << std::endl;
for (size_t i = 0; i < size_; i++) { std::vector<int> newBits(bits_.size(), 0);
for (int i = 0; i < size_; i++) {
if (get(size_ - i - 1)) { if (get(size_ - i - 1)) {
newBits[i >> logBits_] |= 1<< (i & bitsMask_); newBits[i >> logBits_] |= 1<< (i & bitsMask_);
} }
} }
bits_ = newBits; bits_ = newBits;
} }
BitArray::Reverse::Reverse(Ref<BitArray> 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;
} }

View file

@ -22,8 +22,12 @@
#include <zxing/common/IllegalArgumentException.h> #include <zxing/common/IllegalArgumentException.h>
#include <vector> #include <vector>
#include <limits> #include <limits>
#include <iostream>
namespace zxing { namespace zxing {
class BitArray;
std::ostream& operator << (std::ostream&, BitArray const&);
}
#define ZX_LOG_DIGITS(digits) \ #define ZX_LOG_DIGITS(digits) \
((digits == 8) ? 3 : \ ((digits == 8) ? 3 : \
@ -33,38 +37,49 @@ namespace zxing {
((digits == 128) ? 7 : \ ((digits == 128) ? 7 : \
(-1)))))) (-1))))))
class BitArray : public Counted { class zxing::BitArray : public Counted {
private: private:
size_t size_; int size_;
std::vector<unsigned int> bits_; std::vector<int> bits_;
static const unsigned int bitsPerWord_ = static const int bitsPerWord_ =
std::numeric_limits<unsigned int>::digits; std::numeric_limits<unsigned int>::digits;
static const unsigned int logBits_ = ZX_LOG_DIGITS(bitsPerWord_); static const int logBits_ = ZX_LOG_DIGITS(bitsPerWord_);
static const unsigned int bitsMask_ = (1 << logBits_) - 1; static const int bitsMask_ = (1 << logBits_) - 1;
static size_t wordsForBits(size_t bits); static int wordsForBits(int bits);
explicit BitArray(); explicit BitArray();
public: public:
BitArray(size_t size); BitArray(int size);
~BitArray(); ~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; return (bits_[i >> logBits_] & (1 << (i & bitsMask_))) != 0;
} }
void set(size_t i) { void set(int i) {
bits_[i >> logBits_] |= 1 << (i & bitsMask_); 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 setRange(int start, int end);
void clear(); void clear();
bool isRange(size_t start, size_t end, bool value); bool isRange(int start, int end, bool value);
std::vector<unsigned int>& getBitArray(); std::vector<int>& getBitArray();
void reverse(); void reverse();
class Reverse;
}; };
} class zxing::BitArray::Reverse {
private:
Ref<BitArray> array;
public:
Reverse(Ref<BitArray> array);
~Reverse();
};
#endif // __BIT_ARRAY_H__ #endif // __BIT_ARRAY_H__

View file

@ -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 <zxing/common/BitArray.h>
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;
}

View file

@ -27,63 +27,62 @@ using std::ostringstream;
using zxing::BitMatrix; using zxing::BitMatrix;
using zxing::BitArray; using zxing::BitArray;
using zxing::ArrayRef;
using zxing::Ref; using zxing::Ref;
namespace { namespace {
size_t wordsForSize(size_t width, int wordsForSize(int width,
size_t height, int height,
unsigned int bitsPerWord, int bitsPerWord,
unsigned int logBits) { int logBits) {
size_t bits = width * height; int bits = width * height;
int arraySize = (bits + bitsPerWord - 1) >> logBits; int arraySize = (bits + bitsPerWord - 1) >> logBits;
return arraySize; return arraySize;
} }
} }
BitMatrix::BitMatrix(size_t dimension) : BitMatrix::BitMatrix(int dimension) :
width_(dimension), height_(dimension), words_(0), bits_(NULL) { width_(dimension), height_(dimension), words_(0) {
words_ = wordsForSize(width_, height_, bitsPerWord, logBits); words_ = wordsForSize(width_, height_, bitsPerWord, logBits);
bits_ = new unsigned int[words_]; bits_ = ArrayRef<int>(words_);
clear(); clear();
} }
BitMatrix::BitMatrix(size_t width, size_t height) : BitMatrix::BitMatrix(int width, int height) :
width_(width), height_(height), words_(0), bits_(NULL) { width_(width), height_(height), words_(0) {
words_ = wordsForSize(width_, height_, bitsPerWord, logBits); words_ = wordsForSize(width_, height_, bitsPerWord, logBits);
bits_ = new unsigned int[words_]; bits_ = ArrayRef<int>(words_);
clear(); clear();
} }
BitMatrix::~BitMatrix() { BitMatrix::~BitMatrix() {}
delete[] bits_;
}
void BitMatrix::flip(size_t x, size_t y) { void BitMatrix::flip(int x, int y) {
size_t offset = x + width_ * y; int offset = x + width_ * y;
bits_[offset >> logBits] ^= 1 << (offset & bitsMask); bits_[offset >> logBits] ^= 1 << (offset & bitsMask);
} }
void BitMatrix::clear() { 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) { if ((long)top < 0 || (long)left < 0) {
throw IllegalArgumentException("topI and leftJ must be nonnegative"); throw IllegalArgumentException("topI and leftJ must be nonnegative");
} }
if (height < 1 || width < 1) { if (height < 1 || width < 1) {
throw IllegalArgumentException("height and width must be at least 1"); throw IllegalArgumentException("height and width must be at least 1");
} }
size_t right = left + width; int right = left + width;
size_t bottom = top + height; int bottom = top + height;
if (right > width_ || bottom > height_) { if (right > width_ || bottom > height_) {
throw IllegalArgumentException("top + height and left + width must be <= matrix dimension"); 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; int yOffset = width_ * y;
for (size_t x = left; x < right; x++) { for (int x = left; x < right; x++) {
size_t offset = x + yOffset; int offset = x + yOffset;
bits_[offset >> logBits] |= 1 << (offset & bitsMask); bits_[offset >> logBits] |= 1 << (offset & bitsMask);
} }
} }
@ -95,26 +94,26 @@ Ref<BitArray> BitMatrix::getRow(int y, Ref<BitArray> row) {
} else { } else {
row->clear(); row->clear();
} }
size_t start = y * width_; int start = y * width_;
size_t end = start + width_ - 1; // end is inclusive int end = start + width_ - 1; // end is inclusive
size_t firstWord = start >> logBits; int firstWord = start >> logBits;
size_t lastWord = end >> logBits; int lastWord = end >> logBits;
size_t bitOffset = start & bitsMask; int bitOffset = start & bitsMask;
for (size_t i = firstWord; i <= lastWord; i++) { for (int i = firstWord; i <= lastWord; i++) {
size_t firstBit = i > firstWord ? 0 : start & bitsMask; int firstBit = i > firstWord ? 0 : start & bitsMask;
size_t lastBit = i < lastWord ? bitsPerWord - 1 : end & bitsMask; int lastBit = i < lastWord ? bitsPerWord - 1 : end & bitsMask;
unsigned int mask; int mask;
if (firstBit == 0 && lastBit == logBits) { if (firstBit == 0 && lastBit == logBits) {
mask = std::numeric_limits<unsigned int>::max(); mask = std::numeric_limits<int>::max();
} else { } else {
mask = 0; mask = 0;
for (size_t j = firstBit; j <= lastBit; j++) { for (int j = firstBit; j <= lastBit; j++) {
mask |= 1 << j; mask |= 1 << j;
} }
} }
row->setBulk((i - firstWord) << logBits, (bits_[i] & mask) >> bitOffset); row->setBulk((i - firstWord) << logBits, (bits_[i] & mask) >> bitOffset);
if (firstBit == 0 && bitOffset != 0) { 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); prevBulk |= (bits_[i] & mask) << (bitsPerWord - bitOffset);
row->setBulk((i - firstWord - 1) << logBits, prevBulk); row->setBulk((i - firstWord - 1) << logBits, prevBulk);
} }
@ -122,26 +121,26 @@ Ref<BitArray> BitMatrix::getRow(int y, Ref<BitArray> row) {
return row; return row;
} }
size_t BitMatrix::getWidth() const { int BitMatrix::getWidth() const {
return width_; return width_;
} }
size_t BitMatrix::getHeight() const { int BitMatrix::getHeight() const {
return height_; return height_;
} }
size_t BitMatrix::getDimension() const { int BitMatrix::getDimension() const {
return width_; return width_;
} }
unsigned int* BitMatrix::getBits() const { ArrayRef<int> BitMatrix::getBits() const {
return bits_; return bits_;
} }
namespace zxing { namespace zxing {
ostream& operator<<(ostream &out, const BitMatrix &bm) { ostream& operator<<(ostream &out, const BitMatrix &bm) {
for (size_t y = 0; y < bm.height_; y++) { for (int y = 0; y < bm.height_; y++) {
for (size_t x = 0; x < bm.width_; x++) { for (int x = 0; x < bm.width_; x++) {
out << (bm.get(x, y) ? "X " : " "); out << (bm.get(x, y) ? "X " : " ");
} }
out << "\n"; out << "\n";

View file

@ -23,16 +23,19 @@
#include <zxing/common/Counted.h> #include <zxing/common/Counted.h>
#include <zxing/common/BitArray.h> #include <zxing/common/BitArray.h>
#include <zxing/common/Array.h>
#include <limits> #include <limits>
namespace zxing { namespace zxing {
class BitMatrix;
}
class BitMatrix : public Counted { class zxing::BitMatrix : public Counted {
private: private:
size_t width_; int width_;
size_t height_; int height_;
size_t words_; int words_;
unsigned int* bits_; ArrayRef<int> bits_;
#define ZX_LOG_DIGITS(digits) \ #define ZX_LOG_DIGITS(digits) \
((digits == 8) ? 3 : \ ((digits == 8) ? 3 : \
@ -42,37 +45,37 @@ private:
((digits == 128) ? 7 : \ ((digits == 128) ? 7 : \
(-1)))))) (-1))))))
static const unsigned int bitsPerWord = static const int bitsPerWord =
std::numeric_limits<unsigned int>::digits; std::numeric_limits<unsigned int>::digits;
static const unsigned int logBits = ZX_LOG_DIGITS(bitsPerWord); static const int logBits = ZX_LOG_DIGITS(bitsPerWord);
static const unsigned int bitsMask = (1 << logBits) - 1; static const int bitsMask = (1 << logBits) - 1;
public: public:
BitMatrix(size_t dimension); BitMatrix(int dimension);
BitMatrix(size_t width, size_t height); BitMatrix(int width, int height);
~BitMatrix(); ~BitMatrix();
bool get(size_t x, size_t y) const { bool get(int x, int y) const {
size_t offset = x + width_ * y; int offset = x + width_ * y;
return ((bits_[offset >> logBits] >> (offset & bitsMask)) & 0x01) != 0; return ((bits_[offset >> logBits] >> (offset & bitsMask)) & 0x01) != 0;
} }
void set(size_t x, size_t y) { void set(int x, int y) {
size_t offset = x + width_ * y; int offset = x + width_ * y;
bits_[offset >> logBits] |= 1 << (offset & bitsMask); bits_[offset >> logBits] |= 1 << (offset & bitsMask);
} }
void flip(size_t x, size_t y); void flip(int x, int y);
void clear(); 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<BitArray> getRow(int y, Ref<BitArray> row); Ref<BitArray> getRow(int y, Ref<BitArray> row);
size_t getDimension() const; int getDimension() const;
size_t getWidth() const; int getWidth() const;
size_t getHeight() const; int getHeight() const;
unsigned int* getBits() const; ArrayRef<int> getBits() const;
friend std::ostream& operator<<(std::ostream &out, const BitMatrix &bm); friend std::ostream& operator<<(std::ostream &out, const BitMatrix &bm);
const char *description(); const char *description();
@ -82,6 +85,4 @@ private:
BitMatrix& operator =(const BitMatrix&); BitMatrix& operator =(const BitMatrix&);
}; };
}
#endif // __BIT_MATRIX_H__ #endif // __BIT_MATRIX_H__

View file

@ -33,7 +33,7 @@ namespace zxing {
* @author christian.brunschen@gmail.com (Christian Brunschen) * @author christian.brunschen@gmail.com (Christian Brunschen)
*/ */
class BitSource : public Counted { class BitSource : public Counted {
typedef unsigned char byte; typedef char byte;
private: private:
ArrayRef<byte> bytes_; ArrayRef<byte> bytes_;
int byteOffset_; int byteOffset_;

View file

@ -97,6 +97,7 @@ public:
reset(o); reset(o);
} }
/*
explicit Ref(const T &o) : explicit Ref(const T &o) :
object_(0) { object_(0) {
#ifdef DEBUG_COUNTING #ifdef DEBUG_COUNTING
@ -104,6 +105,7 @@ public:
#endif #endif
reset(const_cast<T *>(&o)); reset(const_cast<T *>(&o));
} }
*/
Ref(const Ref &other) : Ref(const Ref &other) :
object_(0) { object_(0) {

View file

@ -24,20 +24,20 @@
using namespace std; using namespace std;
using namespace zxing; using namespace zxing;
DecoderResult::DecoderResult(ArrayRef<unsigned char> rawBytes, DecoderResult::DecoderResult(ArrayRef<char> rawBytes,
Ref<String> text, Ref<String> text,
ArrayRef< ArrayRef<unsigned char> >& byteSegments, ArrayRef< ArrayRef<char> >& byteSegments,
string const& ecLevel) : string const& ecLevel) :
rawBytes_(rawBytes), rawBytes_(rawBytes),
text_(text), text_(text),
byteSegments_(byteSegments), byteSegments_(byteSegments),
ecLevel_(ecLevel) {} ecLevel_(ecLevel) {}
DecoderResult::DecoderResult(ArrayRef<unsigned char> rawBytes, DecoderResult::DecoderResult(ArrayRef<char> rawBytes,
Ref<String> text) Ref<String> text)
: rawBytes_(rawBytes), text_(text) {} : rawBytes_(rawBytes), text_(text) {}
ArrayRef<unsigned char> DecoderResult::getRawBytes() { ArrayRef<char> DecoderResult::getRawBytes() {
return rawBytes_; return rawBytes_;
} }

View file

@ -29,20 +29,20 @@ namespace zxing {
class DecoderResult : public Counted { class DecoderResult : public Counted {
private: private:
ArrayRef<unsigned char> rawBytes_; ArrayRef<char> rawBytes_;
Ref<String> text_; Ref<String> text_;
ArrayRef< ArrayRef<unsigned char> > byteSegments_; ArrayRef< ArrayRef<char> > byteSegments_;
std::string ecLevel_; std::string ecLevel_;
public: public:
DecoderResult(ArrayRef<unsigned char> rawBytes, DecoderResult(ArrayRef<char> rawBytes,
Ref<String> text, Ref<String> text,
ArrayRef< ArrayRef<unsigned char> >& byteSegments, ArrayRef< ArrayRef<char> >& byteSegments,
std::string const& ecLevel); std::string const& ecLevel);
DecoderResult(ArrayRef<unsigned char> rawBytes, Ref<String> text); DecoderResult(ArrayRef<char> rawBytes, Ref<String> text);
ArrayRef<unsigned char> getRawBytes(); ArrayRef<char> getRawBytes();
Ref<String> getText(); Ref<String> getText();
}; };

View file

@ -23,15 +23,16 @@
namespace zxing { namespace zxing {
DetectorResult::DetectorResult(Ref<BitMatrix> bits, std::vector<Ref<ResultPoint> > points) : DetectorResult::DetectorResult(Ref<BitMatrix> bits,
bits_(bits), points_(points) { ArrayRef< Ref<ResultPoint> > points)
: bits_(bits), points_(points) {
} }
Ref<BitMatrix> DetectorResult::getBits() { Ref<BitMatrix> DetectorResult::getBits() {
return bits_; return bits_;
} }
std::vector<Ref<ResultPoint> > DetectorResult::getPoints() { ArrayRef< Ref<ResultPoint> > DetectorResult::getPoints() {
return points_; return points_;
} }

View file

@ -20,24 +20,24 @@
* limitations under the License. * limitations under the License.
*/ */
#include <vector>
#include <zxing/common/Counted.h> #include <zxing/common/Counted.h>
#include <zxing/common/Array.h> #include <zxing/common/Array.h>
#include <zxing/common/BitMatrix.h> #include <zxing/common/BitMatrix.h>
#include <zxing/ResultPoint.h> #include <zxing/ResultPoint.h>
namespace zxing { namespace zxing {
class DetectorResult;
class DetectorResult : public Counted {
private:
Ref<BitMatrix> bits_;
std::vector<Ref<ResultPoint> > points_;
public:
DetectorResult(Ref<BitMatrix> bits, std::vector<Ref<ResultPoint> > points);
Ref<BitMatrix> getBits();
std::vector<Ref<ResultPoint> > getPoints();
};
} }
class zxing::DetectorResult : public Counted {
private:
Ref<BitMatrix> bits_;
ArrayRef< Ref<ResultPoint> > points_;
public:
DetectorResult(Ref<BitMatrix> bits, ArrayRef< Ref<ResultPoint> > points);
Ref<BitMatrix> getBits();
ArrayRef< Ref<ResultPoint> > getPoints();
};
#endif // __DETECTOR_RESULT_H__ #endif // __DETECTOR_RESULT_H__

View file

@ -19,35 +19,39 @@
*/ */
#include <zxing/common/GlobalHistogramBinarizer.h> #include <zxing/common/GlobalHistogramBinarizer.h>
#include <zxing/common/IllegalArgumentException.h> #include <zxing/NotFoundException.h>
#include <zxing/common/Array.h> #include <zxing/common/Array.h>
namespace zxing { using zxing::GlobalHistogramBinarizer;
using namespace std; using zxing::Binarizer;
using zxing::ArrayRef;
const int LUMINANCE_BITS = 5; using zxing::Ref;
const int LUMINANCE_SHIFT = 8 - LUMINANCE_BITS; using zxing::BitArray;
const int LUMINANCE_BUCKETS = 1 << LUMINANCE_BITS; using zxing::BitMatrix;
GlobalHistogramBinarizer::GlobalHistogramBinarizer(Ref<LuminanceSource> source) :
Binarizer(source), cached_matrix_(NULL), cached_row_(NULL), cached_row_num_(-1) {
namespace {
const int LUMINANCE_BITS = 5;
const int LUMINANCE_SHIFT = 8 - LUMINANCE_BITS;
const int LUMINANCE_BUCKETS = 1 << LUMINANCE_BITS;
const ArrayRef<char> EMPTY (0);
} }
GlobalHistogramBinarizer::~GlobalHistogramBinarizer() { GlobalHistogramBinarizer::GlobalHistogramBinarizer(Ref<LuminanceSource> source)
} : Binarizer(source), luminances(EMPTY), buckets(LUMINANCE_BUCKETS) {}
GlobalHistogramBinarizer::~GlobalHistogramBinarizer() {}
void GlobalHistogramBinarizer::initArrays(int luminanceSize) {
if (luminances.size() < luminanceSize) {
luminances = ArrayRef<char>(luminanceSize);
}
for (int x = 0; x < LUMINANCE_BUCKETS; x++) {
buckets[x] = 0;
}
}
Ref<BitArray> GlobalHistogramBinarizer::getBlackRow(int y, Ref<BitArray> row) { Ref<BitArray> GlobalHistogramBinarizer::getBlackRow(int y, Ref<BitArray> row) {
if (y == cached_row_num_) { // std::cerr << "gbr " << y << std::endl;
if (cached_row_ != NULL) {
return cached_row_;
} else {
throw IllegalArgumentException("Too little dynamic range in luminance");
}
}
vector<int> histogram(LUMINANCE_BUCKETS, 0);
LuminanceSource& source = *getLuminanceSource(); LuminanceSource& source = *getLuminanceSource();
int width = source.getWidth(); int width = source.getWidth();
if (row == NULL || static_cast<int>(row->getSize()) < width) { if (row == NULL || static_cast<int>(row->getSize()) < width) {
@ -56,99 +60,96 @@ Ref<BitArray> GlobalHistogramBinarizer::getBlackRow(int y, Ref<BitArray> row) {
row->clear(); row->clear();
} }
//TODO(flyashi): cache this instead of allocating and deleting per row initArrays(width);
unsigned char* row_pixels = NULL; ArrayRef<char> localLuminances = source.getRow(y, luminances);
try { if (false) {
row_pixels = new unsigned char[width]; std::cerr << "gbr " << y << " r ";
row_pixels = source.getRow(y, row_pixels); for(int i=0, e=localLuminances->size(); i < e; ++i) {
for (int x = 0; x < width; x++) { std::cerr << 0+localLuminances[i] << " ";
histogram[row_pixels[x] >> LUMINANCE_SHIFT]++;
} }
int blackPoint = estimate(histogram); std::cerr << std::endl;
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;
} }
ArrayRef<int> 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<BitMatrix> GlobalHistogramBinarizer::getBlackMatrix() { Ref<BitMatrix> GlobalHistogramBinarizer::getBlackMatrix() {
if (cached_matrix_ != NULL) {
return cached_matrix_;
}
// Faster than working with the reference
LuminanceSource& source = *getLuminanceSource(); LuminanceSource& source = *getLuminanceSource();
int width = source.getWidth(); int width = source.getWidth();
int height = source.getHeight(); int height = source.getHeight();
vector<int> histogram(LUMINANCE_BUCKETS, 0); Ref<BitMatrix> matrix(new BitMatrix(width, height));
// Quickly calculates the histogram by sampling four rows from the image. // Quickly calculates the histogram by sampling four rows from the image.
// This proved to be more robust on the blackbox tests than sampling a // This proved to be more robust on the blackbox tests than sampling a
// diagonal as we used to do. // diagonal as we used to do.
ArrayRef<unsigned char> ref (width); initArrays(width);
unsigned char* row = &ref[0]; ArrayRef<int> localBuckets = buckets;
for (int y = 1; y < 5; y++) { for (int y = 1; y < 5; y++) {
int rownum = height * y / 5; int row = height * y / 5;
ArrayRef<char> localLuminances = source.getRow(row, luminances);
int right = (width << 2) / 5; int right = (width << 2) / 5;
row = source.getRow(rownum, row);
for (int x = width / 5; x < right; x++) { 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<BitMatrix> matrix_ref(new BitMatrix(width, height)); ArrayRef<char> localLuminances = source.getMatrix();
BitMatrix& matrix = *matrix_ref;
for (int y = 0; y < height; y++) { for (int y = 0; y < height; y++) {
row = source.getRow(y, row); int offset = y * width;
for (int x = 0; x < width; x++) { for (int x = 0; x < width; x++) {
if (row[x] < blackPoint) int pixel = localLuminances[offset + x] & 0xff;
matrix.set(x, y); if (pixel < blackPoint) {
matrix->set(x, y);
}
} }
} }
cached_matrix_ = matrix_ref; return matrix;
// delete [] row;
return matrix_ref;
} }
int GlobalHistogramBinarizer::estimate(vector<int> &histogram) { using namespace std;
int numBuckets = histogram.size();
int maxBucketCount = 0;
int GlobalHistogramBinarizer::estimateBlackPoint(ArrayRef<int> const& buckets) {
// Find tallest peak in histogram // Find tallest peak in histogram
int numBuckets = buckets.size();
int maxBucketCount = 0;
int firstPeak = 0; int firstPeak = 0;
int firstPeakSize = 0; int firstPeakSize = 0;
for (int i = 0; i < numBuckets; i++) { if (false) {
if (histogram[i] > firstPeakSize) { for (int x = 0; x < numBuckets; x++) {
firstPeak = i; cerr << buckets[x] << " ";
firstPeakSize = histogram[i];
} }
if (histogram[i] > maxBucketCount) { cerr << endl;
maxBucketCount = histogram[i]; }
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<int> &histogram) {
// so close to the first one // so close to the first one
int secondPeak = 0; int secondPeak = 0;
int secondPeakScore = 0; int secondPeakScore = 0;
for (int i = 0; i < numBuckets; i++) { for (int x = 0; x < numBuckets; x++) {
int distanceToBiggest = i - firstPeak; int distanceToBiggest = x - firstPeak;
// Encourage more distant second peaks by multiplying by square of distance // 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) { if (score > secondPeakScore) {
secondPeak = i; secondPeak = x;
secondPeakScore = score; secondPeakScore = score;
} }
} }
// Put firstPeak first
if (firstPeak > secondPeak) { if (firstPeak > secondPeak) {
int temp = firstPeak; int temp = firstPeak;
firstPeak = secondPeak; firstPeak = secondPeak;
@ -180,30 +180,30 @@ int GlobalHistogramBinarizer::estimate(vector<int> &histogram) {
// a false positive for 1D formats, which are relatively lenient. // a false positive for 1D formats, which are relatively lenient.
// We arbitrarily say "close" is // We arbitrarily say "close" is
// "<= 1/16 of the total histogram buckets apart" // "<= 1/16 of the total histogram buckets apart"
// std::cerr << "! " << secondPeak << " " << firstPeak << " " << numBuckets << std::endl;
if (secondPeak - firstPeak <= numBuckets >> 4) { 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 // Find a valley between them that is low and closer to the white peak
int bestValley = secondPeak - 1; int bestValley = secondPeak - 1;
int bestValleyScore = -1; int bestValleyScore = -1;
for (int i = secondPeak - 1; i > firstPeak; i--) { for (int x = secondPeak - 1; x > firstPeak; x--) {
int fromFirst = i - firstPeak; int fromFirst = x - firstPeak;
// Favor a "valley" that is not too close to either peak -- especially not // Favor a "valley" that is not too close to either peak -- especially not
// the black peak -- and that has a low value of course // the black peak -- and that has a low value of course
int score = fromFirst * fromFirst * (secondPeak - i) * int score = fromFirst * fromFirst * (secondPeak - x) *
(maxBucketCount - histogram[i]); (maxBucketCount - buckets[x]);
if (score > bestValleyScore) { if (score > bestValleyScore) {
bestValley = i; bestValley = x;
bestValleyScore = score; bestValleyScore = score;
} }
} }
// std::cerr << "bps " << (bestValley << LUMINANCE_SHIFT) << std::endl;
return bestValley << LUMINANCE_SHIFT; return bestValley << LUMINANCE_SHIFT;
} }
Ref<Binarizer> GlobalHistogramBinarizer::createBinarizer(Ref<LuminanceSource> source) { Ref<Binarizer> GlobalHistogramBinarizer::createBinarizer(Ref<LuminanceSource> source) {
return Ref<Binarizer> (new GlobalHistogramBinarizer(source)); return Ref<Binarizer> (new GlobalHistogramBinarizer(source));
} }
} // namespace zxing

View file

@ -1,3 +1,4 @@
// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*-
#ifndef __GLOBALHISTOGRAMBINARIZER_H__ #ifndef __GLOBALHISTOGRAMBINARIZER_H__
#define __GLOBALHISTOGRAMBINARIZER_H__ #define __GLOBALHISTOGRAMBINARIZER_H__
/* /*
@ -19,29 +20,29 @@
* limitations under the License. * limitations under the License.
*/ */
#include <vector>
#include <zxing/Binarizer.h> #include <zxing/Binarizer.h>
#include <zxing/common/BitArray.h> #include <zxing/common/BitArray.h>
#include <zxing/common/BitMatrix.h> #include <zxing/common/BitMatrix.h>
#include <zxing/common/Array.h>
namespace zxing { namespace zxing {
class GlobalHistogramBinarizer;
class GlobalHistogramBinarizer : public Binarizer {
private:
Ref<BitMatrix> cached_matrix_;
Ref<BitArray> cached_row_;
int cached_row_num_;
public:
GlobalHistogramBinarizer(Ref<LuminanceSource> source);
virtual ~GlobalHistogramBinarizer();
virtual Ref<BitArray> getBlackRow(int y, Ref<BitArray> row);
virtual Ref<BitMatrix> getBlackMatrix();
static int estimate(std::vector<int> &histogram);
Ref<Binarizer> createBinarizer(Ref<LuminanceSource> source);
};
} }
class zxing::GlobalHistogramBinarizer : public Binarizer {
private:
ArrayRef<char> luminances;
ArrayRef<int> buckets;
public:
GlobalHistogramBinarizer(Ref<LuminanceSource> source);
virtual ~GlobalHistogramBinarizer();
virtual Ref<BitArray> getBlackRow(int y, Ref<BitArray> row);
virtual Ref<BitMatrix> getBlackMatrix();
static int estimateBlackPoint(ArrayRef<int> const& buckets);
Ref<Binarizer> createBinarizer(Ref<LuminanceSource> source);
private:
void initArrays(int luminanceSize);
};
#endif /* GLOBALHISTOGRAMBINARIZER_H_ */ #endif /* GLOBALHISTOGRAMBINARIZER_H_ */

View file

@ -1,3 +1,4 @@
// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*-
/* /*
* GreyscaleLuminanceSource.cpp * GreyscaleLuminanceSource.cpp
* zxing * zxing
@ -21,50 +22,90 @@
#include <zxing/common/GreyscaleRotatedLuminanceSource.h> #include <zxing/common/GreyscaleRotatedLuminanceSource.h>
#include <zxing/common/IllegalArgumentException.h> #include <zxing/common/IllegalArgumentException.h>
namespace zxing { using zxing::Ref;
using zxing::ArrayRef;
GreyscaleLuminanceSource::GreyscaleLuminanceSource(unsigned char* greyData, int dataWidth, using zxing::LuminanceSource;
int dataHeight, int left, int top, int width, int height) : greyData_(greyData), using zxing::GreyscaleLuminanceSource;
dataWidth_(dataWidth), dataHeight_(dataHeight), left_(left), top_(top), width_(width),
height_(height) {
GreyscaleLuminanceSource::
GreyscaleLuminanceSource(ArrayRef<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) {
if (left + width > dataWidth || top + height > dataHeight || top < 0 || left < 0) { if (left + width > dataWidth || top + height > dataHeight || top < 0 || left < 0) {
throw IllegalArgumentException("Crop rectangle does not fit within image data."); throw IllegalArgumentException("Crop rectangle does not fit within image data.");
} }
} }
unsigned char* GreyscaleLuminanceSource::getRow(int y, unsigned char* row) { ArrayRef<char> GreyscaleLuminanceSource::getRow(int y, ArrayRef<char> row) {
if (y < 0 || y >= this->getHeight()) { if (y < 0 || y >= this->getHeight()) {
throw IllegalArgumentException("Requested row is outside the image."); throw IllegalArgumentException("Requested row is outside the image.");
} }
int width = getWidth(); int width = getWidth();
// TODO(flyashi): determine if row has enough size. if (!row || row.size() < width) {
if (row == NULL) { ArrayRef<char> temp (width);
row = new unsigned char[width_]; row = temp;
} }
int offset = (y + top_) * dataWidth_ + left_; int offset = (y + top_) * dataWidth_ + left_;
memcpy(row, &greyData_[offset], width); memcpy(&row[0], &greyData_[offset], width);
return row; return row;
} }
unsigned char* GreyscaleLuminanceSource::getMatrix() { ArrayRef<char> GreyscaleLuminanceSource::getMatrix() {
int size = width_ * height_; int size = width_ * height_;
unsigned char* result = new unsigned char[size]; ArrayRef<char> result (size);
if (left_ == 0 && top_ == 0 && dataWidth_ == width_ && dataHeight_ == height_) { if (left_ == 0 && top_ == 0 && dataWidth_ == width_ && dataHeight_ == height_) {
memcpy(result, greyData_, size); memcpy(&result[0], &greyData_[0], size);
} else { } else {
for (int row = 0; row < height_; row++) { 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; return result;
} }
Ref<LuminanceSource> GreyscaleLuminanceSource::rotateCounterClockwise() { extern "C" void abort();
// Intentionally flip the left, top, width, and height arguments as needed. dataWidth and
// dataHeight are always kept unrotated.
return Ref<LuminanceSource> (new GreyscaleRotatedLuminanceSource(greyData_, dataWidth_,
dataHeight_, top_, left_, height_, width_));
}
} /* namespace */ Ref<LuminanceSource> GreyscaleLuminanceSource::rotateCounterClockwise() {
// Intentionally flip the left, top, width, and height arguments as
// needed. dataWidth and dataHeight are always kept unrotated.
Ref<LuminanceSource> 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<char>())[c] !=
result->getRow(rot_r, ArrayRef<char>())[rot_c]) {
using namespace std;
cerr << r << "," << c << " "
<< rot_r << "," << rot_c << " "
<< (0+getRow(r, ArrayRef<char>())[c]) << " "
<< (0+result->getRow(rot_r, ArrayRef<char>())[rot_c]) << " "
<< endl;
abort();
}
}
}
*/
return result;
}

View file

@ -1,3 +1,4 @@
// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*-
#ifndef __GREYSCALE_LUMINANCE_SOURCE__ #ifndef __GREYSCALE_LUMINANCE_SOURCE__
#define __GREYSCALE_LUMINANCE_SOURCE__ #define __GREYSCALE_LUMINANCE_SOURCE__
/* /*
@ -22,11 +23,13 @@
#include <zxing/LuminanceSource.h> #include <zxing/LuminanceSource.h>
namespace zxing { namespace zxing {
class GreyscaleLuminanceSource;
}
class GreyscaleLuminanceSource : public LuminanceSource { class zxing::GreyscaleLuminanceSource : public LuminanceSource {
private: private:
unsigned char* greyData_; ArrayRef<char> greyData_;
int dataWidth_; int dataWidth_;
int dataHeight_; int dataHeight_;
int left_; int left_;
@ -34,12 +37,12 @@ class GreyscaleLuminanceSource : public LuminanceSource {
int width_; int width_;
int height_; int height_;
public: public:
GreyscaleLuminanceSource(unsigned char* greyData, int dataWidth, int dataHeight, int left, GreyscaleLuminanceSource(ArrayRef<char> greyData, int dataWidth, int dataHeight, int left,
int top, int width, int height); int top, int width, int height);
unsigned char* getRow(int y, unsigned char* row); ArrayRef<char> getRow(int y, ArrayRef<char> row);
unsigned char* getMatrix(); ArrayRef<char> getMatrix();
bool isRotateSupported() const { bool isRotateSupported() const {
return true; return true;
@ -57,6 +60,4 @@ class GreyscaleLuminanceSource : public LuminanceSource {
}; };
} /* namespace */
#endif #endif

View file

@ -1,3 +1,4 @@
// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*-
/* /*
* GreyscaleRotatedLuminanceSource.cpp * GreyscaleRotatedLuminanceSource.cpp
* zxing * zxing
@ -21,15 +22,21 @@
#include <zxing/common/GreyscaleRotatedLuminanceSource.h> #include <zxing/common/GreyscaleRotatedLuminanceSource.h>
#include <zxing/common/IllegalArgumentException.h> #include <zxing/common/IllegalArgumentException.h>
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 // Note that dataWidth and dataHeight are not reversed, as we need to
// greyData correctly, which does not get rotated. // be able to traverse the greyData correctly, which does not get
GreyscaleRotatedLuminanceSource::GreyscaleRotatedLuminanceSource(unsigned char* greyData, // rotated.
int dataWidth, int dataHeight, int left, int top, int width, int height) : greyData_(greyData), GreyscaleRotatedLuminanceSource::
dataWidth_(dataWidth), left_(left), top_(top), width_(width), GreyscaleRotatedLuminanceSource(ArrayRef<char> 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) { height_(height) {
// Intentionally comparing to the opposite dimension since we're rotated. // Intentionally comparing to the opposite dimension since we're rotated.
if (left + width > dataHeight || top + height > dataWidth) { if (left + width > dataHeight || top + height > dataWidth) {
throw IllegalArgumentException("Crop rectangle does not fit within image data."); 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. // The API asks for rows, but we're rotated, so we return columns.
unsigned char* GreyscaleRotatedLuminanceSource::getRow(int y, unsigned char* row) { ArrayRef<char>
GreyscaleRotatedLuminanceSource::getRow(int y, ArrayRef<char> row) {
if (y < 0 || y >= getHeight()) { if (y < 0 || y >= getHeight()) {
throw IllegalArgumentException("Requested row is outside the image."); throw IllegalArgumentException("Requested row is outside the image.");
} }
int width = getWidth(); if (!row || row.size() < width_) {
if (row == NULL) { row = ArrayRef<char>(width_);
row = new unsigned char[width];
} }
int offset = (left_ * dataWidth_) + (dataWidth_ - 1 - (y + top_)); 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]; row[x] = greyData_[offset];
offset += dataWidth_; offset += dataWidth_;
} }
return row; return row;
} }
unsigned char* GreyscaleRotatedLuminanceSource::getMatrix() { ArrayRef<char> GreyscaleRotatedLuminanceSource::getMatrix() {
unsigned char* result = new unsigned char[width_ * height_]; ArrayRef<char> result (width_ * height_);
// This depends on getRow() honoring its second parameter.
for (int y = 0; y < height_; y++) { 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; return result;
} }
} // namespace

View file

@ -1,3 +1,4 @@
// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*-
#ifndef __GREYSCALE_ROTATED_LUMINANCE_SOURCE__ #ifndef __GREYSCALE_ROTATED_LUMINANCE_SOURCE__
#define __GREYSCALE_ROTATED_LUMINANCE_SOURCE__ #define __GREYSCALE_ROTATED_LUMINANCE_SOURCE__
/* /*
@ -23,22 +24,24 @@
#include <zxing/LuminanceSource.h> #include <zxing/LuminanceSource.h>
namespace zxing { namespace zxing {
class GreyscaleRotatedLuminanceSource;
}
class GreyscaleRotatedLuminanceSource : public LuminanceSource { class zxing::GreyscaleRotatedLuminanceSource : public LuminanceSource {
private: private:
unsigned char* greyData_; ArrayRef<char> greyData_;
int dataWidth_; const int dataWidth_;
int left_; const int left_;
int top_; const int top_;
int width_; const int width_;
int height_; const int height_;
public: public:
GreyscaleRotatedLuminanceSource(unsigned char* greyData, int dataWidth, int dataHeight, GreyscaleRotatedLuminanceSource(ArrayRef<char> greyData, int dataWidth, int dataHeight,
int left, int top, int width, int height); int left, int top, int width, int height);
unsigned char* getRow(int y, unsigned char* row); ArrayRef<char> getRow(int y, ArrayRef<char> row);
unsigned char* getMatrix(); ArrayRef<char> getMatrix();
bool isRotateSupported() const { bool isRotateSupported() const {
return false; return false;
@ -54,6 +57,4 @@ public:
}; };
} /* namespace */
#endif #endif

View file

@ -59,7 +59,7 @@ Ref<BitMatrix> HybridBinarizer::getBlackMatrix() {
int width = source.getWidth(); int width = source.getWidth();
int height = source.getHeight(); int height = source.getHeight();
if (width >= MINIMUM_DIMENSION && height >= MINIMUM_DIMENSION) { if (width >= MINIMUM_DIMENSION && height >= MINIMUM_DIMENSION) {
unsigned char* luminances = source.getMatrix(); ArrayRef<char> luminances = source.getMatrix();
int subWidth = width >> BLOCK_SIZE_POWER; int subWidth = width >> BLOCK_SIZE_POWER;
if ((width & BLOCK_SIZE_MASK) != 0) { if ((width & BLOCK_SIZE_MASK) != 0) {
subWidth++; subWidth++;
@ -68,7 +68,7 @@ Ref<BitMatrix> HybridBinarizer::getBlackMatrix() {
if ((height & BLOCK_SIZE_MASK) != 0) { if ((height & BLOCK_SIZE_MASK) != 0) {
subHeight++; subHeight++;
} }
int* blackPoints = ArrayRef<int> blackPoints =
calculateBlackPoints(luminances, subWidth, subHeight, width, height); calculateBlackPoints(luminances, subWidth, subHeight, width, height);
Ref<BitMatrix> newMatrix (new BitMatrix(width, height)); Ref<BitMatrix> newMatrix (new BitMatrix(width, height));
@ -80,13 +80,6 @@ Ref<BitMatrix> HybridBinarizer::getBlackMatrix() {
blackPoints, blackPoints,
newMatrix); newMatrix);
matrix_ = 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 { } else {
// If the image is too small, fall back to the global histogram approach. // If the image is too small, fall back to the global histogram approach.
matrix_ = GlobalHistogramBinarizer::getBlackMatrix(); matrix_ = GlobalHistogramBinarizer::getBlackMatrix();
@ -101,12 +94,12 @@ namespace {
} }
void void
HybridBinarizer::calculateThresholdForBlock(unsigned char* luminances, HybridBinarizer::calculateThresholdForBlock(ArrayRef<char> luminances,
int subWidth, int subWidth,
int subHeight, int subHeight,
int width, int width,
int height, int height,
int blackPoints[], ArrayRef<int> blackPoints,
Ref<BitMatrix> const& matrix) { Ref<BitMatrix> const& matrix) {
for (int y = 0; y < subHeight; y++) { for (int y = 0; y < subHeight; y++) {
int yoffset = y << BLOCK_SIZE_POWER; 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<char> luminances,
int xoffset, int xoffset,
int yoffset, int yoffset,
int threshold, int threshold,
@ -156,7 +149,7 @@ void HybridBinarizer::thresholdBlock(unsigned char* luminances,
} }
namespace { namespace {
inline int getBlackPointFromNeighbors(int* blackPoints, int subWidth, int x, int y) { inline int getBlackPointFromNeighbors(ArrayRef<int> blackPoints, int subWidth, int x, int y) {
return (blackPoints[(y-1)*subWidth+x] + return (blackPoints[(y-1)*subWidth+x] +
2*blackPoints[y*subWidth+x-1] + 2*blackPoints[y*subWidth+x-1] +
blackPoints[(y-1)*subWidth+x-1]) >> 2; blackPoints[(y-1)*subWidth+x-1]) >> 2;
@ -164,14 +157,14 @@ namespace {
} }
int* HybridBinarizer::calculateBlackPoints(unsigned char* luminances, ArrayRef<int> HybridBinarizer::calculateBlackPoints(ArrayRef<char> luminances,
int subWidth, int subWidth,
int subHeight, int subHeight,
int width, int width,
int height) { int height) {
const int minDynamicRange = 24; const int minDynamicRange = 24;
int *blackPoints = new int[subHeight * subWidth]; ArrayRef<int> blackPoints (subHeight * subWidth);
for (int y = 0; y < subHeight; y++) { for (int y = 0; y < subHeight; y++) {
int yoffset = y << BLOCK_SIZE_POWER; int yoffset = y << BLOCK_SIZE_POWER;
int maxYOffset = height - BLOCK_SIZE; int maxYOffset = height - BLOCK_SIZE;

View file

@ -42,19 +42,19 @@ namespace zxing {
private: private:
// We'll be using one-D arrays because C++ can't dynamically allocate 2D // We'll be using one-D arrays because C++ can't dynamically allocate 2D
// arrays // arrays
int* calculateBlackPoints(unsigned char* luminances, ArrayRef<int> calculateBlackPoints(ArrayRef<char> luminances,
int subWidth, int subWidth,
int subHeight, int subHeight,
int width, int width,
int height); int height);
void calculateThresholdForBlock(unsigned char* luminances, void calculateThresholdForBlock(ArrayRef<char> luminances,
int subWidth, int subWidth,
int subHeight, int subHeight,
int width, int width,
int height, int height,
int blackPoints[], ArrayRef<int> blackPoints,
Ref<BitMatrix> const& matrix); Ref<BitMatrix> const& matrix);
void thresholdBlock(unsigned char* luminances, void thresholdBlock(ArrayRef<char>luminances,
int xoffset, int xoffset,
int yoffset, int yoffset,
int threshold, int threshold,

View file

@ -1,3 +1,4 @@
// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*-
/* /*
* String.cpp * String.cpp
* zxing * zxing
@ -20,19 +21,25 @@
#include <zxing/common/Str.h> #include <zxing/common/Str.h>
namespace zxing { using std::string;
using namespace std; using zxing::String;
using zxing::Ref;
String::String(const std::string &text) : String::String(const std::string &text) :
text_(text) { text_(text) {
} }
const std::string& String::getText() const { const std::string& String::getText() const {
return text_; 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> String::substring(int i) const {
return Ref<String>(new String(text_.substr(i)));
}
std::ostream& zxing::operator << (std::ostream& out, String const& s) {
out << s.text_; out << s.text_;
return out; return out;
} }
}

View file

@ -1,3 +1,4 @@
// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*-
#ifndef __STR_H__ #ifndef __STR_H__
#define __STR_H__ #define __STR_H__
@ -25,16 +26,21 @@
#include <zxing/common/Counted.h> #include <zxing/common/Counted.h>
namespace zxing { namespace zxing {
class String;
std::ostream& operator << (std::ostream& out, String const& s);
}
class String : public Counted { class zxing::String : public Counted {
private: private:
std::string text_; std::string text_;
public: public:
String(const std::string &text); explicit String(const std::string &text);
char charAt(int) const;
Ref<String> substring(int) const;
const std::string &getText() 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__ #endif // __COMMON__STRING_H__

View file

@ -35,7 +35,7 @@ char const* const StringUtils::ISO88591 = "ISO8859-1";
const bool StringUtils::ASSUME_SHIFT_JIS = false; const bool StringUtils::ASSUME_SHIFT_JIS = false;
string string
StringUtils::guessEncoding(unsigned char* bytes, int length, StringUtils::guessEncoding(char* bytes, int length,
Hashtable const& hints) { Hashtable const& hints) {
Hashtable::const_iterator i = hints.find(DecodeHints::CHARACTER_SET); Hashtable::const_iterator i = hints.find(DecodeHints::CHARACTER_SET);
if (i != hints.end()) { if (i != hints.end()) {
@ -64,7 +64,7 @@ StringUtils::guessEncoding(unsigned char* bytes, int length,
//int isoHighChars = 0; //int isoHighChars = 0;
int isoHighOther = 0; int isoHighOther = 0;
typedef unsigned char byte; typedef char byte;
boolean utf8bom = length > 3 && boolean utf8bom = length > 3 &&
bytes[0] == (byte) 0xEF && bytes[0] == (byte) 0xEF &&
bytes[1] == (byte) 0xBB && bytes[1] == (byte) 0xBB &&

View file

@ -46,7 +46,7 @@ public:
typedef std::map<DecodeHintType, std::string> Hashtable; typedef std::map<DecodeHintType, std::string> 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 #endif

View file

@ -28,27 +28,28 @@
namespace zxing { namespace zxing {
class GenericGF; class GenericGF;
class GenericGFPoly;
class GenericGFPoly : public Counted {
private:
Ref<GenericGF> field_;
ArrayRef<int> coefficients_;
public:
GenericGFPoly(Ref<GenericGF> field, ArrayRef<int> coefficients);
ArrayRef<int> getCoefficients();
int getDegree();
bool isZero();
int getCoefficient(int degree);
int evaluateAt(int a);
Ref<GenericGFPoly> addOrSubtract(Ref<GenericGFPoly> other);
Ref<GenericGFPoly> multiply(Ref<GenericGFPoly> other);
Ref<GenericGFPoly> multiply(int scalar);
Ref<GenericGFPoly> multiplyByMonomial(int degree, int coefficient);
std::vector<Ref<GenericGFPoly> > divide(Ref<GenericGFPoly> other);
//#warning todo: add print method
};
} }
class zxing::GenericGFPoly : public Counted {
private:
Ref<GenericGF> field_;
ArrayRef<int> coefficients_;
public:
GenericGFPoly(Ref<GenericGF> field, ArrayRef<int> coefficients);
ArrayRef<int> getCoefficients();
int getDegree();
bool isZero();
int getCoefficient(int degree);
int evaluateAt(int a);
Ref<GenericGFPoly> addOrSubtract(Ref<GenericGFPoly> other);
Ref<GenericGFPoly> multiply(Ref<GenericGFPoly> other);
Ref<GenericGFPoly> multiply(int scalar);
Ref<GenericGFPoly> multiplyByMonomial(int degree, int coefficient);
std::vector<Ref<GenericGFPoly> > divide(Ref<GenericGFPoly> other);
//#warning todo: add print method
};
#endif //GENERICGFPOLY_H #endif //GENERICGFPOLY_H

View file

@ -1,3 +1,4 @@
// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*-
/* /*
* ReedSolomonDecoder.cpp * ReedSolomonDecoder.cpp
* zxing * zxing
@ -25,36 +26,23 @@
#include <zxing/common/reedsolomon/ReedSolomonException.h> #include <zxing/common/reedsolomon/ReedSolomonException.h>
#include <zxing/common/IllegalArgumentException.h> #include <zxing/common/IllegalArgumentException.h>
using namespace std; using namespace std; // remove
namespace zxing { using zxing::Ref;
using zxing::ArrayRef;
using zxing::ReedSolomonDecoder;
using zxing::GenericGFPoly;
ReedSolomonDecoder::ReedSolomonDecoder(Ref<GenericGF> fld) : ReedSolomonDecoder::ReedSolomonDecoder(Ref<GenericGF> fld) :
field(fld) { field(fld) {
} }
ReedSolomonDecoder::~ReedSolomonDecoder() { ReedSolomonDecoder::~ReedSolomonDecoder() {
} }
void ReedSolomonDecoder::decode(ArrayRef<int> received, int twoS) { void ReedSolomonDecoder::decode(ArrayRef<int> received, int twoS) {
Ref<GenericGFPoly> poly(new GenericGFPoly(field, received)); Ref<GenericGFPoly> poly(new GenericGFPoly(field, received));
ArrayRef<int> syndromeCoefficients(twoS);
/*
#ifdef DEBUG
cout << "decoding with poly " << *poly << endl;
#endif
*/
ArrayRef<int> syndromeCoefficients(new Array<int> (twoS));
#ifdef DEBUG
cout << "syndromeCoefficients array = " <<
syndromeCoefficients.array_ << endl;
#endif
bool dataMatrix = (field.object_ == GenericGF::DATA_MATRIX_FIELD_256.object_); bool dataMatrix = (field.object_ == GenericGF::DATA_MATRIX_FIELD_256.object_);
bool noError = true; bool noError = true;
for (int i = 0; i < twoS; i++) { for (int i = 0; i < twoS; i++) {
@ -67,17 +55,18 @@ void ReedSolomonDecoder::decode(ArrayRef<int> received, int twoS) {
if (noError) { if (noError) {
return; return;
} }
Ref<GenericGFPoly> syndrome(new GenericGFPoly(field, syndromeCoefficients)); Ref<GenericGFPoly> syndrome(new GenericGFPoly(field, syndromeCoefficients));
Ref<GenericGFPoly> monomial = field->buildMonomial(twoS, 1); vector<Ref<GenericGFPoly> > sigmaOmega =
vector<Ref<GenericGFPoly> > sigmaOmega = runEuclideanAlgorithm(monomial, syndrome, twoS); runEuclideanAlgorithm(field->buildMonomial(twoS, 1), syndrome, twoS);
ArrayRef<int> errorLocations = findErrorLocations(sigmaOmega[0]); Ref<GenericGFPoly> sigma = sigmaOmega[0];
ArrayRef<int> errorMagitudes = findErrorMagnitudes(sigmaOmega[1], errorLocations, dataMatrix); Ref<GenericGFPoly> omega = sigmaOmega[1];
for (unsigned i = 0; i < errorLocations->size(); i++) { ArrayRef<int> errorLocations = findErrorLocations(sigma);
ArrayRef<int> errorMagitudes = findErrorMagnitudes(omega, errorLocations, dataMatrix);
for (int i = 0; i < errorLocations->size(); i++) {
int position = received->size() - 1 - field->log(errorLocations[i]); int position = received->size() - 1 - field->log(errorLocations[i]);
//TODO: check why the position would be invalid if (position < 0) {
if (position < 0 || (size_t)position >= received.size()) throw ReedSolomonException("Bad error location");
throw IllegalArgumentException("Invalid position (ReedSolomonDecoder)"); }
received[position] = GenericGF::addOrSubtract(received[position], errorMagitudes[i]); received[position] = GenericGF::addOrSubtract(received[position], errorMagitudes[i]);
} }
} }
@ -137,12 +126,12 @@ vector<Ref<GenericGFPoly> > ReedSolomonDecoder::runEuclideanAlgorithm(Ref<Generi
/* /*
#ifdef DEBUG #ifdef DEBUG
cout << "t = " << *t << endl; cout << "t = " << *t << endl;
cout << "r = " << *r << "\n"; cout << "r = " << *r << "\n";
cout << "sigma = " << *sigma << endl; cout << "sigma = " << *sigma << endl;
cout << "omega = " << *omega << endl; cout << "omega = " << *omega << endl;
#endif #endif
*/ */
vector<Ref<GenericGFPoly> > result(2); vector<Ref<GenericGFPoly> > result(2);
@ -184,15 +173,14 @@ ArrayRef<int> ReedSolomonDecoder::findErrorMagnitudes(Ref<GenericGFPoly> errorEv
for (int j = 0; j < s; j++) { for (int j = 0; j < s; j++) {
if (i != j) { if (i != j) {
denominator = field->multiply(denominator, GenericGF::addOrSubtract(1, field->multiply(errorLocations[j], denominator = field->multiply(denominator, GenericGF::addOrSubtract(1, field->multiply(errorLocations[j],
xiInverse))); xiInverse)));
} }
} }
result[i] = field->multiply(errorEvaluator->evaluateAt(xiInverse), field->inverse(denominator)); result[i] = field->multiply(errorEvaluator->evaluateAt(xiInverse), field->inverse(denominator));
if (dataMatrix) { if (dataMatrix) {
result[i] = field->multiply(result[i], xiInverse); result[i] = field->multiply(result[i], xiInverse);
} }
} }
return result; return result;
} }
}

View file

@ -50,7 +50,7 @@ Ref<Result> DataMatrixReader::decode(Ref<BinaryBitmap> image, DecodeHints hints)
cout << "(2) detected, have detectorResult " << detectorResult.object_ << "\n" << flush; cout << "(2) detected, have detectorResult " << detectorResult.object_ << "\n" << flush;
#endif #endif
std::vector<Ref<ResultPoint> > points(detectorResult->getPoints()); ArrayRef< Ref<ResultPoint> > points(detectorResult->getPoints());
#ifdef DEBUG #ifdef DEBUG
@ -69,7 +69,7 @@ Ref<Result> DataMatrixReader::decode(Ref<BinaryBitmap> image, DecodeHints hints)
#endif #endif
Ref<Result> result( Ref<Result> result(
new Result(decoderResult->getText(), decoderResult->getRawBytes(), points, BarcodeFormat_DATA_MATRIX)); new Result(decoderResult->getText(), decoderResult->getRawBytes(), points, BarcodeFormat::DATA_MATRIX));
#ifdef DEBUG #ifdef DEBUG
cout << "(5) created result " << result.object_ << ", returning\n" << flush; cout << "(5) created result " << result.object_ << ", returning\n" << flush;
#endif #endif

View file

@ -57,9 +57,9 @@ Ref<Version> BitMatrixParser::readVersion(Ref<BitMatrix> bitMatrix) {
throw ReaderException("Couldn't decode version"); throw ReaderException("Couldn't decode version");
} }
ArrayRef<unsigned char> BitMatrixParser::readCodewords() { ArrayRef<char> BitMatrixParser::readCodewords() {
ArrayRef<unsigned char> result(parsedVersion_->getTotalCodewords()); ArrayRef<char> result(parsedVersion_->getTotalCodewords());
int resultOffset = 0; int resultOffset = 0;
int row = 4; int row = 4;
int column = 0; int column = 0;
@ -75,22 +75,22 @@ ArrayRef<unsigned char> BitMatrixParser::readCodewords() {
do { do {
// Check the four corner cases // Check the four corner cases
if ((row == numRows) && (column == 0) && !corner1Read) { if ((row == numRows) && (column == 0) && !corner1Read) {
result[resultOffset++] = (unsigned char) readCorner1(numRows, numColumns); result[resultOffset++] = (char) readCorner1(numRows, numColumns);
row -= 2; row -= 2;
column +=2; column +=2;
corner1Read = true; corner1Read = true;
} else if ((row == numRows-2) && (column == 0) && ((numColumns & 0x03) != 0) && !corner2Read) { } 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; row -= 2;
column +=2; column +=2;
corner2Read = true; corner2Read = true;
} else if ((row == numRows+4) && (column == 2) && ((numColumns & 0x07) == 0) && !corner3Read) { } 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; row -= 2;
column +=2; column +=2;
corner3Read = true; corner3Read = true;
} else if ((row == numRows-2) && (column == 0) && ((numColumns & 0x07) == 4) && !corner4Read) { } 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; row -= 2;
column +=2; column +=2;
corner4Read = true; corner4Read = true;
@ -98,7 +98,7 @@ ArrayRef<unsigned char> BitMatrixParser::readCodewords() {
// Sweep upward diagonally to the right // Sweep upward diagonally to the right
do { do {
if ((row < numRows) && (column >= 0) && !readBitMatrix_->get(column, row)) { 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; row -= 2;
column +=2; column +=2;
@ -109,7 +109,7 @@ ArrayRef<unsigned char> BitMatrixParser::readCodewords() {
// Sweep downward diagonally to the left // Sweep downward diagonally to the left
do { do {
if ((row >= 0) && (column < numColumns) && !readBitMatrix_->get(column, row)) { 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; row += 2;
column -=2; column -=2;

View file

@ -41,7 +41,7 @@ private:
public: public:
BitMatrixParser(Ref<BitMatrix> bitMatrix); BitMatrixParser(Ref<BitMatrix> bitMatrix);
Ref<Version> readVersion(Ref<BitMatrix> bitMatrix); Ref<Version> readVersion(Ref<BitMatrix> bitMatrix);
ArrayRef<unsigned char> readCodewords(); ArrayRef<char> readCodewords();
bool readModule(int row, int column, int numRows, int numColumns); bool readModule(int row, int column, int numRows, int numColumns);
private: private:

View file

@ -26,7 +26,7 @@ namespace datamatrix {
using namespace std; using namespace std;
DataBlock::DataBlock(int numDataCodewords, ArrayRef<unsigned char> codewords) : DataBlock::DataBlock(int numDataCodewords, ArrayRef<char> codewords) :
numDataCodewords_(numDataCodewords), codewords_(codewords) { numDataCodewords_(numDataCodewords), codewords_(codewords) {
} }
@ -34,11 +34,11 @@ int DataBlock::getNumDataCodewords() {
return numDataCodewords_; return numDataCodewords_;
} }
ArrayRef<unsigned char> DataBlock::getCodewords() { ArrayRef<char> DataBlock::getCodewords() {
return codewords_; return codewords_;
} }
std::vector<Ref<DataBlock> > DataBlock::getDataBlocks(ArrayRef<unsigned char> rawCodewords, Version *version) { std::vector<Ref<DataBlock> > DataBlock::getDataBlocks(ArrayRef<char> rawCodewords, Version *version) {
// Figure out the number and size of data blocks used by this version and // Figure out the number and size of data blocks used by this version and
// error correction level // error correction level
ECBlocks* ecBlocks = version->getECBlocks(); ECBlocks* ecBlocks = version->getECBlocks();
@ -58,7 +58,7 @@ std::vector<Ref<DataBlock> > DataBlock::getDataBlocks(ArrayRef<unsigned char> ra
for (int i = 0; i < ecBlock->getCount(); i++) { for (int i = 0; i < ecBlock->getCount(); i++) {
int numDataCodewords = ecBlock->getDataCodewords(); int numDataCodewords = ecBlock->getDataCodewords();
int numBlockCodewords = ecBlocks->getECCodewords() + numDataCodewords; int numBlockCodewords = ecBlocks->getECCodewords() + numDataCodewords;
ArrayRef<unsigned char> buffer(numBlockCodewords); ArrayRef<char> buffer(numBlockCodewords);
Ref<DataBlock> blockRef(new DataBlock(numDataCodewords, buffer)); Ref<DataBlock> blockRef(new DataBlock(numDataCodewords, buffer));
result[numResultBlocks++] = blockRef; result[numResultBlocks++] = blockRef;
} }
@ -102,7 +102,7 @@ std::vector<Ref<DataBlock> > DataBlock::getDataBlocks(ArrayRef<unsigned char> ra
} }
} }
if ((size_t)rawCodewordsOffset != rawCodewords.size()) { if (rawCodewordsOffset != rawCodewords.size()) {
throw IllegalArgumentException("rawCodewordsOffset != rawCodewords.length"); throw IllegalArgumentException("rawCodewordsOffset != rawCodewords.length");
} }

View file

@ -32,15 +32,15 @@ namespace datamatrix {
class DataBlock : public Counted { class DataBlock : public Counted {
private: private:
int numDataCodewords_; int numDataCodewords_;
ArrayRef<unsigned char> codewords_; ArrayRef<char> codewords_;
DataBlock(int numDataCodewords, ArrayRef<unsigned char> codewords); DataBlock(int numDataCodewords, ArrayRef<char> codewords);
public: public:
static std::vector<Ref<DataBlock> > getDataBlocks(ArrayRef<unsigned char> rawCodewords, Version *version); static std::vector<Ref<DataBlock> > getDataBlocks(ArrayRef<char> rawCodewords, Version *version);
int getNumDataCodewords(); int getNumDataCodewords();
ArrayRef<unsigned char> getCodewords(); ArrayRef<char> getCodewords();
}; };
} }

View file

@ -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 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '{', '|', '}', '~', (char) 127
}; };
Ref<DecoderResult> DecodedBitStreamParser::decode(ArrayRef<unsigned char> bytes) { Ref<DecoderResult> DecodedBitStreamParser::decode(ArrayRef<char> bytes) {
Ref<BitSource> bits(new BitSource(bytes)); Ref<BitSource> bits(new BitSource(bytes));
ostringstream result; ostringstream result;
ostringstream resultTrailer; ostringstream resultTrailer;
vector<unsigned char> byteSegments; vector<char> byteSegments;
int mode = ASCII_ENCODE; int mode = ASCII_ENCODE;
do { do {
if (mode == ASCII_ENCODE) { if (mode == ASCII_ENCODE) {
@ -87,7 +87,7 @@ Ref<DecoderResult> DecodedBitStreamParser::decode(ArrayRef<unsigned char> bytes)
if (resultTrailer.str().size() > 0) { if (resultTrailer.str().size() > 0) {
result << resultTrailer.str(); result << resultTrailer.str();
} }
ArrayRef<unsigned char> rawBytes(bytes); ArrayRef<char> rawBytes(bytes);
Ref<String> text(new String(result.str())); Ref<String> text(new String(result.str()));
return Ref<DecoderResult>(new DecoderResult(rawBytes, text)); return Ref<DecoderResult>(new DecoderResult(rawBytes, text));
} }
@ -381,7 +381,7 @@ void DecodedBitStreamParser::decodeEdifactSegment(Ref<BitSource> bits, ostringst
} while (bits->available() > 0); } while (bits->available() > 0);
} }
void DecodedBitStreamParser::decodeBase256Segment(Ref<BitSource> bits, ostringstream& result, vector<unsigned char> byteSegments) { void DecodedBitStreamParser::decodeBase256Segment(Ref<BitSource> bits, ostringstream& result, vector<char> byteSegments) {
// Figure out how long the Base 256 Segment is. // Figure out how long the Base 256 Segment is.
int codewordPosition = 1 + bits->getByteOffset(); // position is 1-indexed int codewordPosition = 1 + bits->getByteOffset(); // position is 1-indexed
int d1 = unrandomize255State(bits->readBits(8), codewordPosition++); int d1 = unrandomize255State(bits->readBits(8), codewordPosition++);
@ -399,7 +399,7 @@ void DecodedBitStreamParser::decodeBase256Segment(Ref<BitSource> bits, ostringst
throw FormatException("NegativeArraySizeException"); throw FormatException("NegativeArraySizeException");
} }
unsigned char* bytes = new unsigned char[count]; char* bytes = new char[count];
for (int i = 0; i < count; i++) { for (int i = 0; i < count; i++) {
// Have seen this particular error in the wild, such as at // 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 // http://www.bcgen.com/demo/IDAutomationStreamingDataMatrix.aspx?MODE=3&D=Fred&PFMT=3&PT=F&X=0.3&O=0&LM=0.2

View file

@ -79,23 +79,23 @@ private:
/** /**
* See ISO 16022:2006, 5.2.9 and Annex B, B.2 * See ISO 16022:2006, 5.2.9 and Annex B, B.2
*/ */
void decodeBase256Segment(Ref<BitSource> bits, std::ostringstream &result, std::vector<unsigned char> byteSegments); void decodeBase256Segment(Ref<BitSource> bits, std::ostringstream &result, std::vector<char> byteSegments);
void parseTwoBytes(int firstByte, int secondByte, int* result); void parseTwoBytes(int firstByte, int secondByte, int* result);
/** /**
* See ISO 16022:2006, Annex B, B.2 * See ISO 16022:2006, Annex B, B.2
*/ */
unsigned char unrandomize255State(int randomizedBase256Codeword, char unrandomize255State(int randomizedBase256Codeword,
int base256CodewordPosition) { int base256CodewordPosition) {
int pseudoRandomNumber = ((149 * base256CodewordPosition) % 255) + 1; int pseudoRandomNumber = ((149 * base256CodewordPosition) % 255) + 1;
int tempVariable = randomizedBase256Codeword - pseudoRandomNumber; 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: public:
DecodedBitStreamParser() { }; DecodedBitStreamParser() { };
Ref<DecoderResult> decode(ArrayRef<unsigned char> bytes); Ref<DecoderResult> decode(ArrayRef<char> bytes);
}; };
} }

View file

@ -36,7 +36,7 @@ Decoder::Decoder() :
} }
void Decoder::correctErrors(ArrayRef<unsigned char> codewordBytes, int numDataCodewords) { void Decoder::correctErrors(ArrayRef<char> codewordBytes, int numDataCodewords) {
int numCodewords = codewordBytes->size(); int numCodewords = codewordBytes->size();
ArrayRef<int> codewordInts(numCodewords); ArrayRef<int> codewordInts(numCodewords);
for (int i = 0; i < numCodewords; i++) { for (int i = 0; i < numCodewords; i++) {
@ -52,7 +52,7 @@ void Decoder::correctErrors(ArrayRef<unsigned char> codewordBytes, int numDataCo
// Copy back into array of bytes -- only need to worry about the bytes that were data // 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 // We don't care about errors in the error-correction codewords
for (int i = 0; i < numDataCodewords; i++) { for (int i = 0; i < numDataCodewords; i++) {
codewordBytes[i] = (unsigned char)codewordInts[i]; codewordBytes[i] = (char)codewordInts[i];
} }
} }
@ -62,7 +62,7 @@ Ref<DecoderResult> Decoder::decode(Ref<BitMatrix> bits) {
Version *version = parser.readVersion(bits); Version *version = parser.readVersion(bits);
// Read codewords // Read codewords
ArrayRef<unsigned char> codewords(parser.readCodewords()); ArrayRef<char> codewords(parser.readCodewords());
// Separate into data blocks // Separate into data blocks
std::vector<Ref<DataBlock> > dataBlocks = DataBlock::getDataBlocks(codewords, version); std::vector<Ref<DataBlock> > dataBlocks = DataBlock::getDataBlocks(codewords, version);
@ -73,12 +73,12 @@ Ref<DecoderResult> Decoder::decode(Ref<BitMatrix> bits) {
for (int i = 0; i < dataBlocksCount; i++) { for (int i = 0; i < dataBlocksCount; i++) {
totalBytes += dataBlocks[i]->getNumDataCodewords(); totalBytes += dataBlocks[i]->getNumDataCodewords();
} }
ArrayRef<unsigned char> resultBytes(totalBytes); ArrayRef<char> resultBytes(totalBytes);
// Error-correct and copy data blocks together into a stream of bytes // Error-correct and copy data blocks together into a stream of bytes
for (int j = 0; j < dataBlocksCount; j++) { for (int j = 0; j < dataBlocksCount; j++) {
Ref<DataBlock> dataBlock(dataBlocks[j]); Ref<DataBlock> dataBlock(dataBlocks[j]);
ArrayRef<unsigned char> codewordBytes = dataBlock->getCodewords(); ArrayRef<char> codewordBytes = dataBlock->getCodewords();
int numDataCodewords = dataBlock->getNumDataCodewords(); int numDataCodewords = dataBlock->getNumDataCodewords();
correctErrors(codewordBytes, numDataCodewords); correctErrors(codewordBytes, numDataCodewords);
for (int i = 0; i < numDataCodewords; i++) { for (int i = 0; i < numDataCodewords; i++) {

View file

@ -35,7 +35,7 @@ class Decoder {
private: private:
ReedSolomonDecoder rsDecoder_; ReedSolomonDecoder rsDecoder_;
void correctErrors(ArrayRef<unsigned char> bytes, int numDataCodewords); void correctErrors(ArrayRef<char> bytes, int numDataCodewords);
public: public:
Decoder(); Decoder();

View file

@ -245,7 +245,7 @@ Ref<DetectorResult> Detector::detect() {
bits = sampleGrid(image_, dimensionCorrected, dimensionCorrected, transform); bits = sampleGrid(image_, dimensionCorrected, dimensionCorrected, transform);
} }
std::vector<Ref<ResultPoint> > points(4); ArrayRef< Ref<ResultPoint> > points (new Array< Ref<ResultPoint> >(4));
points[0].reset(topLeft); points[0].reset(topLeft);
points[1].reset(bottomLeft); points[1].reset(bottomLeft);
points[2].reset(correctedTopRight); points[2].reset(correctedTopRight);

View file

@ -60,8 +60,8 @@ void GenericMultipleBarcodeReader::doDecodeMultiple(Ref<BinaryBitmap> image,
} }
results.push_back(translateResultPoints(result, xOffset, yOffset)); results.push_back(translateResultPoints(result, xOffset, yOffset));
const std::vector<Ref<ResultPoint> > resultPoints = result->getResultPoints(); ArrayRef< Ref<ResultPoint> > resultPoints = result->getResultPoints();
if (resultPoints.empty()) { if (resultPoints->empty()) {
return; return;
} }
@ -71,7 +71,7 @@ void GenericMultipleBarcodeReader::doDecodeMultiple(Ref<BinaryBitmap> image,
float minY = height; float minY = height;
float maxX = 0.0f; float maxX = 0.0f;
float maxY = 0.0f; float maxY = 0.0f;
for (unsigned int i = 0; i < resultPoints.size(); i++) { for (int i = 0; i < resultPoints.size(); i++) {
Ref<ResultPoint> point = resultPoints[i]; Ref<ResultPoint> point = resultPoints[i];
float x = point->getX(); float x = point->getX();
float y = point->getY(); float y = point->getY();
@ -112,14 +112,14 @@ void GenericMultipleBarcodeReader::doDecodeMultiple(Ref<BinaryBitmap> image,
} }
Ref<Result> GenericMultipleBarcodeReader::translateResultPoints(Ref<Result> result, int xOffset, int yOffset){ Ref<Result> GenericMultipleBarcodeReader::translateResultPoints(Ref<Result> result, int xOffset, int yOffset){
const std::vector<Ref<ResultPoint> > oldResultPoints = result->getResultPoints(); ArrayRef< Ref<ResultPoint> > oldResultPoints = result->getResultPoints();
if (oldResultPoints.empty()) { if (oldResultPoints->empty()) {
return result; return result;
} }
std::vector<Ref<ResultPoint> > newResultPoints; ArrayRef< Ref<ResultPoint> > newResultPoints;
for (unsigned int i = 0; i < oldResultPoints.size(); i++) { for (int i = 0; i < oldResultPoints.size(); i++) {
Ref<ResultPoint> oldPoint = oldResultPoints[i]; Ref<ResultPoint> oldPoint = oldResultPoints[i];
newResultPoints.push_back(Ref<ResultPoint>(new ResultPoint(oldPoint->getX() + xOffset, oldPoint->getY() + yOffset))); newResultPoints->values().push_back(Ref<ResultPoint>(new ResultPoint(oldPoint->getX() + xOffset, oldPoint->getY() + yOffset)));
} }
return Ref<Result>(new Result(result->getText(), result->getRawBytes(), newResultPoints, result->getBarcodeFormat())); return Ref<Result>(new Result(result->getText(), result->getRawBytes(), newResultPoints, result->getBarcodeFormat()));
} }

View file

@ -36,10 +36,10 @@ std::vector<Ref<Result> > QRCodeMultiReader::decodeMultiple(Ref<BinaryBitmap> im
for (unsigned int i = 0; i < detectorResult.size(); i++) { for (unsigned int i = 0; i < detectorResult.size(); i++) {
try { try {
Ref<DecoderResult> decoderResult = getDecoder().decode(detectorResult[i]->getBits()); Ref<DecoderResult> decoderResult = getDecoder().decode(detectorResult[i]->getBits());
std::vector<Ref<ResultPoint> > points = detectorResult[i]->getPoints(); ArrayRef< Ref<ResultPoint> > points = detectorResult[i]->getPoints();
Ref<Result> result = Ref<Result>(new Result(decoderResult->getText(), Ref<Result> result = Ref<Result>(new Result(decoderResult->getText(),
decoderResult->getRawBytes(), decoderResult->getRawBytes(),
points, BarcodeFormat_QR_CODE)); points, BarcodeFormat::QR_CODE));
// result->putMetadata(ResultMetadataType.BYTE_SEGMENTS, decoderResult->getByteSegments()); // result->putMetadata(ResultMetadataType.BYTE_SEGMENTS, decoderResult->getByteSegments());
// result->putMetadata(ResultMetadataType.ERROR_CORRECTION_LEVEL, decoderResult->getECLevel().toString()); // result->putMetadata(ResultMetadataType.ERROR_CORRECTION_LEVEL, decoderResult->getECLevel().toString());
results.push_back(result); results.push_back(result);

View file

@ -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 <zxing/oned/OneDResultPoint.h>
#include <zxing/common/Array.h>
#include <zxing/ReaderException.h>
#include <zxing/NotFoundException.h>
#include <zxing/FormatException.h>
#include <zxing/ChecksumException.h>
#include <math.h>
#include <string.h>
#include <sstream>
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<Result> CodaBarReader::decodeRow(int rowNumber,
Ref<BitArray> 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<ResultPoint> > resultPoints(2);
resultPoints[0] =
Ref<OneDResultPoint>(new OneDResultPoint(left, (float) rowNumber));
resultPoints[1] =
Ref<OneDResultPoint>(new OneDResultPoint(right, (float) rowNumber));
return Ref<Result>(
new Result(
Ref<String>(new String(decodeRowResult)),
ArrayRef<char>(),
resultPoints,
BarcodeFormat::CODABAR)
);
}
void CodaBarReader::validatePattern(int start) {
// First, sum up the total size of our four categories of stripe sizes;
vector<int> sizes (4, 0);
vector<int> 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<int> maxes (4, 0);
vector<int> 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<BitArray> 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<int> maxes (2, 0);
vector<int> mins (2, std::numeric_limits<int>::max());
vector<int> 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;
}

View file

@ -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 <zxing/oned/OneDReader.h>
#include <zxing/common/BitArray.h>
#include <zxing/Result.h>
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<int> counters;
int counterLength;
public:
CodaBarReader();
Ref<Result> decodeRow(int rowNumber, Ref<BitArray> row);
void validatePattern(int start);
private:
void setCounters(Ref<BitArray> row);
void counterAppend(int e);
int findStartPattern();
static bool arrayContains(char const array[], char key);
int toNarrowWidePattern(int position);
};
#endif

View file

@ -19,471 +19,457 @@
#include <zxing/oned/OneDResultPoint.h> #include <zxing/oned/OneDResultPoint.h>
#include <zxing/common/Array.h> #include <zxing/common/Array.h>
#include <zxing/ReaderException.h> #include <zxing/ReaderException.h>
#include <zxing/NotFoundException.h>
#include <zxing/FormatException.h>
#include <zxing/ChecksumException.h>
#include <math.h> #include <math.h>
#include <string.h> #include <string.h>
#include <sstream> #include <sstream>
namespace zxing { using std::vector;
namespace oned { 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 Code128Reader::MAX_AVG_VARIANCE = int(PATTERN_MATCH_RESULT_SCALE_FACTOR * 250/1000);
const int countersLength = 6; const int Code128Reader::MAX_INDIVIDUAL_VARIANCE = int(PATTERN_MATCH_RESULT_SCALE_FACTOR * 700/1000);
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}
};
namespace {
Code128Reader::Code128Reader(){ const int CODE_SHIFT = 98;
}
const int CODE_CODE_C = 99;
int* Code128Reader::findStartPattern(Ref<BitArray> row){ const int CODE_CODE_B = 100;
int width = row->getSize(); const int CODE_CODE_A = 101;
int rowOffset = 0;
while (rowOffset < width) { const int CODE_FNC_1 = 102;
if (row->get(rowOffset)) { const int CODE_FNC_2 = 97;
break; const int CODE_FNC_3 = 96;
} const int CODE_FNC_4_A = 101;
rowOffset++; const int CODE_FNC_4_B = 100;
}
const int CODE_START_A = 103;
int counterPosition = 0; const int CODE_START_B = 104;
int counters[countersLength] = {0,0,0,0,0,0}; const int CODE_START_C = 105;
int patternStart = rowOffset; const int CODE_STOP = 106;
bool isWhite = false;
int patternLength = sizeof(counters) / sizeof(int); const int CODE_PATTERNS_LENGTH = 107;
const int CODE_PATTERNS[CODE_PATTERNS_LENGTH][6] = {
for (int i = rowOffset; i < width; i++) { {2, 1, 2, 2, 2, 2}, /* 0 */
bool pixel = row->get(i); {2, 2, 2, 1, 2, 2},
if (pixel ^ isWhite) { {2, 2, 2, 2, 2, 1},
counters[counterPosition]++; {1, 2, 1, 2, 2, 3},
} else { {1, 2, 1, 3, 2, 2},
if (counterPosition == patternLength - 1) { {1, 3, 1, 2, 2, 2}, /* 5 */
unsigned int bestVariance = MAX_AVG_VARIANCE; {1, 2, 2, 2, 1, 3},
int bestMatch = -1; {1, 2, 2, 3, 1, 2},
for (int startCode = CODE_START_A; startCode <= CODE_START_C; startCode++) { {1, 3, 2, 2, 1, 2},
unsigned int variance = patternMatchVariance(counters, sizeof(counters) / sizeof(int), {2, 2, 1, 2, 1, 3},
CODE_PATTERNS[startCode], MAX_INDIVIDUAL_VARIANCE); {2, 2, 1, 3, 1, 2}, /* 10 */
if (variance < bestVariance) { {2, 3, 1, 2, 1, 2},
bestVariance = variance; {1, 1, 2, 2, 3, 2},
bestMatch = startCode; {1, 2, 2, 1, 3, 2},
} {1, 2, 2, 2, 3, 1},
} {1, 1, 3, 2, 2, 2}, /* 15 */
// Look for whitespace before start pattern, >= 50% of width of start pattern {1, 2, 3, 1, 2, 2},
if (bestMatch >= 0 && {1, 2, 3, 2, 2, 1},
row->isRange(std::max(0, patternStart - (i - patternStart) / 2), patternStart, {2, 2, 3, 2, 1, 1},
false)) { {2, 2, 1, 1, 3, 2},
int* resultValue = new int[3]; {2, 2, 1, 2, 3, 1}, /* 20 */
resultValue[0] = patternStart; {2, 1, 3, 2, 1, 2},
resultValue[1] = i; {2, 2, 3, 1, 1, 2},
resultValue[2] = bestMatch; {3, 1, 2, 1, 3, 1},
return resultValue; {3, 1, 1, 2, 2, 2},
} {3, 2, 1, 1, 2, 2}, /* 25 */
patternStart += counters[0] + counters[1]; {3, 2, 1, 2, 2, 1},
for (int y = 2; y < patternLength; y++) { {3, 1, 2, 2, 1, 2},
counters[y - 2] = counters[y]; {3, 2, 2, 1, 1, 2},
} {3, 2, 2, 2, 1, 1},
counters[patternLength - 2] = 0; {2, 1, 2, 1, 2, 3}, /* 30 */
counters[patternLength - 1] = 0; {2, 1, 2, 3, 2, 1},
counterPosition--; {2, 3, 2, 1, 2, 1},
} else { {1, 1, 1, 3, 2, 3},
counterPosition++; {1, 3, 1, 1, 2, 3},
} {1, 3, 1, 3, 2, 1}, /* 35 */
counters[counterPosition] = 1; {1, 1, 2, 3, 1, 3},
isWhite = !isWhite; {1, 3, 2, 1, 1, 3},
} {1, 3, 2, 3, 1, 1},
} {2, 1, 1, 3, 1, 3},
throw ReaderException(""); {2, 3, 1, 1, 1, 3}, /* 40 */
} {2, 3, 1, 3, 1, 1},
{1, 1, 2, 1, 3, 3},
int Code128Reader::decodeCode(Ref<BitArray> row, int counters[], int countersCount, {1, 1, 2, 3, 3, 1},
int rowOffset) { {1, 3, 2, 1, 3, 1},
if (!recordPattern(row, rowOffset, counters, countersCount)) { {1, 1, 3, 1, 2, 3}, /* 45 */
throw ReaderException(""); {1, 1, 3, 3, 2, 1},
} {1, 3, 3, 1, 2, 1},
unsigned int bestVariance = MAX_AVG_VARIANCE; // worst variance we'll accept {3, 1, 3, 1, 2, 1},
int bestMatch = -1; {2, 1, 1, 3, 3, 1},
for (int d = 0; d < CODE_PATTERNS_LENGTH; d++) { {2, 3, 1, 1, 3, 1}, /* 50 */
int pattern[countersLength]; {2, 1, 3, 1, 1, 3},
{2, 1, 3, 3, 1, 1},
for(int ind = 0; ind< countersLength; ind++){ {2, 1, 3, 1, 3, 1},
pattern[ind] = CODE_PATTERNS[d][ind]; {3, 1, 1, 1, 2, 3},
} {3, 1, 1, 3, 2, 1}, /* 55 */
// memcpy(pattern, CODE_PATTERNS[d], countersLength); {3, 3, 1, 1, 2, 1},
unsigned int variance = patternMatchVariance(counters, countersCount, pattern, {3, 1, 2, 1, 1, 3},
MAX_INDIVIDUAL_VARIANCE); {3, 1, 2, 3, 1, 1},
if (variance < bestVariance) { {3, 3, 2, 1, 1, 1},
bestVariance = variance; {3, 1, 4, 1, 1, 1}, /* 60 */
bestMatch = d; {2, 2, 1, 4, 1, 1},
} {4, 3, 1, 1, 1, 1},
} {1, 1, 1, 2, 2, 4},
// TODO We're overlooking the fact that the STOP pattern has 7 values, not 6. {1, 1, 1, 4, 2, 2},
if (bestMatch >= 0) { {1, 2, 1, 1, 2, 4}, /* 65 */
return bestMatch; {1, 2, 1, 4, 2, 1},
} else { {1, 4, 1, 1, 2, 2},
throw ReaderException(""); {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},
Ref<Result> Code128Reader::decodeRow(int rowNumber, Ref<BitArray> row) { {1, 2, 2, 4, 1, 1},
int* startPatternInfo = NULL; {1, 4, 2, 1, 1, 2},
try { {1, 4, 2, 2, 1, 1},
startPatternInfo = findStartPattern(row); {2, 4, 1, 2, 1, 1}, /* 75 */
int startCode = startPatternInfo[2]; {2, 2, 1, 1, 1, 4},
int codeSet; {4, 1, 3, 1, 1, 1},
switch (startCode) { {2, 4, 1, 1, 1, 2},
case CODE_START_A: {1, 3, 4, 1, 1, 1},
codeSet = CODE_CODE_A; {1, 1, 1, 2, 4, 2}, /* 80 */
break; {1, 2, 1, 1, 4, 2},
case CODE_START_B: {1, 2, 1, 2, 4, 1},
codeSet = CODE_CODE_B; {1, 1, 4, 2, 1, 2},
break; {1, 2, 4, 1, 1, 2},
case CODE_START_C: {1, 2, 4, 2, 1, 1}, /* 85 */
codeSet = CODE_CODE_C; {4, 1, 1, 2, 1, 2},
break; {4, 2, 1, 1, 1, 2},
default: {4, 2, 1, 2, 1, 1},
throw ReaderException(""); {2, 1, 2, 1, 4, 1},
} {2, 1, 4, 1, 2, 1}, /* 90 */
{4, 1, 2, 1, 2, 1},
bool done = false; {1, 1, 1, 1, 4, 3},
bool isNextShifted = false; {1, 1, 1, 3, 4, 1},
{1, 3, 1, 1, 4, 1},
std::string tmpResultString; {1, 1, 4, 1, 1, 3}, /* 95 */
std::stringstream tmpResultSStr; // used if its Code 128C {1, 1, 4, 3, 1, 1},
{4, 1, 1, 1, 1, 3},
int lastStart = startPatternInfo[0]; {4, 1, 1, 3, 1, 1},
int nextStart = startPatternInfo[1]; {1, 1, 3, 1, 4, 1},
int counters[countersLength] = {0,0,0,0,0,0}; {1, 1, 4, 1, 3, 1}, /* 100 */
{3, 1, 1, 1, 4, 1},
int lastCode = 0; {4, 1, 1, 1, 3, 1},
int code = 0; {2, 1, 1, 4, 1, 2},
int checksumTotal = startCode; {2, 1, 1, 2, 1, 4},
int multiplier = 0; {2, 1, 1, 2, 3, 2}, /* 105 */
bool lastCharacterWasPrintable = true; {2, 3, 3, 1, 1, 1}
};
while (!done) { }
bool unshift = isNextShifted;
isNextShifted = false; Code128Reader::Code128Reader(){}
// Save off last code vector<int> Code128Reader::findStartPattern(Ref<BitArray> row){
lastCode = code; int width = row->getSize();
int rowOffset = row->getNextSet(0);
// Decode another code from image
try { int counterPosition = 0;
code = decodeCode(row, counters, sizeof(counters)/sizeof(int), nextStart); vector<int> counters (6, 0);
} catch (ReaderException const& re) { int patternStart = rowOffset;
throw re; bool isWhite = false;
} int patternLength = counters.size();
// Remember whether the last code was printable or not (excluding CODE_STOP) for (int i = rowOffset; i < width; i++) {
if (code != CODE_STOP) { if (row->get(i) ^ isWhite) {
lastCharacterWasPrintable = true; counters[counterPosition]++;
} } else {
if (counterPosition == patternLength - 1) {
// Add to checksum computation (if not CODE_STOP of course) int bestVariance = MAX_AVG_VARIANCE;
if (code != CODE_STOP) { int bestMatch = -1;
multiplier++; for (int startCode = CODE_START_A; startCode <= CODE_START_C; startCode++) {
checksumTotal += multiplier * code; int variance = patternMatchVariance(counters, CODE_PATTERNS[startCode], MAX_INDIVIDUAL_VARIANCE);
} if (variance < bestVariance) {
bestVariance = variance;
// Advance to where the next code will to start bestMatch = startCode;
lastStart = nextStart; }
int _countersLength = sizeof(counters) / sizeof(int); }
for (int i = 0; i < _countersLength; i++) { // Look for whitespace before start pattern, >= 50% of width of start pattern
nextStart += counters[i]; if (bestMatch >= 0 &&
} row->isRange(std::max(0, patternStart - (i - patternStart) / 2), patternStart, false)) {
vector<int> resultValue (3, 0);
// Take care of illegal start codes resultValue[0] = patternStart;
switch (code) { resultValue[1] = i;
case CODE_START_A: resultValue[2] = bestMatch;
case CODE_START_B: return resultValue;
case CODE_START_C: }
throw ReaderException(""); patternStart += counters[0] + counters[1];
} for (int y = 2; y < patternLength; y++) {
counters[y - 2] = counters[y];
switch (codeSet) { }
counters[patternLength - 2] = 0;
case CODE_CODE_A: counters[patternLength - 1] = 0;
if (code < 64) { counterPosition--;
tmpResultString.append(1, (char) (' ' + code)); } else {
} else if (code < 96) { counterPosition++;
tmpResultString.append(1, (char) (code - 64)); }
} else { counters[counterPosition] = 1;
// Don't let CODE_STOP, which always appears, affect whether whether we think the isWhite = !isWhite;
// last code was printable or not. }
if (code != CODE_STOP) { }
lastCharacterWasPrintable = false; throw NotFoundException();
} }
switch (code) {
case CODE_FNC_1: int Code128Reader::decodeCode(Ref<BitArray> row, vector<int>& counters, int rowOffset) {
case CODE_FNC_2: recordPattern(row, rowOffset, counters);
case CODE_FNC_3: int bestVariance = MAX_AVG_VARIANCE; // worst variance we'll accept
case CODE_FNC_4_A: int bestMatch = -1;
// do nothing? for (int d = 0; d < CODE_PATTERNS_LENGTH; d++) {
break; int const* const pattern = CODE_PATTERNS[d];
case CODE_SHIFT: int variance = patternMatchVariance(counters, pattern, MAX_INDIVIDUAL_VARIANCE);
isNextShifted = true; if (variance < bestVariance) {
codeSet = CODE_CODE_B; bestVariance = variance;
break; bestMatch = d;
case CODE_CODE_B: }
codeSet = CODE_CODE_B; }
break; // TODO We're overlooking the fact that the STOP pattern has 7 values, not 6.
case CODE_CODE_C: if (bestMatch >= 0) {
codeSet = CODE_CODE_C; return bestMatch;
break; } else {
case CODE_STOP: throw NotFoundException();
done = true; }
break; }
}
} Ref<Result> Code128Reader::decodeRow(int rowNumber, Ref<BitArray> row) {
break; vector<int> startPatternInfo (findStartPattern(row));
case CODE_CODE_B: int startCode = startPatternInfo[2];
if (code < 96) { int codeSet;
tmpResultString.append(1, (char) (' ' + code)); switch (startCode) {
} else { case CODE_START_A:
if (code != CODE_STOP) { codeSet = CODE_CODE_A;
lastCharacterWasPrintable = false; break;
} case CODE_START_B:
switch (code) { codeSet = CODE_CODE_B;
case CODE_FNC_1: break;
case CODE_FNC_2: case CODE_START_C:
case CODE_FNC_3: codeSet = CODE_CODE_C;
case CODE_FNC_4_B: break;
// do nothing? default:
break; throw FormatException();
case CODE_SHIFT: }
isNextShifted = true;
codeSet = CODE_CODE_C; bool done = false;
break; bool isNextShifted = false;
case CODE_CODE_A:
codeSet = CODE_CODE_A; string result;
break; vector<char> rawCodes(20, 0);
case CODE_CODE_C:
codeSet = CODE_CODE_C; int lastStart = startPatternInfo[0];
break; int nextStart = startPatternInfo[1];
case CODE_STOP: vector<int> counters (6, 0);
done = true;
break; int lastCode = 0;
} int code = 0;
} int checksumTotal = startCode;
break; int multiplier = 0;
case CODE_CODE_C: bool lastCharacterWasPrintable = true;
tmpResultSStr.str(std::string());
// the code read in this case is the number encoded directly std::ostringstream oss;
if (code < 100) {
if (code < 10) { while (!done) {
tmpResultSStr << '0';
} bool unshift = isNextShifted;
tmpResultSStr << code; isNextShifted = false;
tmpResultString.append(tmpResultSStr.str());
} else { // Save off last code
if (code != CODE_STOP) { lastCode = code;
lastCharacterWasPrintable = false;
} code = decodeCode(row, counters, nextStart);
switch (code) {
case CODE_FNC_1: // Remember whether the last code was printable or not (excluding CODE_STOP)
// do nothing? if (code != CODE_STOP) {
break; lastCharacterWasPrintable = true;
case CODE_CODE_A: }
codeSet = CODE_CODE_A;
break; // Add to checksum computation (if not CODE_STOP of course)
case CODE_CODE_B: if (code != CODE_STOP) {
codeSet = CODE_CODE_B; multiplier++;
break; checksumTotal += multiplier * code;
case CODE_STOP: }
done = true;
break; // Advance to where the next code will to start
} lastStart = nextStart;
} for (int i = 0, e = counters.size(); i < e; i++) {
break; nextStart += counters[i];
} }
// Unshift back to another code set if we were shifted // Take care of illegal start codes
if (unshift) { switch (code) {
switch (codeSet) { case CODE_START_A:
case CODE_CODE_A: case CODE_START_B:
codeSet = CODE_CODE_C; case CODE_START_C:
break; throw FormatException();
case CODE_CODE_B: }
codeSet = CODE_CODE_A;
break; switch (codeSet) {
case CODE_CODE_C:
codeSet = CODE_CODE_B; case CODE_CODE_A:
break; 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
// Check for ample whitespace following pattern, but, to do this we first need to remember that // last code was printable or not.
// we fudged decoding CODE_STOP since it actually has 7 bars, not 6. There is a black bar left if (code != CODE_STOP) {
// to read off. Would be slightly better to properly read. Here we just skip it: lastCharacterWasPrintable = false;
int width = row->getSize(); }
while (nextStart < width && row->get(nextStart)) { switch (code) {
nextStart++; case CODE_FNC_1:
} case CODE_FNC_2:
if (!row->isRange(nextStart, case CODE_FNC_3:
std::min(width, nextStart + (nextStart - lastStart) / 2), case CODE_FNC_4_A:
false)) { // do nothing?
throw ReaderException(""); break;
} case CODE_SHIFT:
isNextShifted = true;
// Pull out from sum the value of the penultimate check code codeSet = CODE_CODE_B;
checksumTotal -= multiplier * lastCode; break;
// lastCode is the checksum then: case CODE_CODE_B:
if (checksumTotal % 103 != lastCode) { codeSet = CODE_CODE_B;
throw ReaderException(""); break;
} case CODE_CODE_C:
codeSet = CODE_CODE_C;
// Need to pull out the check digits from string break;
int resultLength = tmpResultString.length(); case CODE_STOP:
// Only bother if the result had at least one character, and if the checksum digit happened to done = true;
// be a printable character. If it was just interpreted as a control code, nothing to remove. break;
if (resultLength > 0 && lastCharacterWasPrintable) { }
if (codeSet == CODE_CODE_C) { }
tmpResultString.erase(resultLength - 2, resultLength); break;
} else { case CODE_CODE_B:
tmpResultString.erase(resultLength - 1, resultLength); if (code < 96) {
} result.append(1, (char) (' ' + code));
} } else {
if (code != CODE_STOP) {
Ref<String> resultString(new String(tmpResultString)); lastCharacterWasPrintable = false;
if (tmpResultString.length() == 0) { }
// Almost surely a false positive switch (code) {
throw ReaderException(""); case CODE_FNC_1:
} case CODE_FNC_2:
case CODE_FNC_3:
float left = (float) (startPatternInfo[1] + startPatternInfo[0]) / 2.0f; case CODE_FNC_4_B:
float right = (float) (nextStart + lastStart) / 2.0f; // do nothing?
break;
std::vector< Ref<ResultPoint> > resultPoints(2); case CODE_SHIFT:
Ref<OneDResultPoint> resultPoint1(new OneDResultPoint(left, (float) rowNumber)); isNextShifted = true;
Ref<OneDResultPoint> resultPoint2(new OneDResultPoint(right, (float) rowNumber)); codeSet = CODE_CODE_A;
resultPoints[0] = resultPoint1; break;
resultPoints[1] = resultPoint2; case CODE_CODE_A:
codeSet = CODE_CODE_A;
delete [] startPatternInfo; break;
ArrayRef<unsigned char> resultBytes(1); case CODE_CODE_C:
return Ref<Result>(new Result(resultString, resultBytes, resultPoints, codeSet = CODE_CODE_C;
BarcodeFormat_CODE_128)); break;
} catch (ReaderException const& re) { case CODE_STOP:
delete [] startPatternInfo; done = true;
return Ref<Result>(); break;
} }
} }
break;
void Code128Reader::append(char* s, char c){ case CODE_CODE_C:
int len = strlen(s); if (code < 100) {
s[len] = c; if (code < 10) {
s[len + 1] = '\0'; result.append(1, '0');
} }
oss.clear();
Code128Reader::~Code128Reader(){ 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<char> rawBytes (rawCodesSize);
for (int i = 0; i < rawCodesSize; i++) {
rawBytes[i] = rawCodes[i];
}
ArrayRef< Ref<ResultPoint> > resultPoints(2);
resultPoints[0] =
Ref<OneDResultPoint>(new OneDResultPoint(left, (float) rowNumber));
resultPoints[1] =
Ref<OneDResultPoint>(new OneDResultPoint(right, (float) rowNumber));
return Ref<Result>(new Result(Ref<String>(new String(result)), rawBytes, resultPoints,
BarcodeFormat::CODE_128));
}
Code128Reader::~Code128Reader(){}
zxing::BarcodeFormat Code128Reader::getBarcodeFormat(){
return BarcodeFormat::CODE_128;
} }

View file

@ -23,38 +23,26 @@
namespace zxing { namespace zxing {
namespace oned { namespace oned {
class Code128Reader : public OneDReader { class Code128Reader;
}
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<BitArray> row);
static int decodeCode(Ref<BitArray> row, int counters[], int countersCount, int rowOffset);
void append(char* s, char c);
public:
Ref<Result> decodeRow(int rowNumber, Ref<BitArray> row);
Code128Reader();
~Code128Reader();
};
}
} }
class zxing::oned::Code128Reader : public OneDReader {
private:
static const int MAX_AVG_VARIANCE;
static const int MAX_INDIVIDUAL_VARIANCE;
static std::vector<int> findStartPattern(Ref<BitArray> row);
static int decodeCode(Ref<BitArray> row,
std::vector<int>& counters,
int rowOffset);
public:
Ref<Result> decodeRow(int rowNumber, Ref<BitArray> row);
Code128Reader();
~Code128Reader();
BarcodeFormat getBarcodeFormat();
};
#endif #endif

View file

@ -19,14 +19,21 @@
#include <zxing/oned/OneDResultPoint.h> #include <zxing/oned/OneDResultPoint.h>
#include <zxing/common/Array.h> #include <zxing/common/Array.h>
#include <zxing/ReaderException.h> #include <zxing/ReaderException.h>
#include <zxing/NotFoundException.h>
#include <zxing/ChecksumException.h>
#include <math.h> #include <math.h>
#include <limits.h> #include <limits.h>
namespace zxing { using std::vector;
namespace oned { using zxing::Ref;
using zxing::Result;
static const char* ALPHABET = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ-. *$/+%"; 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 * 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. * and narrow, with 1s representing "wide" and 0s representing narrow.
*/ */
const int CHARACTER_ENCODINGS_LEN = 44; 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 0x034, 0x121, 0x061, 0x160, 0x031, 0x130, 0x070, 0x025, 0x124, 0x064, // 0-9
0x109, 0x049, 0x148, 0x019, 0x118, 0x058, 0x00D, 0x10C, 0x04C, 0x01C, // A-J 0x109, 0x049, 0x148, 0x019, 0x118, 0x058, 0x00D, 0x10C, 0x04C, 0x01C, // A-J
0x103, 0x043, 0x142, 0x013, 0x112, 0x052, 0x007, 0x106, 0x046, 0x016, // K-T 0x103, 0x043, 0x142, 0x013, 0x112, 0x052, 0x007, 0x106, 0x046, 0x016, // K-T
@ -43,305 +50,269 @@ namespace oned {
0x0A8, 0x0A2, 0x08A, 0x02A // $-% 0x0A8, 0x0A2, 0x08A, 0x02A // $-%
}; };
static int ASTERISK_ENCODING = 0x094; int ASTERISK_ENCODING = 0x094;
static const char* ALPHABET_STRING = const char* ALPHABET_STRING =
"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ-. *$/+%"; "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) {
}
/** Code39Reader::Code39Reader(bool usingCheckDigit_, bool extendedMode_) :
* Creates a reader that assumes all encoded data is data, and does not treat alphabet_string(ALPHABET_STRING),
* the final character as a check digit. It will not decoded "extended usingCheckDigit(usingCheckDigit_),
* Code 39" sequences. extendedMode(extendedMode_) {
*/
Code39Reader::Code39Reader() : alphabet_string(ALPHABET_STRING),
usingCheckDigit(false),
extendedMode(false) {
} }
/** Ref<Result> Code39Reader::decodeRow(int rowNumber, Ref<BitArray> row) {
* Creates a reader that can be configured to check the last character as a vector<int> counters (9, 0);
* check digit. It will not decoded "extended Code 39" sequences. vector<int> start (findAsteriskPattern(row, counters));
* // Read off white space
* @param usingCheckDigit if true, treat the last data character as a check int nextStart = row->getNextSet(start[1]);
* digit, not data, and verify that the checksum passes. int end = row->getSize();
*/
Code39Reader::Code39Reader(bool usingCheckDigit_) :
alphabet_string(ALPHABET_STRING),
usingCheckDigit(usingCheckDigit_),
extendedMode(false) {
}
std::string result;
Code39Reader::Code39Reader(bool usingCheckDigit_, bool extendedMode_) : char decodedChar;
alphabet_string(ALPHABET_STRING), int lastStart;
usingCheckDigit(usingCheckDigit_), do {
extendedMode(extendedMode_) { recordPattern(row, nextStart, counters);
} int pattern = toNarrowWidePattern(counters);
if (pattern < 0) {
Ref<Result> Code39Reader::decodeRow(int rowNumber, Ref<BitArray> row) { throw NotFoundException();;
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<String> 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<ResultPoint> > resultPoints(2);
Ref<OneDResultPoint> resultPoint1(
new OneDResultPoint(left, (float) rowNumber));
Ref<OneDResultPoint> resultPoint2(
new OneDResultPoint(right, (float) rowNumber));
resultPoints[0] = resultPoint1;
resultPoints[1] = resultPoint2;
ArrayRef<unsigned char> resultBytes(1);
Ref<Result> res(new Result(
resultString, resultBytes, resultPoints, BarcodeFormat_CODE_39));
delete [] start;
return res;
} catch (ReaderException const& re) {
delete [] start;
return Ref<Result>();
} }
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<BitArray> row){ if (usingCheckDigit) {
int width = row->getSize(); int max = result.length() - 1;
int rowOffset = 0; int total = 0;
while (rowOffset < width) { for (int i = 0; i < max; i++) {
if (row->get(rowOffset)) { total += alphabet_string.find_first_of(result[i], 0);
break;
}
rowOffset++;
} }
if (result[max] != ALPHABET[total % 43]) {
int counterPosition = 0; throw ChecksumException();
const int countersLen = 9;
int counters[countersLen];
for (int i = 0; i < countersLen; i++) {
counters[i] = 0;
} }
int patternStart = rowOffset; result.resize(max);
bool isWhite = false; }
int patternLength = countersLen;
if (result.length() == 0) {
// Almost false positive
throw NotFoundException();
}
Ref<String> resultString;
if (extendedMode) {
resultString = decodeExtended(result);
} else {
resultString = Ref<String>(new String(result));
}
for (int i = rowOffset; i < width; i++) { float left = (float) (start[1] + start[0]) / 2.0f;
bool pixel = row->get(i); float right = (float) (nextStart + lastStart) / 2.0f;
if (pixel ^ isWhite) {
counters[counterPosition]++; ArrayRef< Ref<ResultPoint> > resultPoints (2);
resultPoints[0] =
Ref<OneDResultPoint>(new OneDResultPoint(left, (float) rowNumber));
resultPoints[1] =
Ref<OneDResultPoint>(new OneDResultPoint(right, (float) rowNumber));
return Ref<Result>(
new Result(resultString, ArrayRef<char>(), resultPoints, BarcodeFormat::CODE_39)
);
}
vector<int> Code39Reader::findAsteriskPattern(Ref<BitArray> row,
vector<int>& 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<int> 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 { } else {
if (counterPosition == patternLength - 1) { counterPosition++;
// Look for whitespace before start pattern, >= 50% of width of }
// start pattern. counters[counterPosition] = 1;
if (toNarrowWidePattern(counters, countersLen) == ASTERISK_ENCODING && isWhite = !isWhite;
row->isRange(std::max(0, patternStart - ((i - patternStart) >> 1)), patternStart, false)) { }
int* resultValue = new int[2]; }
resultValue[0] = patternStart; throw NotFoundException();
resultValue[1] = i; }
return resultValue;
} // For efficiency, returns -1 on failure. Not throwing here saved as many as
patternStart += counters[0] + counters[1]; // 700 exceptions per image when using some of our blackbox images.
for (int y = 2; y < patternLength; y++) { int Code39Reader::toNarrowWidePattern(vector<int>& counters){
counters[y - 2] = counters[y]; int numCounters = counters.size();
} int maxNarrowCounter = 0;
counters[patternLength - 2] = 0; int wideCounters;
counters[patternLength - 1] = 0; do {
counterPosition--; int minCounter = INT_MAX;
} else { for (int i = 0; i < numCounters; i++) {
counterPosition++; int counter = counters[i];
} if (counter < minCounter && counter > maxNarrowCounter) {
counters[counterPosition] = 1; minCounter = counter;
isWhite = !isWhite;
} }
} }
throw ReaderException(""); maxNarrowCounter = minCounter;
} wideCounters = 0;
int totalWideCountersWidth = 0;
// For efficiency, returns -1 on failure. Not throwing here saved as many as int pattern = 0;
// 700 exceptions per image when using some of our blackbox images. for (int i = 0; i < numCounters; i++) {
int Code39Reader::toNarrowWidePattern(int counters[], int countersLen){ int counter = counters[i];
int numCounters = countersLen; if (counters[i] > maxNarrowCounter) {
int maxNarrowCounter = 0; pattern |= 1 << (numCounters - 1 - i);
int wideCounters; wideCounters++;
do { totalWideCountersWidth += counter;
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; if (wideCounters == 3) {
int totalWideCountersWidth = 0; // Found 3 wide counters, but are they close enough in width?
int pattern = 0; // We can perform a cheap, conservative check to see if any individual
for (int i = 0; i < numCounters; i++) { // counter is more than 1.5 times the average:
for (int i = 0; i < numCounters && wideCounters > 0; i++) {
int counter = counters[i]; int counter = counters[i];
if (counters[i] > maxNarrowCounter) { if (counters[i] > maxNarrowCounter) {
pattern |= 1 << (numCounters - 1 - i); wideCounters--;
wideCounters++; // totalWideCountersWidth = 3 * average, so this checks if
totalWideCountersWidth += counter; // counter >= 3/2 * average.
} if ((counter << 1) >= totalWideCountersWidth) {
} return -1;
if (wideCounters == 3) {
// Found 3 wide counters, but are they close enough in width?
// We can perform a cheap, conservative check to see if any individual
// counter is more than 1.5 times the average:
for (int i = 0; i < numCounters && wideCounters > 0; i++) {
int counter = counters[i];
if (counters[i] > maxNarrowCounter) {
wideCounters--;
// totalWideCountersWidth = 3 * average, so this checks if
// counter >= 3/2 * average.
if ((counter << 1) >= totalWideCountersWidth) {
return -1;
}
} }
} }
return pattern;
}
} while (wideCounters > 3);
return -1;
}
char Code39Reader::patternToChar(int pattern){
for (int i = 0; i < CHARACTER_ENCODINGS_LEN; i++) {
if (CHARACTER_ENCODINGS[i] == pattern) {
return ALPHABET[i];
} }
return pattern;
} }
throw ReaderException(""); } while (wideCounters > 3);
} return -1;
}
Ref<String> Code39Reader::decodeExtended(std::string encoded){ char Code39Reader::patternToChar(int pattern){
int length = encoded.length(); for (int i = 0; i < CHARACTER_ENCODINGS_LEN; i++) {
std::string tmpDecoded; if (CHARACTER_ENCODINGS[i] == pattern) {
for (int i = 0; i < length; i++) { return ALPHABET[i];
char c = encoded[i]; }
if (c == '+' || c == '$' || c == '%' || c == '/') { }
char next = encoded[i + 1]; throw ReaderException("");
char decodedChar = '\0'; }
switch (c) {
case '+': Ref<String> Code39Reader::decodeExtended(std::string encoded){
// +A to +Z map to a to z int length = encoded.length();
if (next >= 'A' && next <= 'Z') { std::string tmpDecoded;
decodedChar = (char) (next + 32); for (int i = 0; i < length; i++) {
} else { char c = encoded[i];
throw ReaderException(""); if (c == '+' || c == '$' || c == '%' || c == '/') {
} char next = encoded[i + 1];
break; char decodedChar = '\0';
case '$': switch (c) {
// $A to $Z map to control codes SH to SB case '+':
if (next >= 'A' && next <= 'Z') { // +A to +Z map to a to z
decodedChar = (char) (next - 64); if (next >= 'A' && next <= 'Z') {
} else { decodedChar = (char) (next + 32);
throw ReaderException(""); } 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); break;
// bump up i again since we read two characters case '$':
i++; // $A to $Z map to control codes SH to SB
} else { if (next >= 'A' && next <= 'Z') {
tmpDecoded.append(1, c); decodedChar = (char) (next - 64);
} else {
throw ReaderException("");
}
break;
case '%':
// %A to %E map to control codes ESC to US
if (next >= 'A' && next <= 'E') {
decodedChar = (char) (next - 38);
} else if (next >= 'F' && next <= 'W') {
decodedChar = (char) (next - 11);
} else {
throw ReaderException("");
}
break;
case '/':
// /A to /O map to ! to , and /Z maps to :
if (next >= 'A' && next <= 'O') {
decodedChar = (char) (next - 32);
} else if (next == 'Z') {
decodedChar = ':';
} else {
throw ReaderException("");
}
break;
} }
tmpDecoded.append(1, decodedChar);
// bump up i again since we read two characters
i++;
} else {
tmpDecoded.append(1, c);
} }
Ref<String> decoded(new String(tmpDecoded));
return decoded;
} }
} // namespace oned Ref<String> decoded(new String(tmpDecoded));
} // namespace zxing return decoded;
}

View file

@ -1,3 +1,4 @@
// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*-
#ifndef __CODE_39_READER_H__ #ifndef __CODE_39_READER_H__
#define __CODE_39_READER_H__ #define __CODE_39_READER_H__
/* /*
@ -24,35 +25,37 @@
#include <zxing/Result.h> #include <zxing/Result.h>
namespace zxing { namespace zxing {
namespace oned { namespace oned {
class Code39Reader;
/** }
* <p>Decodes Code 39 barcodes. This does not support "Full ASCII Code 39" yet.</p>
* 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<BitArray> row); //throws ReaderException
static int toNarrowWidePattern(int counters[], int countersLen);
static char patternToChar(int pattern); //throws ReaderException
static Ref<String> decodeExtended(std::string encoded); //throws ReaderException
void append(char* s, char c);
public:
Code39Reader();
Code39Reader(bool usingCheckDigit_);
Code39Reader(bool usingCheckDigit_, bool extendedMode_);
Ref<Result> decodeRow(int rowNumber, Ref<BitArray> row);
};
}
} }
/**
* <p>Decodes Code 39 barcodes. This does not support "Full ASCII Code 39" yet.</p>
* 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<int> findAsteriskPattern(Ref<BitArray> row,
std::vector<int>& counters);
static int toNarrowWidePattern(std::vector<int>& counters);
static char patternToChar(int pattern);
static Ref<String> decodeExtended(std::string encoded);
void append(char* s, char c);
public:
Code39Reader();
Code39Reader(bool usingCheckDigit_);
Code39Reader(bool usingCheckDigit_, bool extendedMode_);
Ref<Result> decodeRow(int rowNumber, Ref<BitArray> row);
};
#endif #endif

View file

@ -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 <zxing/oned/OneDResultPoint.h>
#include <zxing/common/Array.h>
#include <zxing/ReaderException.h>
#include <zxing/FormatException.h>
#include <zxing/NotFoundException.h>
#include <zxing/ChecksumException.h>
#include <math.h>
#include <limits.h>
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<Result> Code93Reader::decodeRow(int rowNumber, Ref<BitArray> row) {
Range start (findAsteriskPattern(row));
// Read off white space
int nextStart = row->getNextSet(start[1]);
int end = row->getSize();
string result;
vector<int> 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<String> resultString = decodeExtended(result);
float left = (float) (start[1] + start[0]) / 2.0f;
float right = (float) (nextStart + lastStart) / 2.0f;
ArrayRef< Ref<ResultPoint> > resultPoints (2);
resultPoints[0] =
Ref<OneDResultPoint>(new OneDResultPoint(left, (float) rowNumber));
resultPoints[1] =
Ref<OneDResultPoint>(new OneDResultPoint(right, (float) rowNumber));
return Ref<Result>(new Result(
resultString,
ArrayRef<char>(),
resultPoints,
BarcodeFormat::CODE_93));
}
Code93Reader::Range Code93Reader::findAsteriskPattern(Ref<BitArray> row) {
int width = row->getSize();
int rowOffset = row->getNextSet(0);
int counterPosition = 0;
vector<int> 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<int>& counters) {
int max = counters.size();
int sum = 0;
for(int i=0, e=counters.size(); i<e; ++i) {
sum += counters[i];
}
int pattern = 0;
for (int i = 0; i < max; i++) {
int scaledShifted = (counters[i] << INTEGER_MATH_SHIFT) * 9 / sum;
int scaledUnshifted = scaledShifted >> 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<String> 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<String>(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();
}
}

View file

@ -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 <zxing/oned/OneDReader.h>
#include <zxing/common/BitArray.h>
#include <zxing/Result.h>
namespace zxing {
namespace oned {
class Code93Reader;
}
}
/**
* <p>Decodes Code 93 barcodes. This does not support "Full ASCII Code 93" yet.</p>
* Ported form Java (author Sean Owen)
* @author Lukasz Warchol
*/
class zxing::oned::Code93Reader : public OneDReader {
public:
Ref<Result> decodeRow(int rowNumber, Ref<BitArray> row);
private:
static Range findAsteriskPattern(Ref<BitArray> row);
static int toPattern(std::vector<int>& counters);
static char patternToChar(int pattern);
static Ref<String> decodeExtended(std::string const& encoded);
static void checkChecksums(std::string const& result);
static void checkOneChecksum(std::string const& result,
int checkPosition,
int weightMax);
};
#endif

View file

@ -16,79 +16,76 @@
*/ */
#include "EAN13Reader.h" #include "EAN13Reader.h"
#include <zxing/ReaderException.h> #include <zxing/NotFoundException.h>
namespace zxing { using std::vector;
namespace oned { using zxing::Ref;
using zxing::BitArray;
using zxing::oned::EAN13Reader;
static const int FIRST_DIGIT_ENCODINGS[10] = { namespace {
0x00, 0x0B, 0x0D, 0xE, 0x13, 0x19, 0x1C, 0x15, 0x16, 0x1A 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<BitArray> row, int startGuardBegin, int startGuardEnd, int EAN13Reader::decodeMiddle(Ref<BitArray> row,
std::string& resultString) { Range const& startRange,
(void)startGuardBegin; std::string& resultString) {
const int countersLen = 4; if (false) {
int counters[countersLen] = { 0, 0, 0, 0 }; std::cerr << "ba "
<< startRange[0] << " "
<< startRange[1] << " "
<< *row << std::endl;
}
vector<int>& counters (decodeMiddleCounters);
counters.clear();
counters.resize(4);
int end = row->getSize();
int rowOffset = startRange[1];
int end = row->getSize(); int lgPatternFound = 0;
int rowOffset = startGuardEnd;
int lgPatternFound = 0;
for (int x = 0; x < 6 && rowOffset < end; x++) { for (int x = 0; x < 6 && rowOffset < end; x++) {
int bestMatch = decodeDigit(row, counters, countersLen, rowOffset, int bestMatch = decodeDigit(row, counters, rowOffset, L_AND_G_PATTERNS);
UPC_EAN_PATTERNS_L_AND_G_PATTERNS); resultString.append(1, (char) ('0' + bestMatch % 10));
if (bestMatch < 0) { for (int i = 0, end = counters.size(); i <end; i++) {
return -1; rowOffset += counters[i];
}
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;
} }
if (bestMatch >= 10) {
bool EAN13Reader::determineFirstDigit(std::string& resultString, int lgPatternFound) { lgPatternFound |= 1 << (5 - x);
for (int d = 0; d < 10; d++) {
if (lgPatternFound == FIRST_DIGIT_ENCODINGS[d]) {
resultString.insert(0, 1, (char) ('0' + d));
return true;
}
}
return false;
}
BarcodeFormat EAN13Reader::getBarcodeFormat(){
return BarcodeFormat_EAN_13;
} }
} }
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 << " " <<FIRST_DIGIT_ENCODINGS << std::endl;
for (int d = 0; d < 10; d++) {
if (lgPatternFound == FIRST_DIGIT_ENCODINGS[d]) {
resultString.insert(0, 1, (char) ('0' + d));
return;
}
}
throw NotFoundException::getNotFoundInstance();
}
zxing::BarcodeFormat EAN13Reader::getBarcodeFormat(){
return BarcodeFormat::EAN_13;
} }

View file

@ -1,3 +1,4 @@
// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*-
#ifndef __EAN_13_READER_H__ #ifndef __EAN_13_READER_H__
#define __EAN_13_READER_H__ #define __EAN_13_READER_H__
@ -25,20 +26,24 @@
namespace zxing { namespace zxing {
namespace oned { namespace oned {
class EAN13Reader : public UPCEANReader { class EAN13Reader;
private:
static bool determineFirstDigit(std::string& resultString, int lgPatternFound);
public:
EAN13Reader();
int decodeMiddle(Ref<BitArray> row, int startGuardBegin, int startGuardEnd,
std::string& resultString);
BarcodeFormat getBarcodeFormat();
};
} }
} }
class zxing::oned::EAN13Reader : public UPCEANReader {
private:
std::vector<int> decodeMiddleCounters;
static void determineFirstDigit(std::string& resultString,
int lgPatternFound);
public:
EAN13Reader();
int decodeMiddle(Ref<BitArray> row,
Range const& startRange,
std::string& resultString);
BarcodeFormat getBarcodeFormat();
};
#endif #endif

View file

@ -18,55 +18,44 @@
#include "EAN8Reader.h" #include "EAN8Reader.h"
#include <zxing/ReaderException.h> #include <zxing/ReaderException.h>
namespace zxing { using std::vector;
namespace oned { using zxing::oned::EAN8Reader;
EAN8Reader::EAN8Reader(){ } EAN8Reader::EAN8Reader() : decodeMiddleCounters(4, 0) { }
int EAN8Reader::decodeMiddle(Ref<BitArray> row, int startGuardBegin, int startGuardEnd, int EAN8Reader::decodeMiddle(Ref<BitArray> row,
std::string& resultString){ Range const& startRange,
(void)startGuardBegin; std::string& result){
const int countersLen = 4; vector<int>& counters (decodeMiddleCounters);
int counters[countersLen] = { 0, 0, 0, 0 }; counters[0] = 0;
counters[1] = 0;
counters[2] = 0;
counters[3] = 0;
int end = row->getSize(); int end = row->getSize();
int rowOffset = startGuardEnd; int rowOffset = startRange[1];
for (int x = 0; x < 4 && rowOffset < end; x++) { for (int x = 0; x < 4 && rowOffset < end; x++) {
int bestMatch = decodeDigit(row, counters, countersLen, rowOffset, int bestMatch = decodeDigit(row, counters, rowOffset, L_PATTERNS);
UPC_EAN_PATTERNS_L_PATTERNS); result.append(1, (char) ('0' + bestMatch));
if (bestMatch < 0) { for (int i = 0, end = counters.size(); i < end; i++) {
return -1; rowOffset += counters[i];
}
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;
} }
} }
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;
} }

View file

@ -1,3 +1,4 @@
// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*-
#ifndef __EAN_8_READER_H__ #ifndef __EAN_8_READER_H__
#define __EAN_8_READER_H__ #define __EAN_8_READER_H__
@ -25,17 +26,21 @@
namespace zxing { namespace zxing {
namespace oned { namespace oned {
class EAN8Reader : public UPCEANReader { class EAN8Reader;
public:
EAN8Reader();
int decodeMiddle(Ref<BitArray> row, int startGuardBegin, int startGuardEnd,
std::string& resultString);
BarcodeFormat getBarcodeFormat();
};
} }
} }
class zxing::oned::EAN8Reader : public UPCEANReader {
std::vector<int> decodeMiddleCounters;
public:
EAN8Reader();
int decodeMiddle(Ref<BitArray> row,
Range const& startRange,
std::string& resultString);
BarcodeFormat getBarcodeFormat();
};
#endif #endif

View file

@ -19,227 +19,216 @@
#include <zxing/oned/OneDResultPoint.h> #include <zxing/oned/OneDResultPoint.h>
#include <zxing/common/Array.h> #include <zxing/common/Array.h>
#include <zxing/ReaderException.h> #include <zxing/ReaderException.h>
#include <zxing/FormatException.h>
#include <zxing/NotFoundException.h>
#include <math.h> #include <math.h>
namespace zxing { using std::vector;
namespace oned { 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 #define VECTOR_INIT(v) v, v + sizeof(v)/sizeof(v[0])
static const int N = 1; // Pixed width of a narrow line
const int DEFAULT_ALLOWED_LENGTHS_LEN = 10; namespace {
const int DEFAULT_ALLOWED_LENGTHS[DEFAULT_ALLOWED_LENGTHS_LEN] = { 44, 24, 20, 18, 16, 14, 12, 10, 8, 6 };
/** const int W = 3; // Pixel width of a wide line
* Start/end guard pattern. const int N = 1; // Pixed width of a narrow line
*
* Note: The end pattern is reversed because the row is reversed before
* searching for the END_PATTERN
*/
static const int START_PATTERN_LEN = 4;
static const int START_PATTERN[START_PATTERN_LEN] = {N, N, N, N};
static const int END_PATTERN_REVERSED_LEN = 3; const int DEFAULT_ALLOWED_LENGTHS_LEN = 10;
static const int END_PATTERN_REVERSED[END_PATTERN_REVERSED_LEN] = {N, N, W}; const int DEFAULT_ALLOWED_LENGTHS_[DEFAULT_ALLOWED_LENGTHS_LEN] = { 44, 24, 20, 18, 16, 14, 12, 10, 8, 6 };
const ArrayRef<int> DEFAULT_ALLOWED_LENGTHS (new Array<int>(DEFAULT_ALLOWED_LENGTHS_,
DEFAULT_ALLOWED_LENGTHS_LEN ));
/** /**
* Patterns of Wide / Narrow lines to indicate each digit * Start/end guard pattern.
*/ *
static const int PATTERNS_LEN = 10; * Note: The end pattern is reversed because the row is reversed before
static const int PATTERNS[PATTERNS_LEN][5] = { * searching for the END_PATTERN
{N, N, W, W, N}, // 0 */
{W, N, N, N, W}, // 1 const int START_PATTERN_LEN = 4;
{N, W, N, N, W}, // 2 const int START_PATTERN_[START_PATTERN_LEN] = {N, N, N, N};
{W, W, N, N, N}, // 3 const vector<int> START_PATTERN (VECTOR_INIT(START_PATTERN_));
{N, N, W, N, W}, // 4
{W, N, W, N, N}, // 5 const int END_PATTERN_REVERSED_LEN = 3;
{N, W, W, N, N}, // 6 const int END_PATTERN_REVERSED_[END_PATTERN_REVERSED_LEN] = {N, N, W};
{N, N, N, W, W}, // 7 const vector<int> END_PATTERN_REVERSED (VECTOR_INIT(END_PATTERN_REVERSED_));
{W, N, N, W, N}, // 8
{N, W, N, W, N} // 9 /**
}; * 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<Result> ITFReader::decodeRow(int rowNumber, Ref<BitArray> 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<String> resultString(new String(result));
ArrayRef<int> 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<ResultPoint> > resultPoints(2);
resultPoints[0] = Ref<OneDResultPoint>(new OneDResultPoint(startRange[1], (float) rowNumber));
resultPoints[1] = Ref<OneDResultPoint>(new OneDResultPoint(endRange[0], (float) rowNumber));
return Ref<Result>(new Result(resultString, ArrayRef<char>(), 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<BitArray> row,
int payloadStart,
int payloadEnd,
std::string& resultString) {
// Digits are interleaved in pairs - 5 black lines for one digit, and the
// 5
// interleaved white lines for the second digit.
// Therefore, need to scan 10 lines and then
// split these into two arrays
vector<int> counterDigitPair(10, 0);
vector<int> counterBlack(5, 0);
vector<int> 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<Result> ITFReader::decodeRow(int rowNumber, Ref<BitArray> row) { for (int i = 0, e = counterDigitPair.size(); i < e; i++) {
int* startRange = 0; payloadStart += counterDigitPair[i];
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<String> resultString(new String(tmpResult));
std::vector< Ref<ResultPoint> > resultPoints(2);
Ref<OneDResultPoint> resultPoint1(new OneDResultPoint(startRange[1], (float) rowNumber));
Ref<OneDResultPoint> resultPoint2(new OneDResultPoint(endRange[0], (float) rowNumber));
resultPoints[0] = resultPoint1;
resultPoints[1] = resultPoint2;
delete [] startRange;
delete [] endRange;
ArrayRef<unsigned char> resultBytes(1);
return Ref<Result>(new Result(resultString, resultBytes, resultPoints, BarcodeFormat_ITF));
} catch (ReaderException const& re) {
delete [] startRange;
delete [] endRange;
return Ref<Result>();
}
} }
}
}
/** /**
* @param row row of black/white values to search * Identify where the start of the middle / payload section starts.
* @param payloadStart offset of start pattern *
* @param resultString {@link StringBuffer} to append decoded chars to * @param row row of black/white values to search
* @throws ReaderException if decoding could not complete successfully * @return Array, containing index of start of 'start block' and end of
*/ * 'start block'
void ITFReader::decodeMiddle(Ref<BitArray> row, int payloadStart, int payloadEnd, * @throws ReaderException
std::string& resultString) { */
// Digits are interleaved in pairs - 5 black lines for one digit, and the ITFReader::Range ITFReader::decodeStart(Ref<BitArray> row) {
// 5 int endStart = skipWhiteSpace(row);
// interleaved white lines for the second digit. Range startPattern = findGuardPattern(row, endStart, START_PATTERN);
// Therefore, need to scan 10 lines and then
// split these into two arrays
int counterDigitPairLen = 10;
int counterDigitPair[counterDigitPairLen];
for (int i=0; i<counterDigitPairLen; i++) {
counterDigitPair[i] = 0;
}
int counterBlack[5]; // Determine the width of a narrow line in pixels. We can do this by
int counterWhite[5]; // getting the width of the start pattern and dividing by 4 because its
for (int i=0; i<5; i++) { // made up of 4 narrow lines.
counterBlack[i] = 0; narrowLineWidth = (startPattern[1] - startPattern[0]) >> 2;
counterWhite[i] = 0;
}
while (payloadStart < payloadEnd) { validateQuietZone(row, startPattern[0]);
// Get 10 runs of black/white. return startPattern;
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];
}
int bestMatch = decodeDigit(counterBlack, 5); /**
resultString.append(1, (char) ('0' + bestMatch)); * Identify where the end of the middle / payload section ends.
bestMatch = decodeDigit(counterWhite, 5); *
resultString.append(1, (char) ('0' + bestMatch)); * @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++) { ITFReader::Range ITFReader::decodeEnd(Ref<BitArray> row) {
payloadStart += counterDigitPair[i]; // For convenience, reverse the row and then
} // search from 'the start' for the end block
} BitArray::Reverse r (row);
}
/** int endStart = skipWhiteSpace(row);
* Identify where the start of the middle / payload section starts. Range endPattern = findGuardPattern(row, endStart, END_PATTERN_REVERSED);
*
* @param row row of black/white values to search
* @return Array, containing index of start of 'start block' and end of
* 'start block'
* @throws ReaderException
*/
int* ITFReader::decodeStart(Ref<BitArray> row) {
int endStart = skipWhiteSpace(row);
int* startPattern = 0;
try {
startPattern = findGuardPattern(row, endStart, START_PATTERN, START_PATTERN_LEN);
// Determine the width of a narrow line in pixels. We can do this by // The start & end patterns must be pre/post fixed by a quiet zone. This
// getting the width of the start pattern and dividing by 4 because its // zone must be at least 10 times the width of a narrow line.
// made up of 4 narrow lines. // ref: http://www.barcode-1.net/i25code.html
narrowLineWidth = (startPattern[1] - startPattern[0]) >> 2; validateQuietZone(row, endPattern[0]);
validateQuietZone(row, startPattern[0]);
return startPattern;
} catch (ReaderException const& re) {
delete [] startPattern;
throw re;
}
}
/** // Now recalculate the indices of where the 'endblock' starts & stops to
* Identify where the end of the middle / payload section ends. // accommodate
* // the reversed nature of the search
* @param row row of black/white values to search int temp = endPattern[0];
* @return Array, containing index of start of 'end block' and end of 'end endPattern[0] = row->getSize() - endPattern[1];
* block' endPattern[1] = row->getSize() - temp;
* @throws ReaderException
*/ return endPattern;
}
int* ITFReader::decodeEnd(Ref<BitArray> row) { /**
// For convenience, reverse the row and then * The start & end patterns must be pre/post fixed by a quiet zone. This
// search from 'the start' for the end block * zone must be at least 10 times the width of a narrow line. Scan back until
row->reverse(); * we either get to the start of the barcode or match the necessary number of
int* endPattern = 0; * quiet zone pixels.
try { *
int endStart = skipWhiteSpace(row); * Note: Its assumed the row is reversed when using this method to find
endPattern = findGuardPattern(row, endStart, END_PATTERN_REVERSED, END_PATTERN_REVERSED_LEN); * quiet zone after the end pattern.
*
// The start & end patterns must be pre/post fixed by a quiet zone. This * ref: http://www.barcode-1.net/i25code.html
// zone must be at least 10 times the width of a narrow line. *
// ref: http://www.barcode-1.net/i25code.html * @param row bit array representing the scanned barcode.
validateQuietZone(row, endPattern[0]); * @param startPattern index into row of the start or end pattern.
* @throws ReaderException if the quiet zone cannot be found, a ReaderException is thrown.
// Now recalculate the indices of where the 'endblock' starts & stops to */
// accommodate void ITFReader::validateQuietZone(Ref<BitArray> row, int startPattern) {
// the reversed nature of the search (void)row;
int temp = endPattern[0]; (void)startPattern;
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<BitArray> row, int startPattern) {
(void)row;
(void)startPattern;
//#pragma mark needs some corrections //#pragma mark needs some corrections
// int quietCount = narrowLineWidth * 10; // expect to find this many pixels of quiet zone // 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. // // Unable to find the necessary number of quiet zone pixels.
// throw ReaderException("Unable to find the necessary number of quiet zone pixels"); // throw ReaderException("Unable to find the necessary number of quiet zone pixels");
// } // }
}
/**
* Skip all whitespace until we get to the first black line.
*
* @param row row of black/white values to search
* @return index of the first black line.
* @throws ReaderException Throws exception if no black lines are found in the row
*/
int ITFReader::skipWhiteSpace(Ref<BitArray> row) {
int width = row->getSize();
int endStart = 0;
while (endStart < width) {
if (row->get(endStart)) {
break;
} }
endStart++;
}
if (endStart == width) {
throw ReaderException("");
}
return endStart;
}
/** /**
* Skip all whitespace until we get to the first black line. * @param row row of black/white values to search
* * @param rowOffset position to start search
* @param row row of black/white values to search * @param pattern pattern of counts of number of black and white pixels that are
* @return index of the first black line. * being searched for as a pattern
* @throws ReaderException Throws exception if no black lines are found in the row * @return start/end horizontal offset of guard pattern, as an array of two
*/ * ints
int ITFReader::skipWhiteSpace(Ref<BitArray> row) { * @throws ReaderException if pattern is not found
int width = row->getSize(); */
int endStart = 0; ITFReader::Range ITFReader::findGuardPattern(Ref<BitArray> row,
while (endStart < width) { int rowOffset,
if (row->get(endStart)) { vector<int> const& pattern) {
break; // TODO: This is very similar to implementation in UPCEANReader. Consider if they can be
} // merged to a single method.
endStart++; int patternLength = pattern.size();
} vector<int> counters(patternLength, 0);
if (endStart == width) { int width = row->getSize();
throw ReaderException(""); bool isWhite = false;
}
return endStart;
}
/** int counterPosition = 0;
* @param row row of black/white values to search int patternStart = rowOffset;
* @param rowOffset position to start search for (int x = rowOffset; x < width; x++) {
* @param pattern pattern of counts of number of black and white pixels that are if (row->get(x) ^ isWhite) {
* being searched for as a pattern counters[counterPosition]++;
* @return start/end horizontal offset of guard pattern, as an array of two } else {
* ints if (counterPosition == patternLength - 1) {
* @throws ReaderException if pattern is not found if (patternMatchVariance(counters, &pattern[0], MAX_INDIVIDUAL_VARIANCE) < MAX_AVG_VARIANCE) {
*/ return Range(patternStart, x);
int* ITFReader::findGuardPattern(Ref<BitArray> row, int rowOffset, const int pattern[],
int patternLen) {
// TODO: This is very similar to implementation in UPCEANReader. Consider if they can be
// merged to a single method.
int patternLength = patternLen;
int counters[patternLength];
for (int i=0; i<patternLength; i++) {
counters[i] = 0;
}
int width = row->getSize();
bool isWhite = false;
int counterPosition = 0;
int patternStart = rowOffset;
for (int x = rowOffset; x < width; x++) {
bool pixel = row->get(x);
if (pixel ^ isWhite) {
counters[counterPosition]++;
} else {
if (counterPosition == patternLength - 1) {
if (patternMatchVariance(counters, patternLength, pattern,
MAX_INDIVIDUAL_VARIANCE) < MAX_AVG_VARIANCE) {
int* resultValue = new int[2];
resultValue[0] = patternStart;
resultValue[1] = x;
return resultValue;
}
patternStart += counters[0] + counters[1];
for (int y = 2; y < patternLength; y++) {
counters[y - 2] = counters[y];
}
counters[patternLength - 2] = 0;
counters[patternLength - 1] = 0;
counterPosition--;
} else {
counterPosition++;
}
counters[counterPosition] = 1;
isWhite = !isWhite;
} }
} patternStart += counters[0] + counters[1];
throw ReaderException(""); for (int y = 2; y < patternLength; y++) {
} counters[y - 2] = counters[y];
/**
* Attempts to decode a sequence of ITF black/white lines into single
* digit.
*
* @param counters the counts of runs of observed black/white/black/... values
* @return The decoded digit
* @throws ReaderException if digit cannot be decoded
*/
int ITFReader::decodeDigit(int counters[], int countersLen){
unsigned int bestVariance = MAX_AVG_VARIANCE; // worst variance we'll accept
int bestMatch = -1;
int max = PATTERNS_LEN;
for (int i = 0; i < max; i++) {
int pattern[countersLen];
for(int ind = 0; ind<countersLen; ind++){
pattern[ind] = PATTERNS[i][ind];
} }
unsigned int variance = patternMatchVariance(counters, countersLen, pattern, counters[patternLength - 2] = 0;
MAX_INDIVIDUAL_VARIANCE); counters[patternLength - 1] = 0;
if (variance < bestVariance) { counterPosition--;
bestVariance = variance;
bestMatch = i;
}
}
if (bestMatch >= 0) {
return bestMatch;
} else { } else {
throw ReaderException("digit didint found"); counterPosition++;
} }
} counters[counterPosition] = 1;
isWhite = !isWhite;
ITFReader::~ITFReader(){
} }
} }
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<int>& 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(){}

View file

@ -24,30 +24,32 @@
namespace zxing { namespace zxing {
namespace oned { namespace oned {
class ITFReader : public OneDReader { class ITFReader;
}
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<BitArray> row); //throws ReaderException
int* decodeEnd(Ref<BitArray> row); //throws ReaderException
static void decodeMiddle(Ref<BitArray> row, int payloadStart, int payloadEnd, std::string& resultString); //throws ReaderException
void validateQuietZone(Ref<BitArray> row, int startPattern); //throws ReaderException
static int skipWhiteSpace(Ref<BitArray> row); //throws ReaderException
static int* findGuardPattern(Ref<BitArray> 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<Result> decodeRow(int rowNumber, Ref<BitArray> row); ///throws ReaderException
ITFReader();
~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<BitArray> row);
Range decodeEnd(Ref<BitArray> row);
static void decodeMiddle(Ref<BitArray> row, int payloadStart, int payloadEnd, std::string& resultString);
void validateQuietZone(Ref<BitArray> row, int startPattern);
static int skipWhiteSpace(Ref<BitArray> row);
static Range findGuardPattern(Ref<BitArray> row, int rowOffset, std::vector<int> const& pattern);
static int decodeDigit(std::vector<int>& counters);
void append(char* s, char c);
public:
Ref<Result> decodeRow(int rowNumber, Ref<BitArray> row);
ITFReader();
~ITFReader();
};
#endif #endif

View file

@ -1,3 +1,4 @@
// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*-
/* /*
* MultiFormatOneDReader.cpp * MultiFormatOneDReader.cpp
* ZXing * ZXing
@ -22,45 +23,76 @@
#include <zxing/oned/MultiFormatUPCEANReader.h> #include <zxing/oned/MultiFormatUPCEANReader.h>
#include <zxing/oned/Code39Reader.h> #include <zxing/oned/Code39Reader.h>
#include <zxing/oned/Code128Reader.h> #include <zxing/oned/Code128Reader.h>
#include <zxing/oned/Code93Reader.h>
#include <zxing/oned/CodaBarReader.h>
#include <zxing/oned/ITFReader.h> #include <zxing/oned/ITFReader.h>
#include <zxing/ReaderException.h> #include <zxing/ReaderException.h>
#include <zxing/NotFoundException.h>
namespace zxing { using zxing::Ref;
namespace oned { using zxing::Result;
MultiFormatOneDReader::MultiFormatOneDReader(DecodeHints hints) : readers() { using zxing::oned::MultiFormatOneDReader;
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<OneDReader>(new MultiFormatUPCEANReader(hints)));
}
if (hints.containsFormat(BarcodeFormat_CODE_39)) {
readers.push_back(Ref<OneDReader>(new Code39Reader()));
}
if (hints.containsFormat(BarcodeFormat_CODE_128)) {
readers.push_back(Ref<OneDReader>(new Code128Reader()));
}
if (hints.containsFormat(BarcodeFormat_ITF)) {
readers.push_back(Ref<OneDReader>(new ITFReader()));
}
if (readers.size() == 0) {
readers.push_back(Ref<OneDReader>(new MultiFormatUPCEANReader(hints)));
readers.push_back(Ref<OneDReader>(new Code39Reader()));
readers.push_back(Ref<OneDReader>(new Code128Reader()));
readers.push_back(Ref<OneDReader>(new ITFReader()));
}
}
Ref<Result> MultiFormatOneDReader::decodeRow(int rowNumber, Ref<BitArray> row) { MultiFormatOneDReader::MultiFormatOneDReader(DecodeHints hints) : readers() {
int size = readers.size(); if (hints.containsFormat(BarcodeFormat::EAN_13) ||
for (int i = 0; i < size; i++) { hints.containsFormat(BarcodeFormat::EAN_8) ||
OneDReader* reader = readers[i]; hints.containsFormat(BarcodeFormat::UPC_A) ||
Ref<Result> result = reader->decodeRow(rowNumber, row); hints.containsFormat(BarcodeFormat::UPC_E)) {
if (!result.empty()) { readers.push_back(Ref<OneDReader>(new MultiFormatUPCEANReader(hints)));
return result; }
} if (hints.containsFormat(BarcodeFormat::CODE_39)) {
} readers.push_back(Ref<OneDReader>(new Code39Reader()));
return Ref<Result>(); }
} if (hints.containsFormat(BarcodeFormat::CODE_93)) {
readers.push_back(Ref<OneDReader>(new Code93Reader()));
}
if (hints.containsFormat(BarcodeFormat::CODE_128)) {
readers.push_back(Ref<OneDReader>(new Code128Reader()));
}
if (hints.containsFormat(BarcodeFormat::ITF)) {
readers.push_back(Ref<OneDReader>(new ITFReader()));
}
if (hints.containsFormat(BarcodeFormat::CODABAR)) {
readers.push_back(Ref<OneDReader>(new CodaBarReader()));
}
/*
if (hints.containsFormat(BarcodeFormat::RSS_14)) {
readers.push_back(Ref<OneDReader>(new RSS14Reader()));
}
*/
/*
if (hints.containsFormat(BarcodeFormat::RSS_EXPANDED)) {
readers.push_back(Ref<OneDReader>(new RSS14ExpandedReader()));
}
*/
if (readers.size() == 0) {
readers.push_back(Ref<OneDReader>(new MultiFormatUPCEANReader(hints)));
readers.push_back(Ref<OneDReader>(new Code39Reader()));
readers.push_back(Ref<OneDReader>(new CodaBarReader()));
readers.push_back(Ref<OneDReader>(new Code93Reader()));
readers.push_back(Ref<OneDReader>(new Code128Reader()));
readers.push_back(Ref<OneDReader>(new ITFReader()));
// readers.push_back(Ref<OneDReader>(new RSS14Reader()));
// readers.push_back(Ref<OneDReader>(new RSS14ExpandedReader()));
} }
} }
#include <typeinfo>
Ref<Result> MultiFormatOneDReader::decodeRow(int rowNumber, Ref<BitArray> 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> 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();
}

View file

@ -1,3 +1,4 @@
// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*-
/* /*
* MultiFormatUPCEANReader.cpp * MultiFormatUPCEANReader.cpp
* ZXing * ZXing
@ -25,63 +26,81 @@
#include <zxing/oned/OneDResultPoint.h> #include <zxing/oned/OneDResultPoint.h>
#include <zxing/common/Array.h> #include <zxing/common/Array.h>
#include <zxing/ReaderException.h> #include <zxing/ReaderException.h>
#include <zxing/NotFoundException.h>
#include <math.h> #include <math.h>
namespace zxing { using zxing::NotFoundException;
namespace oned { using zxing::Ref;
using zxing::Result;
MultiFormatUPCEANReader::MultiFormatUPCEANReader(DecodeHints hints) : readers() { using zxing::oned::MultiFormatUPCEANReader;
if (hints.containsFormat(BarcodeFormat_EAN_13)) {
readers.push_back(Ref<OneDReader>(new EAN13Reader())); MultiFormatUPCEANReader::MultiFormatUPCEANReader(DecodeHints hints) : readers() {
} else if (hints.containsFormat(BarcodeFormat_UPC_A)) { if (hints.containsFormat(BarcodeFormat::EAN_13)) {
readers.push_back(Ref<OneDReader>(new UPCAReader())); readers.push_back(Ref<UPCEANReader>(new EAN13Reader()));
} } else if (hints.containsFormat(BarcodeFormat::UPC_A)) {
if (hints.containsFormat(BarcodeFormat_EAN_8)) { readers.push_back(Ref<UPCEANReader>(new UPCAReader()));
readers.push_back(Ref<OneDReader>(new EAN8Reader())); }
} if (hints.containsFormat(BarcodeFormat::EAN_8)) {
if (hints.containsFormat(BarcodeFormat_UPC_E)) { readers.push_back(Ref<UPCEANReader>(new EAN8Reader()));
readers.push_back(Ref<OneDReader>(new UPCEReader())); }
} if (hints.containsFormat(BarcodeFormat::UPC_E)) {
if (readers.size() == 0) { readers.push_back(Ref<UPCEANReader>(new UPCEReader()));
readers.push_back(Ref<OneDReader>(new EAN13Reader())); }
// UPC-A is covered by EAN-13 if (readers.size() == 0) {
readers.push_back(Ref<OneDReader>(new EAN8Reader())); readers.push_back(Ref<UPCEANReader>(new EAN13Reader()));
readers.push_back(Ref<OneDReader>(new UPCEReader())); // UPC-A is covered by EAN-13
} readers.push_back(Ref<UPCEANReader>(new EAN8Reader()));
} readers.push_back(Ref<UPCEANReader>(new UPCEReader()));
Ref<Result> MultiFormatUPCEANReader::decodeRow(int rowNumber, Ref<BitArray> row) {
// Compute this location once and reuse it on multiple implementations
int size = readers.size();
for (int i = 0; i < size; i++) {
Ref<OneDReader> reader = readers[i];
Ref<Result> 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<String> resultString(new String(text.substr(1)));
Ref<Result> res(new Result(resultString, result->getRawBytes(),
result->getResultPoints(), BarcodeFormat_UPC_A));
return res;
}
}
return result;
}
return Ref<Result>();
}
} }
} }
#include <typeinfo>
Ref<Result> MultiFormatUPCEANReader::decodeRow(int rowNumber, Ref<BitArray> 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<UPCEANReader> reader = readers[i];
Ref<Result> 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<Result> resultUPCA (new Result(result->getText()->substring(1),
result->getRawBytes(),
result->getResultPoints(),
BarcodeFormat::UPC_A));
// needs java metadata stuff
return resultUPCA;
}
return result;
}
throw NotFoundException();
}

View file

@ -1,3 +1,4 @@
// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*-
#ifndef __MULTI_FORMAT_UPC_EAN_READER_H__ #ifndef __MULTI_FORMAT_UPC_EAN_READER_H__
#define __MULTI_FORMAT_UPC_EAN_READER_H__ #define __MULTI_FORMAT_UPC_EAN_READER_H__
/* /*
@ -23,16 +24,17 @@
namespace zxing { namespace zxing {
namespace oned { namespace oned {
class MultiFormatUPCEANReader : public OneDReader { class UPCEANReader;
class MultiFormatUPCEANReader;
private:
std::vector<Ref<OneDReader> > readers;
public:
MultiFormatUPCEANReader(DecodeHints hints);
Ref<Result> decodeRow(int rowNumber, Ref<BitArray> row);
};
} }
} }
class zxing::oned::MultiFormatUPCEANReader : public OneDReader {
private:
std::vector< Ref<UPCEANReader> > readers;
public:
MultiFormatUPCEANReader(DecodeHints hints);
Ref<Result> decodeRow(int rowNumber, Ref<BitArray> row);
};
#endif #endif

View file

@ -21,187 +21,202 @@
#include "OneDReader.h" #include "OneDReader.h"
#include <zxing/ReaderException.h> #include <zxing/ReaderException.h>
#include <zxing/oned/OneDResultPoint.h> #include <zxing/oned/OneDResultPoint.h>
#include <zxing/NotFoundException.h>
#include <math.h> #include <math.h>
#include <limits.h> #include <limits.h>
namespace zxing { using std::vector;
namespace oned { using zxing::Ref;
using namespace std; using zxing::Result;
using zxing::NotFoundException;
using zxing::oned::OneDReader;
OneDReader::OneDReader() { OneDReader::OneDReader() {}
}
Ref<Result> OneDReader::decode(Ref<BinaryBitmap> image, DecodeHints hints) { Ref<Result> OneDReader::decode(Ref<BinaryBitmap> image, DecodeHints hints) {
Ref<Result> result = doDecode(image, hints); try {
if (result.empty() && hints.getTryHarder() && image->isRotateSupported()) { return doDecode(image, hints);
Ref<BinaryBitmap> rotatedImage(image->rotateCounterClockwise()); } catch (NotFoundException const& nfe) {
result = doDecode(rotatedImage, hints); // std::cerr << "trying harder" << std::endl;
if (!result.empty()) { bool tryHarder = hints.getTryHarder();
/* if (tryHarder && image->isRotateSupported()) {
// Record that we found it rotated 90 degrees CCW / 270 degrees CW // std::cerr << "v rotate" << std::endl;
Hashtable metadata = result.getResultMetadata(); Ref<BinaryBitmap> rotatedImage(image->rotateCounterClockwise());
int orientation = 270; // std::cerr << "^ rotate" << std::endl;
if (metadata != null && metadata.containsKey(ResultMetadataType.ORIENTATION)) { Ref<Result> result = doDecode(rotatedImage, hints);
// But if we found it reversed in doDecode(), add in that result here: // Doesn't have java metadata stuff
orientation = (orientation + ArrayRef< Ref<ResultPoint> >& points (result->getResultPoints());
((Integer) metadata.get(ResultMetadataType.ORIENTATION)).intValue()) % 360; if (points && !points->empty()) {
} int height = rotatedImage->getHeight();
result.putMetadata(ResultMetadataType.ORIENTATION, new Integer(orientation)); for (int i = 0; i < points.size(); i++) {
*/ points[i].reset(new OneDResultPoint(height - points[i]->getY() - 1, points[i]->getX()));
// Update result points
std::vector<Ref<ResultPoint> >& 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()));
}
} }
} }
if (result.empty()) { // std::cerr << "tried harder" << std::endl;
throw ReaderException("");
}
return result; return result;
} } else {
// std::cerr << "tried harder nfe" << std::endl;
Ref<Result> OneDReader::doDecode(Ref<BinaryBitmap> image, DecodeHints hints) { throw nfe;
int width = image->getWidth();
int height = image->getHeight();
Ref<BitArray> 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> 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<Ref<ResultPoint> > 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<ResultPoint> pointZero(new OneDResultPoint(width - points[0]->getX() - 1,
points[0]->getY()));
points[0] = pointZero;
Ref<ResultPoint> pointOne(new OneDResultPoint(width - points[1]->getX() - 1,
points[1]->getY()));
points[1] = pointOne;
result.reset(new Result(result->getText(), result->getRawBytes(), points,
result->getBarcodeFormat()));
}
}
return result;
}
}
}
return Ref<Result>();
}
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<BitArray> 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() {
} }
} }
} }
#include <typeinfo>
Ref<Result> OneDReader::doDecode(Ref<BinaryBitmap> image, DecodeHints hints) {
int width = image->getWidth();
int height = image->getHeight();
Ref<BitArray> 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> 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<ResultPoint> > points(result->getResultPoints());
if (points) {
points[0] = Ref<ResultPoint>(new OneDResultPoint(width - points[0]->getX() - 1,
points[0]->getY()));
points[1] = Ref<ResultPoint>(new OneDResultPoint(width - points[1]->getX() - 1,
points[1]->getY()));
}
}
return result;
} catch (ReaderException const& re) {
continue;
}
}
}
throw NotFoundException();
}
int OneDReader::patternMatchVariance(vector<int>& counters,
vector<int> const& pattern,
int maxIndividualVariance) {
return patternMatchVariance(counters, &pattern[0], maxIndividualVariance);
}
int OneDReader::patternMatchVariance(vector<int>& 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<BitArray> row,
int start,
vector<int>& 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() {}

View file

@ -1,3 +1,4 @@
// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*-
#ifndef __ONED_READER_H__ #ifndef __ONED_READER_H__
#define __ONED_READER_H__ #define __ONED_READER_H__
@ -23,28 +24,58 @@
#include <zxing/Reader.h> #include <zxing/Reader.h>
namespace zxing { namespace zxing {
namespace oned { namespace oned {
class OneDReader : public Reader { class OneDReader;
private: }
static const int INTEGER_MATH_SHIFT = 8;
Ref<Result> doDecode(Ref<BinaryBitmap> image, DecodeHints hints);
public:
static const int PATTERN_MATCH_RESULT_SCALE_FACTOR = 1 << INTEGER_MATH_SHIFT;
OneDReader();
virtual Ref<Result> decode(Ref<BinaryBitmap> 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<Result>();
virtual Ref<Result> decodeRow(int rowNumber, Ref<BitArray> row) = 0;
static unsigned int patternMatchVariance(int counters[], int countersSize,
const int pattern[], int maxIndividualVariance);
static bool recordPattern(Ref<BitArray> row, int start, int counters[], int countersCount);
virtual ~OneDReader();
};
}
} }
class zxing::oned::OneDReader : public Reader {
private:
Ref<Result> doDecode(Ref<BinaryBitmap> 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<int>& counters,
std::vector<int> const& pattern,
int maxIndividualVariance);
static int patternMatchVariance(std::vector<int>& counters,
int const pattern[],
int maxIndividualVariance);
protected:
static const int PATTERN_MATCH_RESULT_SCALE_FACTOR = 1 << INTEGER_MATH_SHIFT;
public:
OneDReader();
virtual Ref<Result> decode(Ref<BinaryBitmap> 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<Result>();
virtual Ref<Result> decodeRow(int rowNumber, Ref<BitArray> row) = 0;
static void recordPattern(Ref<BitArray> row,
int start,
std::vector<int>& counters);
virtual ~OneDReader();
};
#endif #endif

View file

@ -1,3 +1,4 @@
// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*-
/* /*
* UPCAReader.cpp * UPCAReader.cpp
* ZXing * ZXing
@ -20,46 +21,47 @@
#include "UPCAReader.h" #include "UPCAReader.h"
#include <zxing/ReaderException.h> #include <zxing/ReaderException.h>
namespace zxing { using zxing::oned::UPCAReader;
namespace oned { using zxing::Ref;
UPCAReader::UPCAReader() : ean13Reader() { using zxing::Result;
}
Ref<Result> UPCAReader::decodeRow(int rowNumber, Ref<BitArray> row) { UPCAReader::UPCAReader() : ean13Reader() {
return maybeReturnResult(ean13Reader.decodeRow(rowNumber, row)); }
}
Ref<Result> UPCAReader::decodeRow(int rowNumber, Ref<BitArray> row) {
Ref<Result> UPCAReader::decodeRow(int rowNumber, Ref<BitArray> row, int startGuardBegin, return maybeReturnResult(ean13Reader.decodeRow(rowNumber, row));
int startGuardEnd) { }
return maybeReturnResult(ean13Reader.decodeRow(rowNumber, row, startGuardBegin,
startGuardEnd)); Ref<Result> UPCAReader::decodeRow(int rowNumber,
} Ref<BitArray> row,
Range const& startGuardRange) {
Ref<Result> UPCAReader::decode(Ref<BinaryBitmap> image, DecodeHints hints) { return maybeReturnResult(ean13Reader.decodeRow(rowNumber, row, startGuardRange));
return maybeReturnResult(ean13Reader.decode(image, hints)); }
}
Ref<Result> UPCAReader::decode(Ref<BinaryBitmap> image, DecodeHints hints) {
int UPCAReader::decodeMiddle(Ref<BitArray> row, int startGuardBegin, int startGuardEnd, return maybeReturnResult(ean13Reader.decode(image, hints));
std::string& resultString) { }
return ean13Reader.decodeMiddle(row, startGuardBegin, startGuardEnd, resultString);
} int UPCAReader::decodeMiddle(Ref<BitArray> row,
Range const& startRange,
Ref<Result> UPCAReader::maybeReturnResult(Ref<Result> result) { std::string& resultString) {
if (result.empty()) { return ean13Reader.decodeMiddle(row, startRange, resultString);
return result; }
}
const std::string& text = (result->getText())->getText(); Ref<Result> UPCAReader::maybeReturnResult(Ref<Result> result) {
if (text[0] == '0') { if (result.empty()) {
Ref<String> resultString(new String(text.substr(1))); return result;
Ref<Result> res(new Result(resultString, result->getRawBytes(), result->getResultPoints(), }
BarcodeFormat_UPC_A)); const std::string& text = (result->getText())->getText();
return res; if (text[0] == '0') {
} Ref<String> resultString(new String(text.substr(1)));
return Ref<Result>(); Ref<Result> res(new Result(resultString, result->getRawBytes(), result->getResultPoints(),
} BarcodeFormat::UPC_A));
return res;
BarcodeFormat UPCAReader::getBarcodeFormat(){ }
return BarcodeFormat_UPC_A; return Ref<Result>();
} }
}
zxing::BarcodeFormat UPCAReader::getBarcodeFormat(){
return BarcodeFormat::UPC_A;
} }

View file

@ -1,3 +1,4 @@
// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*-
#ifndef __UPCA_READER_H__ #ifndef __UPCA_READER_H__
#define __UPCA_READER_H__ #define __UPCA_READER_H__
/* /*
@ -24,26 +25,26 @@
namespace zxing { namespace zxing {
namespace oned { namespace oned {
class UPCAReader : public UPCEANReader { class UPCAReader;
private:
EAN13Reader ean13Reader;
static Ref<Result> maybeReturnResult(Ref<Result> result);
public:
UPCAReader();
int decodeMiddle(Ref<BitArray> row, int startGuardBegin, int startGuardEnd,
std::string& resultString);
Ref<Result> decodeRow(int rowNumber, Ref<BitArray> row);
Ref<Result> decodeRow(int rowNumber, Ref<BitArray> row, int startGuardBegin,
int startGuardEnd);
Ref<Result> decode(Ref<BinaryBitmap> image, DecodeHints hints);
BarcodeFormat getBarcodeFormat();
};
} }
} }
class zxing::oned::UPCAReader : public UPCEANReader {
private:
EAN13Reader ean13Reader;
static Ref<Result> maybeReturnResult(Ref<Result> result);
public:
UPCAReader();
int decodeMiddle(Ref<BitArray> row, Range const& startRange, std::string& resultString);
Ref<Result> decodeRow(int rowNumber, Ref<BitArray> row);
Ref<Result> decodeRow(int rowNumber, Ref<BitArray> row, Range const& startGuardRange);
Ref<Result> decode(Ref<BinaryBitmap> image, DecodeHints hints);
BarcodeFormat getBarcodeFormat();
};
#endif #endif

View file

@ -1,3 +1,4 @@
// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*-
/* /*
* UPCEANReader.cpp * UPCEANReader.cpp
* ZXing * ZXing
@ -20,292 +21,280 @@
#include "UPCEANReader.h" #include "UPCEANReader.h"
#include <zxing/oned/OneDResultPoint.h> #include <zxing/oned/OneDResultPoint.h>
#include <zxing/ReaderException.h> #include <zxing/ReaderException.h>
#include <zxing/NotFoundException.h>
#include <zxing/ChecksumException.h>
namespace zxing { using zxing::Ref;
namespace oned { using zxing::Result;
using zxing::NotFoundException;
using zxing::ChecksumException;
using zxing::oned::UPCEANReader;
using namespace std; // remove
/** #define LEN(v) ((int)(sizeof(v)/sizeof(v[0])))
* Start/end guard pattern.
*/
static const int START_END_PATTERN[3] = {1, 1, 1};
/** namespace {
* Pattern marking the middle of a UPC/EAN pattern, separating the two halves.
*/
static const int MIDDLE_PATTERN_LEN = 5;
static const int MIDDLE_PATTERN[MIDDLE_PATTERN_LEN] = {1, 1, 1, 1, 1};
/** /**
* "Odd", or "L" patterns used to encode UPC/EAN digits. * Start/end guard pattern.
*/ */
const int L_PATTERNS_LEN = 10; const int START_END_PATTERN_[] = {1, 1, 1};
const int L_PATTERNS_SUB_LEN = 4; const int START_END_PATTERN_LEN = LEN(START_END_PATTERN_);
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
};
/** /**
* As above but also including the "even", or "G" patterns used to encode UPC/EAN digits. * Pattern marking the middle of a UPC/EAN pattern, separating the two halves.
*/ */
const int L_AND_G_PATTERNS_LEN = 20; const int MIDDLE_PATTERN_[] = {1, 1, 1, 1, 1};
const int L_AND_G_PATTERNS_SUB_LEN = 4; const int MIDDLE_PATTERN_LEN = LEN(MIDDLE_PATTERN_);
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
};
/**
* "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<int>
UPCEANReader::START_END_PATTERN (VECTOR_INIT(START_END_PATTERN_));
const vector<int>
UPCEANReader::MIDDLE_PATTERN (VECTOR_INIT(MIDDLE_PATTERN_));
const vector<int const*>
UPCEANReader::L_PATTERNS (VECTOR_INIT(L_PATTERNS_));
const vector<int const*>
UPCEANReader::L_AND_G_PATTERNS (VECTOR_INIT(L_AND_G_PATTERNS_));
UPCEANReader::UPCEANReader() {}
Ref<Result> UPCEANReader::decodeRow(int rowNumber, Ref<BitArray> row) {
return decodeRow(rowNumber, row, findStartGuardPattern(row));
}
Ref<Result> UPCEANReader::decodeRow(int rowNumber,
Ref<BitArray> row,
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<String> 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<ResultPoint> > resultPoints(2);
resultPoints[0] = Ref<ResultPoint>(new OneDResultPoint(left, (float) rowNumber));
resultPoints[1] = Ref<ResultPoint>(new OneDResultPoint(right, (float) rowNumber));
Ref<Result> decodeResult (new Result(resultString, ArrayRef<char>(), resultPoints, format));
// Java extension and man stuff
return decodeResult;
}
UPCEANReader::Range UPCEANReader::findStartGuardPattern(Ref<BitArray> row) {
bool foundStart = false;
Range startRange;
int nextStart = 0;
vector<int> 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;
} }
startRange = findGuardPattern(row, nextStart, false, START_END_PATTERN, counters);
const int* UPCEANReader::getMIDDLE_PATTERN() { // std::cerr << "sr " << startRange[0] << " " << startRange[1] << std::endl;
return MIDDLE_PATTERN; 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.
UPCEANReader::UPCEANReader() { // 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) {
Ref<Result> UPCEANReader::decodeRow(int rowNumber, Ref<BitArray> row) { foundStart = row->isRange(quietStart, start, false);
int rangeStart;
int rangeEnd;
if (findStartGuardPattern(row, &rangeStart, &rangeEnd)) {
try {
return decodeRow(rowNumber, row, rangeStart, rangeEnd);
} catch (ReaderException const& re) {
}
}
return Ref<Result>();
}
Ref<Result> UPCEANReader::decodeRow(int rowNumber, Ref<BitArray> row, int startGuardBegin,
int startGuardEnd) {
std::string tmpResultString;
std::string& tmpResultStringRef = tmpResultString;
int endStart = decodeMiddle(row, startGuardBegin, startGuardEnd, tmpResultStringRef);
if (endStart < 0) {
return Ref<Result>();
}
int endGuardBegin;
int endGuardEnd;
if (!decodeEnd(row, endStart, &endGuardBegin, &endGuardEnd)) {
return Ref<Result>();
}
// 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<Result>();
}
if (!checkChecksum(tmpResultString)) {
return Ref<Result>();
}
Ref<String> resultString(new String(tmpResultString));
float left = (float) (startGuardBegin + startGuardEnd) / 2.0f;
float right = (float) (endGuardBegin + endGuardEnd) / 2.0f;
std::vector< Ref<ResultPoint> > resultPoints(2);
Ref<OneDResultPoint> resultPoint1(new OneDResultPoint(left, (float) rowNumber));
Ref<OneDResultPoint> resultPoint2(new OneDResultPoint(right, (float) rowNumber));
resultPoints[0] = resultPoint1;
resultPoints[1] = resultPoint2;
ArrayRef<unsigned char> resultBytes(1);
return Ref<Result>(new Result(resultString, resultBytes, resultPoints, getBarcodeFormat()));
}
bool UPCEANReader::findStartGuardPattern(Ref<BitArray> 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<BitArray> 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<BitArray> 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<BitArray> 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() {
} }
} }
return startRange;
}
UPCEANReader::Range UPCEANReader::findGuardPattern(Ref<BitArray> row,
int rowOffset,
bool whiteFirst,
vector<int> const& pattern) {
vector<int> counters (pattern.size(), 0);
return findGuardPattern(row, rowOffset, whiteFirst, pattern, counters);
}
UPCEANReader::Range UPCEANReader::findGuardPattern(Ref<BitArray> row,
int rowOffset,
bool whiteFirst,
vector<int> const& pattern,
vector<int>& 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<BitArray> row, int endStart) {
return findGuardPattern(row, endStart, false, START_END_PATTERN);
}
int UPCEANReader::decodeDigit(Ref<BitArray> row,
vector<int> & counters,
int rowOffset,
vector<int const*> 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<String> 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<String> 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() {
} }

View file

@ -22,54 +22,67 @@
#include <zxing/common/BitArray.h> #include <zxing/common/BitArray.h>
#include <zxing/Result.h> #include <zxing/Result.h>
typedef enum UPC_EAN_PATTERNS {
UPC_EAN_PATTERNS_L_PATTERNS = 0,
UPC_EAN_PATTERNS_L_AND_G_PATTERNS
} UPC_EAN_PATTERNS;
namespace zxing { namespace zxing {
namespace oned { namespace oned {
class UPCEANReader : public OneDReader { class MultiFormatUPCEANReader;
class UPCEANReader;
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<BitArray> row, int* rangeStart, int* rangeEnd);
virtual bool decodeEnd(Ref<BitArray> row, int endStart, int* endGuardBegin, int* endGuardEnd);
static bool checkStandardUPCEANChecksum(std::string s);
protected:
static bool findGuardPattern(Ref<BitArray> 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<BitArray> row, int startGuardBegin, int startGuardEnd,
std::string& resultString) = 0;
Ref<Result> decodeRow(int rowNumber, Ref<BitArray> row);
// TODO(dswitkin): Should this be virtual so that UPCAReader can override it?
Ref<Result> decodeRow(int rowNumber, Ref<BitArray> row, int startGuardBegin,
int startGuardEnd);
// Returns < 0 on failure, >= 0 on success.
static int decodeDigit(Ref<BitArray> row, int counters[], int countersLen, int rowOffset,
UPC_EAN_PATTERNS patternType);
virtual bool checkChecksum(std::string s);
virtual BarcodeFormat getBarcodeFormat() = 0;
virtual ~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<BitArray> row);
virtual Range decodeEnd(Ref<BitArray> row, int endStart);
static bool checkStandardUPCEANChecksum(Ref<String> const& s);
static Range findGuardPattern(Ref<BitArray> row,
int rowOffset,
bool whiteFirst,
std::vector<int> const& pattern,
std::vector<int>& counters);
protected:
static const std::vector<int> START_END_PATTERN;
static const std::vector<int> MIDDLE_PATTERN;
static const std::vector<int const*> L_PATTERNS;
static const std::vector<int const*> L_AND_G_PATTERNS;
static Range findGuardPattern(Ref<BitArray> row,
int rowOffset,
bool whiteFirst,
std::vector<int> const& pattern);
public:
UPCEANReader();
virtual int decodeMiddle(Ref<BitArray> row,
Range const& startRange,
std::string& resultString) = 0;
virtual Ref<Result> decodeRow(int rowNumber, Ref<BitArray> row);
virtual Ref<Result> decodeRow(int rowNumber, Ref<BitArray> row, Range const& range);
static int decodeDigit(Ref<BitArray> row,
std::vector<int>& counters,
int rowOffset,
std::vector<int const*> const& patterns);
virtual bool checkChecksum(Ref<String> const& s);
virtual BarcodeFormat getBarcodeFormat() = 0;
virtual ~UPCEANReader();
};
#endif #endif

View file

@ -18,125 +18,125 @@
#include "UPCEReader.h" #include "UPCEReader.h"
#include <zxing/ReaderException.h> #include <zxing/ReaderException.h>
namespace zxing { using std::string;
namespace oned { using std::vector;
using zxing::Ref;
using zxing::String;
using zxing::oned::UPCEReader;
/** #define VECTOR_INIT(v) v, v + sizeof(v)/sizeof(v[0])
* 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};
/** namespace {
* 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) * The pattern that marks the middle, and end, of a UPC-E pattern.
* used, and the check digit. * There is no "second half" to a UPC-E barcode.
*/ */
static const int NUMSYS_AND_CHECK_DIGIT_PATTERNS[2][10] = { const int MIDDLE_END_PATTERN_[6] = {1, 1, 1, 1, 1, 1};
{0x38, 0x34, 0x32, 0x31, 0x2C, 0x26, 0x23, 0x2A, 0x29, 0x25}, const vector<int> MIDDLE_END_PATTERN (VECTOR_INIT(MIDDLE_END_PATTERN_));
{0x07, 0x0B, 0x0D, 0x0E, 0x13, 0x19, 0x1C, 0x15, 0x16, 0x1A}
};
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<BitArray> row, Range const& startRange, string& result) {
vector<int>& 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];
} }
if (bestMatch >= 10) {
int UPCEReader::decodeMiddle(Ref<BitArray> row, int startGuardBegin, int startGuardEnd, lgPatternFound |= 1 << (5 - x);
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<BitArray> 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;
} }
} }
determineNumSysAndCheckDigit(result, lgPatternFound);
return rowOffset;
}
UPCEReader::Range UPCEReader::decodeEnd(Ref<BitArray> row, int endStart) {
return findGuardPattern(row, endStart, true, MIDDLE_END_PATTERN);
}
bool UPCEReader::checkChecksum(Ref<String> 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<String> UPCEReader::convertUPCEtoUPCA(Ref<String> 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<String>(new String(result));
}
zxing::BarcodeFormat UPCEReader::getBarcodeFormat() {
return BarcodeFormat::UPC_E;
} }

View file

@ -1,3 +1,4 @@
// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*-
#ifndef __UPC_E_READER_H__ #ifndef __UPC_E_READER_H__
#define __UPC_E_READER_H__ #define __UPC_E_READER_H__
@ -22,23 +23,25 @@
namespace zxing { namespace zxing {
namespace oned { namespace oned {
class UPCEReader : public UPCEANReader { class UPCEReader;
private:
static bool determineNumSysAndCheckDigit(std::string& resultString, int lgPatternFound);
protected:
bool decodeEnd(Ref<BitArray> row, int endStart, int* endGuardBegin, int* endGuardEnd);
bool checkChecksum(std::string s);
public:
UPCEReader();
int decodeMiddle(Ref<BitArray> row, int startGuardBegin, int startGuardEnd,
std::string& resultString);
static std::string convertUPCEtoUPCA(std::string upce);
BarcodeFormat getBarcodeFormat();
};
} }
} }
class zxing::oned::UPCEReader : public UPCEANReader {
private:
std::vector<int> decodeMiddleCounters;
static bool determineNumSysAndCheckDigit(std::string& resultString, int lgPatternFound);
protected:
Range decodeEnd(Ref<BitArray> row, int endStart);
bool checkChecksum(Ref<String> const& s);
public:
UPCEReader();
int decodeMiddle(Ref<BitArray> row, Range const& startRange, std::string& resultString);
static Ref<String> convertUPCEtoUPCA(Ref<String> const& upce);
BarcodeFormat getBarcodeFormat();
};
#endif #endif

View file

@ -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 }; 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) : FormatInformation::FormatInformation(int formatInfo) :
errorCorrectionLevel_(ErrorCorrectionLevel::forBits((formatInfo >> 3) & 0x03)), dataMask_( errorCorrectionLevel_(ErrorCorrectionLevel::forBits((formatInfo >> 3) & 0x03)), dataMask_((char)(formatInfo & 0x07)) {
(unsigned char)(formatInfo & 0x07)) {
} }
ErrorCorrectionLevel& FormatInformation::getErrorCorrectionLevel() { ErrorCorrectionLevel& FormatInformation::getErrorCorrectionLevel() {
return errorCorrectionLevel_; return errorCorrectionLevel_;
} }
unsigned char FormatInformation::getDataMask() { char FormatInformation::getDataMask() {
return dataMask_; return dataMask_;
} }
int FormatInformation::numBitsDiffering(unsigned int a, unsigned int b) { int FormatInformation::numBitsDiffering(int a, int b) {
a ^= 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 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)] & 0x0F)] + BITS_SET_IN_HALF_BYTE[(a >> 12 & 0x0F)] + BITS_SET_IN_HALF_BYTE[(a >> 16 & 0x0F)]

View file

@ -35,16 +35,16 @@ private:
static int BITS_SET_IN_HALF_BYTE[]; static int BITS_SET_IN_HALF_BYTE[];
ErrorCorrectionLevel &errorCorrectionLevel_; ErrorCorrectionLevel &errorCorrectionLevel_;
unsigned char dataMask_; char dataMask_;
FormatInformation(int formatInfo); FormatInformation(int formatInfo);
public: public:
static int numBitsDiffering(unsigned int a, unsigned int b); static int numBitsDiffering(int a, int b);
static Ref<FormatInformation> decodeFormatInformation(int maskedFormatInfo1, int maskedFormatInfo2); static Ref<FormatInformation> decodeFormatInformation(int maskedFormatInfo1, int maskedFormatInfo2);
static Ref<FormatInformation> doDecodeFormatInformation(int maskedFormatInfo1, int maskedFormatInfo2); static Ref<FormatInformation> doDecodeFormatInformation(int maskedFormatInfo1, int maskedFormatInfo2);
ErrorCorrectionLevel &getErrorCorrectionLevel(); ErrorCorrectionLevel &getErrorCorrectionLevel();
unsigned char getDataMask(); char getDataMask();
friend bool operator==(const FormatInformation &a, const FormatInformation &b); friend bool operator==(const FormatInformation &a, const FormatInformation &b);
friend std::ostream& operator<<(std::ostream& out, const FormatInformation& fi); friend std::ostream& operator<<(std::ostream& out, const FormatInformation& fi);
}; };

View file

@ -49,8 +49,7 @@ namespace zxing {
cout << "(2) detected, have detectorResult " << detectorResult.object_ << "\n" << flush; cout << "(2) detected, have detectorResult " << detectorResult.object_ << "\n" << flush;
#endif #endif
std::vector<Ref<ResultPoint> > points(detectorResult->getPoints()); ArrayRef< Ref<ResultPoint> > points (detectorResult->getPoints());
#ifdef DEBUG #ifdef DEBUG
cout << "(3) extracted points " << &points << "\n" << flush; cout << "(3) extracted points " << &points << "\n" << flush;
@ -68,7 +67,7 @@ namespace zxing {
#endif #endif
Ref<Result> result( Ref<Result> result(
new Result(decoderResult->getText(), decoderResult->getRawBytes(), points, BarcodeFormat_QR_CODE)); new Result(decoderResult->getText(), decoderResult->getRawBytes(), points, BarcodeFormat::QR_CODE));
#ifdef DEBUG #ifdef DEBUG
cout << "(5) created result " << result.object_ << ", returning\n" << flush; cout << "(5) created result " << result.object_ << ", returning\n" << flush;
#endif #endif

View file

@ -116,7 +116,7 @@ Version *BitMatrixParser::readVersion() {
throw ReaderException("Could not decode version"); throw ReaderException("Could not decode version");
} }
ArrayRef<unsigned char> BitMatrixParser::readCodewords() { ArrayRef<char> BitMatrixParser::readCodewords() {
Ref<FormatInformation> formatInfo = readFormatInformation(); Ref<FormatInformation> formatInfo = readFormatInformation();
Version *version = readVersion(); Version *version = readVersion();
@ -141,7 +141,7 @@ ArrayRef<unsigned char> BitMatrixParser::readCodewords() {
// cout << *functionPattern << endl; // cout << *functionPattern << endl;
bool readingUp = true; bool readingUp = true;
ArrayRef<unsigned char> result(version->getTotalCodewords()); ArrayRef<char> result(version->getTotalCodewords());
int resultOffset = 0; int resultOffset = 0;
int currentByte = 0; int currentByte = 0;
int bitsRead = 0; int bitsRead = 0;
@ -166,7 +166,7 @@ ArrayRef<unsigned char> BitMatrixParser::readCodewords() {
} }
// If we've made a whole byte, save it off // If we've made a whole byte, save it off
if (bitsRead == 8) { if (bitsRead == 8) {
result[resultOffset++] = (unsigned char)currentByte; result[resultOffset++] = (char)currentByte;
bitsRead = 0; bitsRead = 0;
currentByte = 0; currentByte = 0;
} }

View file

@ -42,7 +42,7 @@ public:
BitMatrixParser(Ref<BitMatrix> bitMatrix); BitMatrixParser(Ref<BitMatrix> bitMatrix);
Ref<FormatInformation> readFormatInformation(); Ref<FormatInformation> readFormatInformation();
Version *readVersion(); Version *readVersion();
ArrayRef<unsigned char> readCodewords(); ArrayRef<char> readCodewords();
private: private:
BitMatrixParser(const BitMatrixParser&); BitMatrixParser(const BitMatrixParser&);

View file

@ -26,7 +26,7 @@ namespace qrcode {
using namespace std; using namespace std;
DataBlock::DataBlock(int numDataCodewords, ArrayRef<unsigned char> codewords) : DataBlock::DataBlock(int numDataCodewords, ArrayRef<char> codewords) :
numDataCodewords_(numDataCodewords), codewords_(codewords) { numDataCodewords_(numDataCodewords), codewords_(codewords) {
} }
@ -34,12 +34,12 @@ int DataBlock::getNumDataCodewords() {
return numDataCodewords_; return numDataCodewords_;
} }
ArrayRef<unsigned char> DataBlock::getCodewords() { ArrayRef<char> DataBlock::getCodewords() {
return codewords_; return codewords_;
} }
std::vector<Ref<DataBlock> > DataBlock::getDataBlocks(ArrayRef<unsigned char> rawCodewords, Version *version, std::vector<Ref<DataBlock> > DataBlock::getDataBlocks(ArrayRef<char> rawCodewords, Version *version,
ErrorCorrectionLevel &ecLevel) { ErrorCorrectionLevel &ecLevel) {
@ -63,7 +63,7 @@ std::vector<Ref<DataBlock> > DataBlock::getDataBlocks(ArrayRef<unsigned char> ra
for (int i = 0; i < ecBlock->getCount(); i++) { for (int i = 0; i < ecBlock->getCount(); i++) {
int numDataCodewords = ecBlock->getDataCodewords(); int numDataCodewords = ecBlock->getDataCodewords();
int numBlockCodewords = ecBlocks.getECCodewords() + numDataCodewords; int numBlockCodewords = ecBlocks.getECCodewords() + numDataCodewords;
ArrayRef<unsigned char> buffer(numBlockCodewords); ArrayRef<char> buffer(numBlockCodewords);
Ref<DataBlock> blockRef(new DataBlock(numDataCodewords, buffer)); Ref<DataBlock> blockRef(new DataBlock(numDataCodewords, buffer));
result[numResultBlocks++] = blockRef; result[numResultBlocks++] = blockRef;
} }
@ -107,7 +107,7 @@ std::vector<Ref<DataBlock> > DataBlock::getDataBlocks(ArrayRef<unsigned char> ra
} }
} }
if ((size_t)rawCodewordsOffset != rawCodewords.size()) { if (rawCodewordsOffset != rawCodewords.size()) {
throw IllegalArgumentException("rawCodewordsOffset != rawCodewords.length"); throw IllegalArgumentException("rawCodewordsOffset != rawCodewords.length");
} }

View file

@ -32,16 +32,16 @@ namespace qrcode {
class DataBlock : public Counted { class DataBlock : public Counted {
private: private:
int numDataCodewords_; int numDataCodewords_;
ArrayRef<unsigned char> codewords_; ArrayRef<char> codewords_;
DataBlock(int numDataCodewords, ArrayRef<unsigned char> codewords); DataBlock(int numDataCodewords, ArrayRef<char> codewords);
public: public:
static std::vector<Ref<DataBlock> > static std::vector<Ref<DataBlock> >
getDataBlocks(ArrayRef<unsigned char> rawCodewords, Version *version, ErrorCorrectionLevel &ecLevel); getDataBlocks(ArrayRef<char> rawCodewords, Version *version, ErrorCorrectionLevel &ecLevel);
int getNumDataCodewords(); int getNumDataCodewords();
ArrayRef<unsigned char> getCodewords(); ArrayRef<char> getCodewords();
}; };
} }

View file

@ -55,11 +55,11 @@ namespace {int GB2312_SUBSET = 1;}
void DecodedBitStreamParser::append(std::string &result, void DecodedBitStreamParser::append(std::string &result,
string const& in, string const& in,
const char *src) { 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, void DecodedBitStreamParser::append(std::string &result,
const unsigned char *bufIn, const char *bufIn,
size_t nIn, size_t nIn,
const char *src) { const char *src) {
#ifndef NO_ICONV #ifndef NO_ICONV
@ -74,7 +74,7 @@ void DecodedBitStreamParser::append(std::string &result,
} }
const int maxOut = 4 * nIn + 1; 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; ICONV_CONST char *fromPtr = (ICONV_CONST char *)bufIn;
size_t nFrom = nIn; size_t nFrom = nIn;
@ -112,7 +112,7 @@ void DecodedBitStreamParser::decodeHanziSegment(Ref<BitSource> bits_,
// Each character will require 2 bytes. Read the characters as 2-byte pairs // Each character will require 2 bytes. Read the characters as 2-byte pairs
// and decode as GB2312 afterwards // and decode as GB2312 afterwards
size_t nBytes = 2 * count; size_t nBytes = 2 * count;
unsigned char* buffer = new unsigned char[nBytes]; char* buffer = new char[nBytes];
int offset = 0; int offset = 0;
while (count > 0) { while (count > 0) {
// Each 13 bits encodes a 2-byte character // Each 13 bits encodes a 2-byte character
@ -125,8 +125,8 @@ void DecodedBitStreamParser::decodeHanziSegment(Ref<BitSource> bits_,
// In the 0xB0A1 to 0xFAFE range // In the 0xB0A1 to 0xFAFE range
assembledTwoBytes += 0x0A6A1; assembledTwoBytes += 0x0A6A1;
} }
buffer[offset] = (unsigned char) ((assembledTwoBytes >> 8) & 0xFF); buffer[offset] = (char) ((assembledTwoBytes >> 8) & 0xFF);
buffer[offset + 1] = (unsigned char) (assembledTwoBytes & 0xFF); buffer[offset + 1] = (char) (assembledTwoBytes & 0xFF);
offset += 2; offset += 2;
count--; count--;
} }
@ -145,7 +145,7 @@ void DecodedBitStreamParser::decodeKanjiSegment(Ref<BitSource> bits, std::string
// Each character will require 2 bytes. Read the characters as 2-byte pairs // Each character will require 2 bytes. Read the characters as 2-byte pairs
// and decode as Shift_JIS afterwards // and decode as Shift_JIS afterwards
size_t nBytes = 2 * count; size_t nBytes = 2 * count;
unsigned char* buffer = new unsigned char[nBytes]; char* buffer = new char[nBytes];
int offset = 0; int offset = 0;
while (count > 0) { while (count > 0) {
// Each 13 bits encodes a 2-byte character // Each 13 bits encodes a 2-byte character
@ -159,8 +159,8 @@ void DecodedBitStreamParser::decodeKanjiSegment(Ref<BitSource> bits, std::string
// In the 0xE040 to 0xEBBF range // In the 0xE040 to 0xEBBF range
assembledTwoBytes += 0x0C140; assembledTwoBytes += 0x0C140;
} }
buffer[offset] = (unsigned char)(assembledTwoBytes >> 8); buffer[offset] = (char)(assembledTwoBytes >> 8);
buffer[offset + 1] = (unsigned char)assembledTwoBytes; buffer[offset + 1] = (char)assembledTwoBytes;
offset += 2; offset += 2;
count--; count--;
} }
@ -173,7 +173,7 @@ void DecodedBitStreamParser::decodeByteSegment(Ref<BitSource> bits_,
string& result, string& result,
int count, int count,
CharacterSetECI* currentCharacterSetECI, CharacterSetECI* currentCharacterSetECI,
ArrayRef< ArrayRef<unsigned char> >& byteSegments, ArrayRef< ArrayRef<char> >& byteSegments,
Hashtable const& hints) { Hashtable const& hints) {
int nBytes = count; int nBytes = count;
BitSource& bits (*bits_); BitSource& bits (*bits_);
@ -182,10 +182,10 @@ void DecodedBitStreamParser::decodeByteSegment(Ref<BitSource> bits_,
throw FormatException(); throw FormatException();
} }
ArrayRef<unsigned char> bytes_ (count); ArrayRef<char> bytes_ (count);
unsigned char* readBytes = &(*bytes_)[0]; char* readBytes = &(*bytes_)[0];
for (int i = 0; i < count; i++) { for (int i = 0; i < count; i++) {
readBytes[i] = (unsigned char) bits.readBits(8); readBytes[i] = (char) bits.readBits(8);
} }
string encoding; string encoding;
if (currentCharacterSetECI == 0) { if (currentCharacterSetECI == 0) {
@ -208,7 +208,7 @@ void DecodedBitStreamParser::decodeByteSegment(Ref<BitSource> bits_,
void DecodedBitStreamParser::decodeNumericSegment(Ref<BitSource> bits, std::string &result, int count) { void DecodedBitStreamParser::decodeNumericSegment(Ref<BitSource> bits, std::string &result, int count) {
int nBytes = count; int nBytes = count;
unsigned char* bytes = new unsigned char[nBytes]; char* bytes = new char[nBytes];
int i = 0; int i = 0;
// Read three digits at a time // Read three digits at a time
while (count >= 3) { while (count >= 3) {
@ -335,7 +335,7 @@ namespace {
} }
Ref<DecoderResult> Ref<DecoderResult>
DecodedBitStreamParser::decode(ArrayRef<unsigned char> bytes, DecodedBitStreamParser::decode(ArrayRef<char> bytes,
Version* version, Version* version,
ErrorCorrectionLevel const& ecLevel, ErrorCorrectionLevel const& ecLevel,
Hashtable const& hints) { Hashtable const& hints) {
@ -344,7 +344,7 @@ DecodedBitStreamParser::decode(ArrayRef<unsigned char> bytes,
string result; string result;
CharacterSetECI* currentCharacterSetECI = 0; CharacterSetECI* currentCharacterSetECI = 0;
bool fc1InEffect = false; bool fc1InEffect = false;
ArrayRef< ArrayRef<unsigned char> > byteSegments (size_t(0)); ArrayRef< ArrayRef<char> > byteSegments (0);
Mode* mode = 0; Mode* mode = 0;
do { do {
// While still another segment to read... // While still another segment to read...

Some files were not shown because too many files have changed in this diff Show more