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
Memcheck:Leak
fun:malloc
...
fun:_ZN5zxing6common15CharacterSetECI11init_tablesEv
}
dlsym
Memcheck:Value8
fun:_simple_salloc
fun:_ZN4dyld9mkstringfEPKcz
}
{
ImageMagick
Memcheck:Leak
...
fun:AcquireImage
dlsym
Memcheck:Cond
fun:_ZN4dyld9mkstringfEPKcz
}

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

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

View file

@ -22,23 +22,41 @@
*/
namespace zxing {
typedef enum BarcodeFormat {
BarcodeFormat_None = 0,
BarcodeFormat_QR_CODE,
BarcodeFormat_DATA_MATRIX,
BarcodeFormat_UPC_E,
BarcodeFormat_UPC_A,
BarcodeFormat_EAN_8,
BarcodeFormat_EAN_13,
BarcodeFormat_CODE_128,
BarcodeFormat_CODE_39,
BarcodeFormat_ITF,
BarcodeFormat_AZTEC
} BarcodeFormat;
class BarcodeFormat;
}
/* if you update the enum, please update the name in BarcodeFormat.cpp */
extern const char *barcodeFormatNames[];
class zxing::BarcodeFormat {
public:
enum Value {
AZTEC,
CODABAR,
CODE_39,
CODE_93,
CODE_128,
DATA_MATRIX,
EAN_8,
EAN_13,
ITF,
MAXICODE,
PDF_417,
QR_CODE,
RSS_14,
RSS_EXPANDED,
UPC_A,
UPC_E,
UPC_EAN_EXTENSION,
};
BarcodeFormat(Value v) : value(v) {}
const Value value;
operator Value () const {return value;}
/* if you update the enum, please update the name in BarcodeFormat.cpp */
static char const* barcodeFormatNames[];
};
namespace zxing {
class BarcodeFormat;
}
#endif // __BARCODE_FORMAT_H__

View file

@ -1,3 +1,4 @@
// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*-
/*
* BinaryBitmap.cpp
* zxing
@ -19,49 +20,51 @@
#include <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<BitArray> BinaryBitmap::getBlackRow(int y, Ref<BitArray> row) {
return binarizer_->getBlackRow(y, row);
}
Ref<BitMatrix> BinaryBitmap::getBlackMatrix() {
return binarizer_->getBlackMatrix();
}
int BinaryBitmap::getWidth() const {
return getLuminanceSource()->getWidth();
}
int BinaryBitmap::getHeight() const {
return getLuminanceSource()->getHeight();
}
Ref<LuminanceSource> BinaryBitmap::getLuminanceSource() const {
return binarizer_->getLuminanceSource();
}
bool BinaryBitmap::isCropSupported() const {
return getLuminanceSource()->isCropSupported();
}
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))));
}
bool BinaryBitmap::isRotateSupported() const {
return getLuminanceSource()->isRotateSupported();
}
Ref<BinaryBitmap> BinaryBitmap::rotateCounterClockwise() {
return Ref<BinaryBitmap> (new BinaryBitmap(binarizer_->createBinarizer(getLuminanceSource()->rotateCounterClockwise())));
}
BinaryBitmap::BinaryBitmap(Ref<Binarizer> binarizer) : binarizer_(binarizer) {
}
BinaryBitmap::~BinaryBitmap() {
}
Ref<BitArray> BinaryBitmap::getBlackRow(int y, Ref<BitArray> row) {
return binarizer_->getBlackRow(y, row);
}
Ref<BitMatrix> BinaryBitmap::getBlackMatrix() {
return binarizer_->getBlackMatrix();
}
int BinaryBitmap::getWidth() const {
return getLuminanceSource()->getWidth();
}
int BinaryBitmap::getHeight() const {
return getLuminanceSource()->getHeight();
}
Ref<LuminanceSource> BinaryBitmap::getLuminanceSource() const {
return binarizer_->getLuminanceSource();
}
bool BinaryBitmap::isCropSupported() const {
return getLuminanceSource()->isCropSupported();
}
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))));
}
bool BinaryBitmap::isRotateSupported() const {
return getLuminanceSource()->isRotateSupported();
}
Ref<BinaryBitmap> BinaryBitmap::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
* zxing
@ -19,36 +20,37 @@
#include <zxing/DecodeHints.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 DecodeHints DecodeHints::PRODUCT_HINT(
BARCODEFORMAT_UPC_E_HINT |
BARCODEFORMAT_UPC_A_HINT |
BARCODEFORMAT_EAN_8_HINT |
BARCODEFORMAT_EAN_13_HINT);
UPC_A_HINT |
UPC_E_HINT |
EAN_13_HINT |
EAN_8_HINT |
RSS_14_HINT
);
const DecodeHints DecodeHints::ONED_HINT(
BARCODEFORMAT_UPC_E_HINT |
BARCODEFORMAT_UPC_A_HINT |
BARCODEFORMAT_EAN_8_HINT |
BARCODEFORMAT_EAN_13_HINT |
BARCODEFORMAT_CODE_128_HINT |
BARCODEFORMAT_CODE_39_HINT |
BARCODEFORMAT_ITF_HINT);
CODE_39_HINT |
CODE_93_HINT |
CODE_128_HINT |
ITF_HINT |
CODABAR_HINT |
DecodeHints::PRODUCT_HINT
);
const DecodeHints DecodeHints::DEFAULT_HINT(
BARCODEFORMAT_UPC_E_HINT |
BARCODEFORMAT_UPC_A_HINT |
BARCODEFORMAT_EAN_8_HINT |
BARCODEFORMAT_EAN_13_HINT |
BARCODEFORMAT_CODE_128_HINT |
BARCODEFORMAT_CODE_39_HINT |
BARCODEFORMAT_ITF_HINT |
BARCODEFORMAT_DATA_MATRIX_HINT |
BARCODEFORMAT_AZTEC_HINT |
BARCODEFORMAT_QR_CODE_HINT);
ONED_HINT |
QR_CODE_HINT |
DATA_MATRIX_HINT |
AZTEC_HINT
);
DecodeHints::DecodeHints() {
hints = 0;
@ -60,34 +62,46 @@ DecodeHints::DecodeHints(DecodeHintType init) {
void DecodeHints::addFormat(BarcodeFormat toadd) {
switch (toadd) {
case BarcodeFormat_AZTEC: hints |= BARCODEFORMAT_AZTEC_HINT; break;
case BarcodeFormat_QR_CODE: hints |= BARCODEFORMAT_QR_CODE_HINT; break;
case BarcodeFormat_DATA_MATRIX: hints |= BARCODEFORMAT_DATA_MATRIX_HINT; break;
case BarcodeFormat_UPC_E: hints |= BARCODEFORMAT_UPC_E_HINT; break;
case BarcodeFormat_UPC_A: hints |= BARCODEFORMAT_UPC_A_HINT; break;
case BarcodeFormat_EAN_8: hints |= BARCODEFORMAT_EAN_8_HINT; break;
case BarcodeFormat_EAN_13: hints |= BARCODEFORMAT_EAN_13_HINT; break;
case BarcodeFormat_CODE_128: hints |= BARCODEFORMAT_CODE_128_HINT; break;
case BarcodeFormat_CODE_39: hints |= BARCODEFORMAT_CODE_39_HINT; break;
case BarcodeFormat_ITF: hints |= BARCODEFORMAT_ITF_HINT; break;
default: throw IllegalArgumentException("Unrecognizd barcode format");
case BarcodeFormat::AZTEC: hints |= AZTEC_HINT; break;
case BarcodeFormat::CODABAR: hints |= CODABAR_HINT; break;
case BarcodeFormat::CODE_39: hints |= CODE_39_HINT; break;
case BarcodeFormat::CODE_93: hints |= CODE_93_HINT; break;
case BarcodeFormat::CODE_128: hints |= CODE_128_HINT; break;
case BarcodeFormat::DATA_MATRIX: hints |= DATA_MATRIX_HINT; break;
case BarcodeFormat::EAN_8: hints |= EAN_8_HINT; break;
case BarcodeFormat::EAN_13: hints |= EAN_13_HINT; break;
case BarcodeFormat::ITF: hints |= ITF_HINT; break;
case BarcodeFormat::MAXICODE: hints |= MAXICODE_HINT; break;
case BarcodeFormat::QR_CODE: hints |= QR_CODE_HINT; break;
case BarcodeFormat::RSS_14: hints |= RSS_14_HINT; break;
case BarcodeFormat::RSS_EXPANDED: hints |= RSS_EXPANDED_HINT; break;
case BarcodeFormat::UPC_A: hints |= UPC_A_HINT; break;
case BarcodeFormat::UPC_E: hints |= UPC_E_HINT; break;
case BarcodeFormat::UPC_EAN_EXTENSION: hints |= UPC_EAN_EXTENSION_HINT; break;
default: throw IllegalArgumentException("Unrecognizd barcode format");
}
}
bool DecodeHints::containsFormat(BarcodeFormat tocheck) const {
DecodeHintType checkAgainst;
DecodeHintType checkAgainst = 0;
switch (tocheck) {
case BarcodeFormat_AZTEC: checkAgainst = BARCODEFORMAT_AZTEC_HINT; break;
case BarcodeFormat_QR_CODE: checkAgainst = BARCODEFORMAT_QR_CODE_HINT; break;
case BarcodeFormat_DATA_MATRIX: checkAgainst = BARCODEFORMAT_DATA_MATRIX_HINT; break;
case BarcodeFormat_UPC_E: checkAgainst = BARCODEFORMAT_UPC_E_HINT; break;
case BarcodeFormat_UPC_A: checkAgainst = BARCODEFORMAT_UPC_A_HINT; break;
case BarcodeFormat_EAN_8: checkAgainst = BARCODEFORMAT_EAN_8_HINT; break;
case BarcodeFormat_EAN_13: checkAgainst = BARCODEFORMAT_EAN_13_HINT; break;
case BarcodeFormat_CODE_128: checkAgainst = BARCODEFORMAT_CODE_128_HINT; break;
case BarcodeFormat_CODE_39: checkAgainst = BARCODEFORMAT_CODE_39_HINT; break;
case BarcodeFormat_ITF: checkAgainst = BARCODEFORMAT_ITF_HINT; break;
default: throw IllegalArgumentException("Unrecognizd barcode format");
case BarcodeFormat::AZTEC: checkAgainst |= AZTEC_HINT; break;
case BarcodeFormat::CODABAR: checkAgainst |= CODABAR_HINT; break;
case BarcodeFormat::CODE_39: checkAgainst |= CODE_39_HINT; break;
case BarcodeFormat::CODE_93: checkAgainst |= CODE_93_HINT; break;
case BarcodeFormat::CODE_128: checkAgainst |= CODE_128_HINT; break;
case BarcodeFormat::DATA_MATRIX: checkAgainst |= DATA_MATRIX_HINT; break;
case BarcodeFormat::EAN_8: checkAgainst |= EAN_8_HINT; break;
case BarcodeFormat::EAN_13: checkAgainst |= EAN_13_HINT; break;
case BarcodeFormat::ITF: checkAgainst |= ITF_HINT; break;
case BarcodeFormat::MAXICODE: checkAgainst |= MAXICODE_HINT; break;
case BarcodeFormat::QR_CODE: checkAgainst |= QR_CODE_HINT; break;
case BarcodeFormat::RSS_14: checkAgainst |= RSS_14_HINT; break;
case BarcodeFormat::RSS_EXPANDED: checkAgainst |= RSS_EXPANDED_HINT; break;
case BarcodeFormat::UPC_A: checkAgainst |= UPC_A_HINT; break;
case BarcodeFormat::UPC_E: checkAgainst |= UPC_E_HINT; break;
case BarcodeFormat::UPC_EAN_EXTENSION: checkAgainst |= UPC_EAN_EXTENSION_HINT; break;
default: throw IllegalArgumentException("Unrecognizd barcode format");
}
return (hints & checkAgainst);
}
@ -105,11 +119,18 @@ bool DecodeHints::getTryHarder() const {
}
void DecodeHints::setResultPointCallback(Ref<ResultPointCallback> const& _callback) {
callback = _callback;
callback = _callback;
}
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_
#define __DECODEHINTS_H_
/*
@ -23,29 +24,35 @@
#include <zxing/ResultPointCallback.h>
namespace zxing {
typedef unsigned int DecodeHintType;
class DecodeHints;
DecodeHints operator | (DecodeHints const&, DecodeHints const&);
}
typedef unsigned int DecodeHintType;
class DecodeHints {
class zxing::DecodeHints {
private:
DecodeHintType hints;
Ref<ResultPointCallback> callback;
public:
static const DecodeHintType AZTEC_HINT = 1 << BarcodeFormat::AZTEC;
static const DecodeHintType CODABAR_HINT = 1 << BarcodeFormat::CODABAR;
static const DecodeHintType CODE_39_HINT = 1 << BarcodeFormat::CODE_39;
static const DecodeHintType CODE_93_HINT = 1 << BarcodeFormat::CODE_93;
static const DecodeHintType CODE_128_HINT = 1 << BarcodeFormat::CODE_128;
static const DecodeHintType DATA_MATRIX_HINT = 1 << BarcodeFormat::DATA_MATRIX;
static const DecodeHintType EAN_8_HINT = 1 << BarcodeFormat::EAN_8;
static const DecodeHintType EAN_13_HINT = 1 << BarcodeFormat::EAN_13;
static const DecodeHintType ITF_HINT = 1 << BarcodeFormat::ITF;
static const DecodeHintType MAXICODE_HINT = 1 << BarcodeFormat::MAXICODE;
static const DecodeHintType PDF_417_HINT = 1 << BarcodeFormat::PDF_417;
static const DecodeHintType QR_CODE_HINT = 1 << BarcodeFormat::QR_CODE;
static const DecodeHintType RSS_14_HINT = 1 << BarcodeFormat::RSS_14;
static const DecodeHintType RSS_EXPANDED_HINT = 1 << BarcodeFormat::RSS_EXPANDED;
static const DecodeHintType UPC_A_HINT = 1 << BarcodeFormat::UPC_A;
static const DecodeHintType UPC_E_HINT = 1 << BarcodeFormat::UPC_E;
static const DecodeHintType UPC_EAN_EXTENSION_HINT = 1 << BarcodeFormat::UPC_EAN_EXTENSION;
static const DecodeHintType BARCODEFORMAT_QR_CODE_HINT = 1 << BarcodeFormat_QR_CODE;
static const DecodeHintType BARCODEFORMAT_DATA_MATRIX_HINT = 1 << BarcodeFormat_DATA_MATRIX;
static const DecodeHintType BARCODEFORMAT_UPC_E_HINT = 1 << BarcodeFormat_UPC_E;
static const DecodeHintType BARCODEFORMAT_UPC_A_HINT = 1 << BarcodeFormat_UPC_A;
static const DecodeHintType BARCODEFORMAT_EAN_8_HINT = 1 << BarcodeFormat_EAN_8;
static const DecodeHintType BARCODEFORMAT_EAN_13_HINT = 1 << BarcodeFormat_EAN_13;
static const DecodeHintType BARCODEFORMAT_CODE_128_HINT = 1 << BarcodeFormat_CODE_128;
static const DecodeHintType BARCODEFORMAT_CODE_39_HINT = 1 << BarcodeFormat_CODE_39;
static const DecodeHintType BARCODEFORMAT_ITF_HINT = 1 << BarcodeFormat_ITF;
static const DecodeHintType BARCODEFORMAT_AZTEC_HINT = 1 << BarcodeFormat_AZTEC;
static const DecodeHintType CHARACTER_SET = 1 << 30;
static const DecodeHintType TRYHARDER_HINT = 1 << 31;
@ -64,8 +71,7 @@ class DecodeHints {
void setResultPointCallback(Ref<ResultPointCallback> const&);
Ref<ResultPointCallback> getResultPointCallback() const;
friend DecodeHints operator | (DecodeHints const&, DecodeHints const&);
};
}
#endif

View file

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

View file

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

View file

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

View file

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

View file

@ -1,3 +1,4 @@
// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*-
/*
* MultiFormatBarcodeReader.cpp
* ZXing
@ -27,80 +28,96 @@
#include <zxing/oned/MultiFormatOneDReader.h>
#include <zxing/ReaderException.h>
namespace zxing {
MultiFormatReader::MultiFormatReader() {
using zxing::Ref;
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);
return decodeInternal(image);
}
return decodeInternal(image);
}
Ref<Result> MultiFormatReader::decode(Ref<BinaryBitmap> image, DecodeHints hints) {
setHints(hints);
return decodeInternal(image);
void MultiFormatReader::setHints(DecodeHints hints) {
hints_ = hints;
readers_.clear();
bool tryHarder = hints.getTryHarder();
bool addOneDReader = hints.containsFormat(BarcodeFormat::UPC_E) ||
hints.containsFormat(BarcodeFormat::UPC_A) ||
hints.containsFormat(BarcodeFormat::UPC_E) ||
hints.containsFormat(BarcodeFormat::EAN_13) ||
hints.containsFormat(BarcodeFormat::EAN_8) ||
hints.containsFormat(BarcodeFormat::CODABAR) ||
hints.containsFormat(BarcodeFormat::CODE_39) ||
hints.containsFormat(BarcodeFormat::CODE_93) ||
hints.containsFormat(BarcodeFormat::CODE_128) ||
hints.containsFormat(BarcodeFormat::ITF) ||
hints.containsFormat(BarcodeFormat::RSS_14) ||
hints.containsFormat(BarcodeFormat::RSS_EXPANDED);
if (addOneDReader && !tryHarder) {
readers_.push_back(Ref<Reader>(new zxing::oned::MultiFormatOneDReader(hints)));
}
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);
}
return decodeInternal(image);
if (hints.containsFormat(BarcodeFormat::QR_CODE)) {
readers_.push_back(Ref<Reader>(new zxing::qrcode::QRCodeReader()));
}
void MultiFormatReader::setHints(DecodeHints hints) {
hints_ = hints;
readers_.clear();
bool tryHarder = hints.getTryHarder();
bool addOneDReader = hints.containsFormat(BarcodeFormat_UPC_E) ||
hints.containsFormat(BarcodeFormat_UPC_A) ||
hints.containsFormat(BarcodeFormat_EAN_8) ||
hints.containsFormat(BarcodeFormat_EAN_13) ||
hints.containsFormat(BarcodeFormat_CODE_128) ||
hints.containsFormat(BarcodeFormat_CODE_39) ||
hints.containsFormat(BarcodeFormat_ITF);
if (addOneDReader && !tryHarder) {
if (hints.containsFormat(BarcodeFormat::DATA_MATRIX)) {
readers_.push_back(Ref<Reader>(new zxing::datamatrix::DataMatrixReader()));
}
if (hints.containsFormat(BarcodeFormat::AZTEC)) {
readers_.push_back(Ref<Reader>(new zxing::aztec::AztecReader()));
}
/*
if (formats.contains(BarcodeFormat.PDF_417)) {
readers.add(new PDF417Reader());
}
if (formats.contains(BarcodeFormat.MAXICODE)) {
readers.add(new MaxiCodeReader());
}
*/
if (addOneDReader && tryHarder) {
readers_.push_back(Ref<Reader>(new zxing::oned::MultiFormatOneDReader(hints)));
}
if (readers_.size() == 0) {
if (!tryHarder) {
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()));
}
if (hints.containsFormat(BarcodeFormat_DATA_MATRIX)) {
readers_.push_back(Ref<Reader>(new zxing::datamatrix::DataMatrixReader()));
}
if (hints.containsFormat(BarcodeFormat_AZTEC)) {
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::qrcode::QRCodeReader()));
readers_.push_back(Ref<Reader>(new zxing::datamatrix::DataMatrixReader()));
readers_.push_back(Ref<Reader>(new zxing::aztec::AztecReader()));
// readers.add(new PDF417Reader());
// readers.add(new MaxiCodeReader());
if (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::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 {
class MultiFormatReader : public Reader {
private:
Ref<Result> decodeInternal(Ref<BinaryBitmap> image);

View file

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

View file

@ -28,6 +28,8 @@ namespace zxing {
NotFoundException();
NotFoundException(const char *msg);
~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>
namespace zxing {
using namespace std;
using zxing::Result;
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) :
text_(text), rawBytes_(rawBytes), resultPoints_(resultPoints), format_(format) {
}
@ -36,29 +41,18 @@ Ref<String> Result::getText() {
return text_;
}
ArrayRef<unsigned char> Result::getRawBytes() {
ArrayRef<char> Result::getRawBytes() {
return rawBytes_;
}
const std::vector<Ref<ResultPoint> >& Result::getResultPoints() const {
ArrayRef< Ref<ResultPoint> > const& Result::getResultPoints() const {
return resultPoints_;
}
std::vector<Ref<ResultPoint> >& Result::getResultPoints() {
ArrayRef< Ref<ResultPoint> >& Result::getResultPoints() {
return resultPoints_;
}
BarcodeFormat Result::getBarcodeFormat() const {
zxing::BarcodeFormat Result::getBarcodeFormat() const {
return format_;
}
ostream& operator<<(ostream &out, Result& result) {
if (result.text_ != 0) {
out << result.text_->getText();
} else {
out << "[" << result.rawBytes_->size() << " bytes]";
}
return out;
}
}

View file

@ -21,7 +21,6 @@
*/
#include <string>
#include <vector>
#include <zxing/common/Array.h>
#include <zxing/common/Counted.h>
#include <zxing/common/Str.h>
@ -33,18 +32,20 @@ namespace zxing {
class Result : public Counted {
private:
Ref<String> text_;
ArrayRef<unsigned char> rawBytes_;
std::vector<Ref<ResultPoint> > resultPoints_;
ArrayRef<char> rawBytes_;
ArrayRef< Ref<ResultPoint> > resultPoints_;
BarcodeFormat format_;
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);
~Result();
Ref<String> getText();
ArrayRef<unsigned char> getRawBytes();
const std::vector<Ref<ResultPoint> >& getResultPoints() const;
std::vector<Ref<ResultPoint> >& getResultPoints();
ArrayRef<char> getRawBytes();
ArrayRef< Ref<ResultPoint> > const& getResultPoints() const;
ArrayRef< Ref<ResultPoint> >& getResultPoints();
BarcodeFormat getBarcodeFormat() const;
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>
namespace zxing {
namespace aztec {
AztecDetectorResult::AztecDetectorResult(Ref<BitMatrix> bits, std::vector<Ref<ResultPoint> > points, bool compact, int nbDatablocks, int nbLayers)
: DetectorResult(bits, points),
compact_(compact),
nbDatablocks_(nbDatablocks),
nbLayers_(nbLayers) {
};
using zxing::aztec::AztecDetectorResult;
AztecDetectorResult::AztecDetectorResult(Ref<BitMatrix> bits,
ArrayRef< Ref<ResultPoint> > points,
bool compact,
int nbDatablocks,
int nbLayers)
: DetectorResult(bits, points),
compact_(compact),
nbDatablocks_(nbDatablocks),
nbLayers_(nbLayers) {
};
bool AztecDetectorResult::isCompact() {
return compact_;
}
bool AztecDetectorResult::isCompact() {
return compact_;
}
int AztecDetectorResult::getNBDatablocks() {
return nbDatablocks_;
}
int AztecDetectorResult::getNBDatablocks() {
return nbDatablocks_;
}
int AztecDetectorResult::getNBLayers() {
return nbLayers_;
}
}
}
int AztecDetectorResult::getNBLayers() {
return nbLayers_;
}

View file

@ -31,7 +31,11 @@ namespace zxing {
bool compact_;
int nbDatablocks_, nbLayers_;
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();
int getNBDatablocks();
int getNBLayers();

View file

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

View file

@ -40,7 +40,7 @@ using zxing::Ref;
using std::string;
namespace {
void add(string& result, unsigned char character) {
void add(string& result, char character) {
#ifndef NO_ICONV
char s[] = { character & 0xff };
char* ss = s;
@ -163,9 +163,9 @@ Ref<DecoderResult> Decoder::decode(Ref<zxing::aztec::AztecDetectorResult> detect
Ref<String> result = getEncodedData(aCorrectedBits);
// std::printf("constructing array\n");
ArrayRef<unsigned char> arrayOut(aCorrectedBits->getSize());
ArrayRef<char> arrayOut(aCorrectedBits->getSize());
for (int i = 0; i < aCorrectedBits->count(); i++) {
arrayOut[i] = (unsigned char)aCorrectedBits->get(i);
arrayOut[i] = (char)aCorrectedBits->get(i);
}
// std::printf("returning\n");
@ -376,7 +376,7 @@ Ref<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/NotFoundException.h>
using std::vector;
using zxing::aztec::Detector;
using zxing::aztec::Point;
using zxing::aztec::AztecDetectorResult;
using zxing::Ref;
using zxing::ArrayRef;
using zxing::ResultPoint;
using zxing::BitArray;
using zxing::BitMatrix;
@ -52,10 +54,15 @@ Ref<AztecDetectorResult> Detector::detect() {
std::vector<Ref<Point> > bullEyeCornerPoints = getBullEyeCornerPoints(pCenter);
extractParameters(bullEyeCornerPoints);
ArrayRef< Ref<ResultPoint> > corners = getMatrixCornerPoints(bullEyeCornerPoints);
std::vector<Ref<ResultPoint> > corners = getMatrixCornerPoints(bullEyeCornerPoints);
Ref<BitMatrix> bits = sampleGrid(image_, corners[shift_%4], corners[(shift_+3)%4], corners[(shift_+2)%4], corners[(shift_+1)%4]);
Ref<BitMatrix> bits =
sampleGrid(image_,
corners[shift_%4],
corners[(shift_+3)%4],
corners[(shift_+2)%4],
corners[(shift_+1)%4]);
// std::printf("------------\ndetected: compact:%s, nbDataBlocks:%d, nbLayers:%d\n------------\n",compact_?"YES":"NO", nbDataBlocks_, nbLayers_);
@ -127,7 +134,8 @@ void Detector::extractParameters(std::vector<Ref<Point> > bullEyeCornerPoints) {
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_);
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)) {
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(targetbx, targetby)));
returnValue.push_back(Ref<ResultPoint>(new ResultPoint(targetcx, targetcy)));
returnValue.push_back(Ref<ResultPoint>(new ResultPoint(targetdx, targetdy)));
return returnValue;
return ArrayRef< Ref<ResultPoint> >(array);
}
void Detector::correctParameterData(Ref<zxing::BitArray> parameterData, bool compact) {

View file

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

View file

@ -17,28 +17,26 @@
#include <zxing/common/BitArray.h>
using namespace std;
using std::vector;
using zxing::BitArray;
namespace zxing {
size_t BitArray::wordsForBits(size_t bits) {
int BitArray::wordsForBits(int bits) {
int arraySize = (bits + bitsPerWord_ - 1) >> logBits_;
return arraySize;
}
BitArray::BitArray(size_t size) :
size_(size), bits_(wordsForBits(size), (const unsigned int)0) {
BitArray::BitArray(int size) :
size_(size), bits_(wordsForBits(size), 0) {
}
BitArray::~BitArray() {
}
size_t BitArray::getSize() {
int BitArray::getSize() const {
return size_;
}
void BitArray::setBulk(size_t i, unsigned int newBits) {
void BitArray::setBulk(int i, int newBits) {
bits_[i >> logBits_] = newBits;
}
@ -69,13 +67,13 @@ void BitArray::setRange(int start, int end) {
}
void BitArray::clear() {
size_t max = bits_.size();
for (size_t i = 0; i < max; i++) {
int max = bits_.size();
for (int i = 0; i < max; i++) {
bits_[i] = 0;
}
}
bool BitArray::isRange(size_t start, size_t end, bool value) {
bool BitArray::isRange(int start, int end, bool value) {
if (end < start) {
throw IllegalArgumentException("end must be after start");
}
@ -84,17 +82,17 @@ bool BitArray::isRange(size_t start, size_t end, bool value) {
}
// treat the 'end' as inclusive, rather than exclusive
end--;
size_t firstWord = start >> logBits_;
size_t lastWord = end >> logBits_;
for (size_t i = firstWord; i <= lastWord; i++) {
size_t firstBit = i > firstWord ? 0 : start & bitsMask_;
size_t lastBit = i < lastWord ? bitsPerWord_ - 1: end & bitsMask_;
unsigned int mask;
int firstWord = start >> logBits_;
int lastWord = end >> logBits_;
for (int i = firstWord; i <= lastWord; i++) {
int firstBit = i > firstWord ? 0 : start & bitsMask_;
int lastBit = i < lastWord ? bitsPerWord_ - 1: end & bitsMask_;
int mask;
if (firstBit == 0 && lastBit == bitsPerWord_ - 1) {
mask = numeric_limits<unsigned int>::max();
mask = -1;
} else {
mask = 0;
for (size_t j = firstBit; j <= lastBit; j++) {
for (int j = firstBit; j <= lastBit; j++) {
mask |= 1 << j;
}
}
@ -111,17 +109,75 @@ bool BitArray::isRange(size_t start, size_t end, bool value) {
return true;
}
vector<unsigned int>& BitArray::getBitArray() {
vector<int>& BitArray::getBitArray() {
return bits_;
}
void BitArray::reverse() {
std::vector<unsigned int> newBits(bits_.size(),(const unsigned int) 0);
for (size_t i = 0; i < size_; i++) {
// std::cerr << "reverse" << std::endl;
std::vector<int> newBits(bits_.size(), 0);
for (int i = 0; i < size_; i++) {
if (get(size_ - i - 1)) {
newBits[i >> logBits_] |= 1<< (i & bitsMask_);
}
}
bits_ = newBits;
}
BitArray::Reverse::Reverse(Ref<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 <vector>
#include <limits>
#include <iostream>
namespace zxing {
class BitArray;
std::ostream& operator << (std::ostream&, BitArray const&);
}
#define ZX_LOG_DIGITS(digits) \
((digits == 8) ? 3 : \
@ -33,38 +37,49 @@ namespace zxing {
((digits == 128) ? 7 : \
(-1))))))
class BitArray : public Counted {
class zxing::BitArray : public Counted {
private:
size_t size_;
std::vector<unsigned int> bits_;
static const unsigned int bitsPerWord_ =
int size_;
std::vector<int> bits_;
static const int bitsPerWord_ =
std::numeric_limits<unsigned int>::digits;
static const unsigned int logBits_ = ZX_LOG_DIGITS(bitsPerWord_);
static const unsigned int bitsMask_ = (1 << logBits_) - 1;
static size_t wordsForBits(size_t bits);
static const int logBits_ = ZX_LOG_DIGITS(bitsPerWord_);
static const int bitsMask_ = (1 << logBits_) - 1;
static int wordsForBits(int bits);
explicit BitArray();
public:
BitArray(size_t size);
BitArray(int size);
~BitArray();
size_t getSize();
int getSize() const;
bool get(size_t i) {
bool get(int i) const {
return (bits_[i >> logBits_] & (1 << (i & bitsMask_))) != 0;
}
void set(size_t i) {
void set(int i) {
bits_[i >> logBits_] |= 1 << (i & bitsMask_);
}
void setBulk(size_t i, unsigned int newBits);
int getNextSet(int from);
int getNextUnset(int from);
void setBulk(int i, int newBits);
void setRange(int start, int end);
void clear();
bool isRange(size_t start, size_t end, bool value);
std::vector<unsigned int>& getBitArray();
bool isRange(int start, int end, bool value);
std::vector<int>& getBitArray();
void reverse();
class Reverse;
};
}
class zxing::BitArray::Reverse {
private:
Ref<BitArray> array;
public:
Reverse(Ref<BitArray> array);
~Reverse();
};
#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::BitArray;
using zxing::ArrayRef;
using zxing::Ref;
namespace {
size_t wordsForSize(size_t width,
size_t height,
unsigned int bitsPerWord,
unsigned int logBits) {
size_t bits = width * height;
int wordsForSize(int width,
int height,
int bitsPerWord,
int logBits) {
int bits = width * height;
int arraySize = (bits + bitsPerWord - 1) >> logBits;
return arraySize;
}
}
BitMatrix::BitMatrix(size_t dimension) :
width_(dimension), height_(dimension), words_(0), bits_(NULL) {
BitMatrix::BitMatrix(int dimension) :
width_(dimension), height_(dimension), words_(0) {
words_ = wordsForSize(width_, height_, bitsPerWord, logBits);
bits_ = new unsigned int[words_];
bits_ = ArrayRef<int>(words_);
clear();
}
BitMatrix::BitMatrix(size_t width, size_t height) :
width_(width), height_(height), words_(0), bits_(NULL) {
BitMatrix::BitMatrix(int width, int height) :
width_(width), height_(height), words_(0) {
words_ = wordsForSize(width_, height_, bitsPerWord, logBits);
bits_ = new unsigned int[words_];
bits_ = ArrayRef<int>(words_);
clear();
}
BitMatrix::~BitMatrix() {
delete[] bits_;
}
BitMatrix::~BitMatrix() {}
void BitMatrix::flip(size_t x, size_t y) {
size_t offset = x + width_ * y;
void BitMatrix::flip(int x, int y) {
int offset = x + width_ * y;
bits_[offset >> logBits] ^= 1 << (offset & bitsMask);
}
void BitMatrix::clear() {
std::fill(bits_, bits_+words_, 0);
std::fill(&bits_[0], &bits_[words_], 0);
}
void BitMatrix::setRegion(size_t left, size_t top, size_t width, size_t height) {
void BitMatrix::setRegion(int left, int top, int width, int height) {
if ((long)top < 0 || (long)left < 0) {
throw IllegalArgumentException("topI and leftJ must be nonnegative");
}
if (height < 1 || width < 1) {
throw IllegalArgumentException("height and width must be at least 1");
}
size_t right = left + width;
size_t bottom = top + height;
int right = left + width;
int bottom = top + height;
if (right > width_ || bottom > height_) {
throw IllegalArgumentException("top + height and left + width must be <= matrix dimension");
}
for (size_t y = top; y < bottom; y++) {
for (int y = top; y < bottom; y++) {
int yOffset = width_ * y;
for (size_t x = left; x < right; x++) {
size_t offset = x + yOffset;
for (int x = left; x < right; x++) {
int offset = x + yOffset;
bits_[offset >> logBits] |= 1 << (offset & bitsMask);
}
}
@ -95,26 +94,26 @@ Ref<BitArray> BitMatrix::getRow(int y, Ref<BitArray> row) {
} else {
row->clear();
}
size_t start = y * width_;
size_t end = start + width_ - 1; // end is inclusive
size_t firstWord = start >> logBits;
size_t lastWord = end >> logBits;
size_t bitOffset = start & bitsMask;
for (size_t i = firstWord; i <= lastWord; i++) {
size_t firstBit = i > firstWord ? 0 : start & bitsMask;
size_t lastBit = i < lastWord ? bitsPerWord - 1 : end & bitsMask;
unsigned int mask;
int start = y * width_;
int end = start + width_ - 1; // end is inclusive
int firstWord = start >> logBits;
int lastWord = end >> logBits;
int bitOffset = start & bitsMask;
for (int i = firstWord; i <= lastWord; i++) {
int firstBit = i > firstWord ? 0 : start & bitsMask;
int lastBit = i < lastWord ? bitsPerWord - 1 : end & bitsMask;
int mask;
if (firstBit == 0 && lastBit == logBits) {
mask = std::numeric_limits<unsigned int>::max();
mask = std::numeric_limits<int>::max();
} else {
mask = 0;
for (size_t j = firstBit; j <= lastBit; j++) {
for (int j = firstBit; j <= lastBit; j++) {
mask |= 1 << j;
}
}
row->setBulk((i - firstWord) << logBits, (bits_[i] & mask) >> bitOffset);
if (firstBit == 0 && bitOffset != 0) {
unsigned int prevBulk = row->getBitArray()[i - firstWord - 1];
int prevBulk = row->getBitArray()[i - firstWord - 1];
prevBulk |= (bits_[i] & mask) << (bitsPerWord - bitOffset);
row->setBulk((i - firstWord - 1) << logBits, prevBulk);
}
@ -122,26 +121,26 @@ Ref<BitArray> BitMatrix::getRow(int y, Ref<BitArray> row) {
return row;
}
size_t BitMatrix::getWidth() const {
int BitMatrix::getWidth() const {
return width_;
}
size_t BitMatrix::getHeight() const {
int BitMatrix::getHeight() const {
return height_;
}
size_t BitMatrix::getDimension() const {
int BitMatrix::getDimension() const {
return width_;
}
unsigned int* BitMatrix::getBits() const {
ArrayRef<int> BitMatrix::getBits() const {
return bits_;
}
namespace zxing {
ostream& operator<<(ostream &out, const BitMatrix &bm) {
for (size_t y = 0; y < bm.height_; y++) {
for (size_t x = 0; x < bm.width_; x++) {
for (int y = 0; y < bm.height_; y++) {
for (int x = 0; x < bm.width_; x++) {
out << (bm.get(x, y) ? "X " : " ");
}
out << "\n";

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -20,24 +20,24 @@
* limitations under the License.
*/
#include <vector>
#include <zxing/common/Counted.h>
#include <zxing/common/Array.h>
#include <zxing/common/BitMatrix.h>
#include <zxing/ResultPoint.h>
namespace zxing {
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 DetectorResult;
}
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__

View file

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

View file

@ -1,3 +1,4 @@
// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*-
/*
* GreyscaleLuminanceSource.cpp
* zxing
@ -21,50 +22,90 @@
#include <zxing/common/GreyscaleRotatedLuminanceSource.h>
#include <zxing/common/IllegalArgumentException.h>
namespace zxing {
GreyscaleLuminanceSource::GreyscaleLuminanceSource(unsigned char* greyData, int dataWidth,
int dataHeight, int left, int top, int width, int height) : greyData_(greyData),
dataWidth_(dataWidth), dataHeight_(dataHeight), left_(left), top_(top), width_(width),
height_(height) {
using zxing::Ref;
using zxing::ArrayRef;
using zxing::LuminanceSource;
using zxing::GreyscaleLuminanceSource;
GreyscaleLuminanceSource::
GreyscaleLuminanceSource(ArrayRef<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) {
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()) {
throw IllegalArgumentException("Requested row is outside the image.");
}
int width = getWidth();
// TODO(flyashi): determine if row has enough size.
if (row == NULL) {
row = new unsigned char[width_];
if (!row || row.size() < width) {
ArrayRef<char> temp (width);
row = temp;
}
int offset = (y + top_) * dataWidth_ + left_;
memcpy(row, &greyData_[offset], width);
memcpy(&row[0], &greyData_[offset], width);
return row;
}
unsigned char* GreyscaleLuminanceSource::getMatrix() {
ArrayRef<char> GreyscaleLuminanceSource::getMatrix() {
int size = width_ * height_;
unsigned char* result = new unsigned char[size];
ArrayRef<char> result (size);
if (left_ == 0 && top_ == 0 && dataWidth_ == width_ && dataHeight_ == height_) {
memcpy(result, greyData_, size);
memcpy(&result[0], &greyData_[0], size);
} else {
for (int row = 0; row < height_; row++) {
memcpy(result + row * width_, greyData_ + (top_ + row) * dataWidth_ + left_, width_);
memcpy(&result[row * width_], &greyData_[(top_ + row) * dataWidth_ + left_], width_);
}
}
return result;
}
Ref<LuminanceSource> GreyscaleLuminanceSource::rotateCounterClockwise() {
// 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_));
}
extern "C" void abort();
} /* 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__
#define __GREYSCALE_LUMINANCE_SOURCE__
/*
@ -22,11 +23,13 @@
#include <zxing/LuminanceSource.h>
namespace zxing {
class GreyscaleLuminanceSource;
}
class GreyscaleLuminanceSource : public LuminanceSource {
class zxing::GreyscaleLuminanceSource : public LuminanceSource {
private:
unsigned char* greyData_;
private:
ArrayRef<char> greyData_;
int dataWidth_;
int dataHeight_;
int left_;
@ -34,12 +37,12 @@ class GreyscaleLuminanceSource : public LuminanceSource {
int width_;
int height_;
public:
GreyscaleLuminanceSource(unsigned char* greyData, int dataWidth, int dataHeight, int left,
int top, int width, int height);
public:
GreyscaleLuminanceSource(ArrayRef<char> greyData, int dataWidth, int dataHeight, int left,
int top, int width, int height);
unsigned char* getRow(int y, unsigned char* row);
unsigned char* getMatrix();
ArrayRef<char> getRow(int y, ArrayRef<char> row);
ArrayRef<char> getMatrix();
bool isRotateSupported() const {
return true;
@ -57,6 +60,4 @@ class GreyscaleLuminanceSource : public LuminanceSource {
};
} /* namespace */
#endif

View file

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

View file

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

View file

@ -59,7 +59,7 @@ Ref<BitMatrix> HybridBinarizer::getBlackMatrix() {
int width = source.getWidth();
int height = source.getHeight();
if (width >= MINIMUM_DIMENSION && height >= MINIMUM_DIMENSION) {
unsigned char* luminances = source.getMatrix();
ArrayRef<char> luminances = source.getMatrix();
int subWidth = width >> BLOCK_SIZE_POWER;
if ((width & BLOCK_SIZE_MASK) != 0) {
subWidth++;
@ -68,7 +68,7 @@ Ref<BitMatrix> HybridBinarizer::getBlackMatrix() {
if ((height & BLOCK_SIZE_MASK) != 0) {
subHeight++;
}
int* blackPoints =
ArrayRef<int> blackPoints =
calculateBlackPoints(luminances, subWidth, subHeight, width, height);
Ref<BitMatrix> newMatrix (new BitMatrix(width, height));
@ -80,13 +80,6 @@ Ref<BitMatrix> HybridBinarizer::getBlackMatrix() {
blackPoints,
newMatrix);
matrix_ = newMatrix;
// N.B.: these deletes are inadequate if anything between the new
// and this point can throw. As of this writing, it doesn't look
// like they do.
delete [] blackPoints;
delete [] luminances;
} else {
// If the image is too small, fall back to the global histogram approach.
matrix_ = GlobalHistogramBinarizer::getBlackMatrix();
@ -101,12 +94,12 @@ namespace {
}
void
HybridBinarizer::calculateThresholdForBlock(unsigned char* luminances,
HybridBinarizer::calculateThresholdForBlock(ArrayRef<char> luminances,
int subWidth,
int subHeight,
int width,
int height,
int blackPoints[],
ArrayRef<int> blackPoints,
Ref<BitMatrix> const& matrix) {
for (int y = 0; y < subHeight; y++) {
int yoffset = y << BLOCK_SIZE_POWER;
@ -137,7 +130,7 @@ HybridBinarizer::calculateThresholdForBlock(unsigned char* luminances,
}
}
void HybridBinarizer::thresholdBlock(unsigned char* luminances,
void HybridBinarizer::thresholdBlock(ArrayRef<char> luminances,
int xoffset,
int yoffset,
int threshold,
@ -156,7 +149,7 @@ void HybridBinarizer::thresholdBlock(unsigned char* luminances,
}
namespace {
inline int getBlackPointFromNeighbors(int* blackPoints, int subWidth, int x, int y) {
inline int getBlackPointFromNeighbors(ArrayRef<int> blackPoints, int subWidth, int x, int y) {
return (blackPoints[(y-1)*subWidth+x] +
2*blackPoints[y*subWidth+x-1] +
blackPoints[(y-1)*subWidth+x-1]) >> 2;
@ -164,14 +157,14 @@ namespace {
}
int* HybridBinarizer::calculateBlackPoints(unsigned char* luminances,
int subWidth,
int subHeight,
int width,
int height) {
ArrayRef<int> HybridBinarizer::calculateBlackPoints(ArrayRef<char> luminances,
int subWidth,
int subHeight,
int width,
int height) {
const int minDynamicRange = 24;
int *blackPoints = new int[subHeight * subWidth];
ArrayRef<int> blackPoints (subHeight * subWidth);
for (int y = 0; y < subHeight; y++) {
int yoffset = y << BLOCK_SIZE_POWER;
int maxYOffset = height - BLOCK_SIZE;

View file

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

View file

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

View file

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

View file

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

View file

@ -46,7 +46,7 @@ public:
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

View file

@ -28,27 +28,28 @@
namespace zxing {
class GenericGF;
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 GenericGFPoly;
}
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
* zxing
@ -25,36 +26,23 @@
#include <zxing/common/reedsolomon/ReedSolomonException.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) :
field(fld) {
field(fld) {
}
ReedSolomonDecoder::~ReedSolomonDecoder() {
}
void ReedSolomonDecoder::decode(ArrayRef<int> received, int twoS) {
Ref<GenericGFPoly> poly(new GenericGFPoly(field, received));
/*
#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
ArrayRef<int> syndromeCoefficients(twoS);
bool dataMatrix = (field.object_ == GenericGF::DATA_MATRIX_FIELD_256.object_);
bool noError = true;
for (int i = 0; i < twoS; i++) {
@ -67,17 +55,18 @@ void ReedSolomonDecoder::decode(ArrayRef<int> received, int twoS) {
if (noError) {
return;
}
Ref<GenericGFPoly> syndrome(new GenericGFPoly(field, syndromeCoefficients));
Ref<GenericGFPoly> monomial = field->buildMonomial(twoS, 1);
vector<Ref<GenericGFPoly> > sigmaOmega = runEuclideanAlgorithm(monomial, syndrome, twoS);
ArrayRef<int> errorLocations = findErrorLocations(sigmaOmega[0]);
ArrayRef<int> errorMagitudes = findErrorMagnitudes(sigmaOmega[1], errorLocations, dataMatrix);
for (unsigned i = 0; i < errorLocations->size(); i++) {
vector<Ref<GenericGFPoly> > sigmaOmega =
runEuclideanAlgorithm(field->buildMonomial(twoS, 1), syndrome, twoS);
Ref<GenericGFPoly> sigma = sigmaOmega[0];
Ref<GenericGFPoly> omega = sigmaOmega[1];
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]);
//TODO: check why the position would be invalid
if (position < 0 || (size_t)position >= received.size())
throw IllegalArgumentException("Invalid position (ReedSolomonDecoder)");
if (position < 0) {
throw ReedSolomonException("Bad error location");
}
received[position] = GenericGF::addOrSubtract(received[position], errorMagitudes[i]);
}
}
@ -137,12 +126,12 @@ vector<Ref<GenericGFPoly> > ReedSolomonDecoder::runEuclideanAlgorithm(Ref<Generi
/*
#ifdef DEBUG
#ifdef DEBUG
cout << "t = " << *t << endl;
cout << "r = " << *r << "\n";
cout << "sigma = " << *sigma << endl;
cout << "omega = " << *omega << endl;
#endif
#endif
*/
vector<Ref<GenericGFPoly> > result(2);
@ -184,15 +173,14 @@ ArrayRef<int> ReedSolomonDecoder::findErrorMagnitudes(Ref<GenericGFPoly> errorEv
for (int j = 0; j < s; j++) {
if (i != j) {
denominator = field->multiply(denominator, GenericGF::addOrSubtract(1, field->multiply(errorLocations[j],
xiInverse)));
xiInverse)));
}
}
result[i] = field->multiply(errorEvaluator->evaluateAt(xiInverse), field->inverse(denominator));
if (dataMatrix) {
result[i] = field->multiply(result[i], xiInverse);
}
}
}
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;
#endif
std::vector<Ref<ResultPoint> > points(detectorResult->getPoints());
ArrayRef< Ref<ResultPoint> > points(detectorResult->getPoints());
#ifdef DEBUG
@ -69,7 +69,7 @@ Ref<Result> DataMatrixReader::decode(Ref<BinaryBitmap> image, DecodeHints hints)
#endif
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
cout << "(5) created result " << result.object_ << ", returning\n" << flush;
#endif

View file

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

View file

@ -41,7 +41,7 @@ private:
public:
BitMatrixParser(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);
private:

View file

@ -26,7 +26,7 @@ namespace datamatrix {
using namespace std;
DataBlock::DataBlock(int numDataCodewords, ArrayRef<unsigned char> codewords) :
DataBlock::DataBlock(int numDataCodewords, ArrayRef<char> codewords) :
numDataCodewords_(numDataCodewords), codewords_(codewords) {
}
@ -34,11 +34,11 @@ int DataBlock::getNumDataCodewords() {
return numDataCodewords_;
}
ArrayRef<unsigned char> DataBlock::getCodewords() {
ArrayRef<char> DataBlock::getCodewords() {
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
// error correction level
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++) {
int numDataCodewords = ecBlock->getDataCodewords();
int numBlockCodewords = ecBlocks->getECCodewords() + numDataCodewords;
ArrayRef<unsigned char> buffer(numBlockCodewords);
ArrayRef<char> buffer(numBlockCodewords);
Ref<DataBlock> blockRef(new DataBlock(numDataCodewords, buffer));
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");
}

View file

@ -32,15 +32,15 @@ namespace datamatrix {
class DataBlock : public Counted {
private:
int numDataCodewords_;
ArrayRef<unsigned char> codewords_;
ArrayRef<char> codewords_;
DataBlock(int numDataCodewords, ArrayRef<unsigned char> codewords);
DataBlock(int numDataCodewords, ArrayRef<char> codewords);
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();
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
};
Ref<DecoderResult> DecodedBitStreamParser::decode(ArrayRef<unsigned char> bytes) {
Ref<DecoderResult> DecodedBitStreamParser::decode(ArrayRef<char> bytes) {
Ref<BitSource> bits(new BitSource(bytes));
ostringstream result;
ostringstream resultTrailer;
vector<unsigned char> byteSegments;
vector<char> byteSegments;
int mode = ASCII_ENCODE;
do {
if (mode == ASCII_ENCODE) {
@ -87,7 +87,7 @@ Ref<DecoderResult> DecodedBitStreamParser::decode(ArrayRef<unsigned char> bytes)
if (resultTrailer.str().size() > 0) {
result << resultTrailer.str();
}
ArrayRef<unsigned char> rawBytes(bytes);
ArrayRef<char> rawBytes(bytes);
Ref<String> text(new String(result.str()));
return Ref<DecoderResult>(new DecoderResult(rawBytes, text));
}
@ -381,7 +381,7 @@ void DecodedBitStreamParser::decodeEdifactSegment(Ref<BitSource> bits, ostringst
} 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.
int codewordPosition = 1 + bits->getByteOffset(); // position is 1-indexed
int d1 = unrandomize255State(bits->readBits(8), codewordPosition++);
@ -399,7 +399,7 @@ void DecodedBitStreamParser::decodeBase256Segment(Ref<BitSource> bits, ostringst
throw FormatException("NegativeArraySizeException");
}
unsigned char* bytes = new unsigned char[count];
char* bytes = new char[count];
for (int i = 0; i < count; i++) {
// Have seen this particular error in the wild, such as at
// http://www.bcgen.com/demo/IDAutomationStreamingDataMatrix.aspx?MODE=3&D=Fred&PFMT=3&PT=F&X=0.3&O=0&LM=0.2

View file

@ -79,23 +79,23 @@ private:
/**
* 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);
/**
* See ISO 16022:2006, Annex B, B.2
*/
unsigned char unrandomize255State(int randomizedBase256Codeword,
int base256CodewordPosition) {
char unrandomize255State(int randomizedBase256Codeword,
int base256CodewordPosition) {
int pseudoRandomNumber = ((149 * base256CodewordPosition) % 255) + 1;
int tempVariable = randomizedBase256Codeword - pseudoRandomNumber;
return (unsigned char) (tempVariable >= 0 ? tempVariable : (tempVariable + 256));
return (char) (tempVariable >= 0 ? tempVariable : (tempVariable + 256));
};
void append(std::ostream &ost, const unsigned char *bufIn, size_t nIn, const char *src);
void append(std::ostream &ost, const char *bufIn, size_t nIn, const char *src);
public:
DecodedBitStreamParser() { };
Ref<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();
ArrayRef<int> codewordInts(numCodewords);
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
// We don't care about errors in the error-correction codewords
for (int i = 0; i < numDataCodewords; i++) {
codewordBytes[i] = (unsigned char)codewordInts[i];
codewordBytes[i] = (char)codewordInts[i];
}
}
@ -62,7 +62,7 @@ Ref<DecoderResult> Decoder::decode(Ref<BitMatrix> bits) {
Version *version = parser.readVersion(bits);
// Read codewords
ArrayRef<unsigned char> codewords(parser.readCodewords());
ArrayRef<char> codewords(parser.readCodewords());
// Separate into data blocks
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++) {
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
for (int j = 0; j < dataBlocksCount; j++) {
Ref<DataBlock> dataBlock(dataBlocks[j]);
ArrayRef<unsigned char> codewordBytes = dataBlock->getCodewords();
ArrayRef<char> codewordBytes = dataBlock->getCodewords();
int numDataCodewords = dataBlock->getNumDataCodewords();
correctErrors(codewordBytes, numDataCodewords);
for (int i = 0; i < numDataCodewords; i++) {

View file

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

View file

@ -245,7 +245,7 @@ Ref<DetectorResult> Detector::detect() {
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[1].reset(bottomLeft);
points[2].reset(correctedTopRight);

View file

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

View file

@ -36,10 +36,10 @@ std::vector<Ref<Result> > QRCodeMultiReader::decodeMultiple(Ref<BinaryBitmap> im
for (unsigned int i = 0; i < detectorResult.size(); i++) {
try {
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(),
decoderResult->getRawBytes(),
points, BarcodeFormat_QR_CODE));
points, BarcodeFormat::QR_CODE));
// result->putMetadata(ResultMetadataType.BYTE_SEGMENTS, decoderResult->getByteSegments());
// result->putMetadata(ResultMetadataType.ERROR_CORRECTION_LEVEL, decoderResult->getECLevel().toString());
results.push_back(result);

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

View file

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

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 <zxing/ReaderException.h>
#include <zxing/NotFoundException.h>
namespace zxing {
namespace oned {
using std::vector;
using zxing::Ref;
using zxing::BitArray;
using zxing::oned::EAN13Reader;
static const int FIRST_DIGIT_ENCODINGS[10] = {
0x00, 0x0B, 0x0D, 0xE, 0x13, 0x19, 0x1C, 0x15, 0x16, 0x1A
};
namespace {
const int FIRST_DIGIT_ENCODINGS[10] = {
0x00, 0x0B, 0x0D, 0xE, 0x13, 0x19, 0x1C, 0x15, 0x16, 0x1A
};
}
EAN13Reader::EAN13Reader() { }
EAN13Reader::EAN13Reader() : decodeMiddleCounters(4, 0) { }
int EAN13Reader::decodeMiddle(Ref<BitArray> row, int startGuardBegin, int startGuardEnd,
std::string& resultString) {
(void)startGuardBegin;
const int countersLen = 4;
int counters[countersLen] = { 0, 0, 0, 0 };
int EAN13Reader::decodeMiddle(Ref<BitArray> row,
Range const& startRange,
std::string& resultString) {
if (false) {
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 rowOffset = startGuardEnd;
int lgPatternFound = 0;
int lgPatternFound = 0;
for (int x = 0; x < 6 && rowOffset < end; x++) {
int bestMatch = decodeDigit(row, counters, countersLen, rowOffset,
UPC_EAN_PATTERNS_L_AND_G_PATTERNS);
if (bestMatch < 0) {
return -1;
}
resultString.append(1, (char) ('0' + bestMatch % 10));
for (int i = 0; i < countersLen; i++) {
rowOffset += counters[i];
}
if (bestMatch >= 10) {
lgPatternFound |= 1 << (5 - x);
}
}
if (!determineFirstDigit(resultString, lgPatternFound)) {
return -1;
}
int middleRangeStart;
int middleRangeEnd;
if (findGuardPattern(row, rowOffset, true, (int*)getMIDDLE_PATTERN(),
getMIDDLE_PATTERN_LEN(), &middleRangeStart, &middleRangeEnd)) {
rowOffset = middleRangeEnd;
for (int x = 0; x < 6 && rowOffset < end; x++) {
int bestMatch = decodeDigit(row, counters, countersLen, rowOffset,
UPC_EAN_PATTERNS_L_PATTERNS);
if (bestMatch < 0) {
return -1;
}
resultString.append(1, (char) ('0' + bestMatch));
for (int i = 0; i < countersLen; i++) {
rowOffset += counters[i];
}
}
return rowOffset;
}
return -1;
for (int x = 0; x < 6 && rowOffset < end; x++) {
int bestMatch = decodeDigit(row, counters, rowOffset, L_AND_G_PATTERNS);
resultString.append(1, (char) ('0' + bestMatch % 10));
for (int i = 0, end = counters.size(); i <end; i++) {
rowOffset += counters[i];
}
bool EAN13Reader::determineFirstDigit(std::string& resultString, int lgPatternFound) {
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;
if (bestMatch >= 10) {
lgPatternFound |= 1 << (5 - x);
}
}
determineFirstDigit(resultString, lgPatternFound);
Range middleRange = findGuardPattern(row, rowOffset, true, MIDDLE_PATTERN) ;
rowOffset = middleRange[1];
for (int x = 0; x < 6 && rowOffset < end; x++) {
int bestMatch =
decodeDigit(row, counters, rowOffset, L_PATTERNS);
resultString.append(1, (char) ('0' + bestMatch));
for (int i = 0, end = counters.size(); i < end; i++) {
rowOffset += counters[i];
}
}
return rowOffset;
}
void EAN13Reader::determineFirstDigit(std::string& resultString, int lgPatternFound) {
// std::cerr << "K " << resultString << " " << lgPatternFound << " " <<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__
#define __EAN_13_READER_H__
@ -25,20 +26,24 @@
namespace zxing {
namespace oned {
class EAN13Reader : public UPCEANReader {
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 EAN13Reader;
}
}
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

View file

@ -18,55 +18,44 @@
#include "EAN8Reader.h"
#include <zxing/ReaderException.h>
namespace zxing {
namespace oned {
using std::vector;
using zxing::oned::EAN8Reader;
EAN8Reader::EAN8Reader(){ }
EAN8Reader::EAN8Reader() : decodeMiddleCounters(4, 0) { }
int EAN8Reader::decodeMiddle(Ref<BitArray> row, int startGuardBegin, int startGuardEnd,
std::string& resultString){
(void)startGuardBegin;
const int countersLen = 4;
int counters[countersLen] = { 0, 0, 0, 0 };
int EAN8Reader::decodeMiddle(Ref<BitArray> row,
Range const& startRange,
std::string& result){
vector<int>& counters (decodeMiddleCounters);
counters[0] = 0;
counters[1] = 0;
counters[2] = 0;
counters[3] = 0;
int end = row->getSize();
int rowOffset = startGuardEnd;
int end = row->getSize();
int rowOffset = startRange[1];
for (int x = 0; x < 4 && rowOffset < end; x++) {
int bestMatch = decodeDigit(row, counters, countersLen, rowOffset,
UPC_EAN_PATTERNS_L_PATTERNS);
if (bestMatch < 0) {
return -1;
}
resultString.append(1, (char) ('0' + bestMatch));
for (int i = 0; i < countersLen; i++) {
rowOffset += counters[i];
}
}
int middleRangeStart;
int middleRangeEnd;
if (findGuardPattern(row, rowOffset, true, (int*)getMIDDLE_PATTERN(),
getMIDDLE_PATTERN_LEN(), &middleRangeStart, &middleRangeEnd)) {
rowOffset = middleRangeEnd;
for (int x = 0; x < 4 && rowOffset < end; x++) {
int bestMatch = decodeDigit(row, counters, countersLen, rowOffset,
UPC_EAN_PATTERNS_L_PATTERNS);
if (bestMatch < 0) {
return -1;
}
resultString.append(1, (char) ('0' + bestMatch));
for (int i = 0; i < countersLen; i++) {
rowOffset += counters[i];
}
}
return rowOffset;
}
return -1;
}
BarcodeFormat EAN8Reader::getBarcodeFormat(){
return BarcodeFormat_EAN_8;
for (int x = 0; x < 4 && rowOffset < end; x++) {
int bestMatch = decodeDigit(row, counters, rowOffset, L_PATTERNS);
result.append(1, (char) ('0' + bestMatch));
for (int i = 0, end = counters.size(); i < end; i++) {
rowOffset += counters[i];
}
}
Range middleRange =
findGuardPattern(row, rowOffset, true, MIDDLE_PATTERN);
rowOffset = middleRange[1];
for (int x = 0; x < 4 && rowOffset < end; x++) {
int bestMatch = decodeDigit(row, counters, rowOffset, L_PATTERNS);
result.append(1, (char) ('0' + bestMatch));
for (int i = 0, end = counters.size(); i < end; i++) {
rowOffset += counters[i];
}
}
return rowOffset;
}
zxing::BarcodeFormat EAN8Reader::getBarcodeFormat(){
return BarcodeFormat::EAN_8;
}

View file

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

View file

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

View file

@ -1,3 +1,4 @@
// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*-
/*
* MultiFormatOneDReader.cpp
* ZXing
@ -22,45 +23,76 @@
#include <zxing/oned/MultiFormatUPCEANReader.h>
#include <zxing/oned/Code39Reader.h>
#include <zxing/oned/Code128Reader.h>
#include <zxing/oned/Code93Reader.h>
#include <zxing/oned/CodaBarReader.h>
#include <zxing/oned/ITFReader.h>
#include <zxing/ReaderException.h>
#include <zxing/NotFoundException.h>
namespace zxing {
namespace oned {
MultiFormatOneDReader::MultiFormatOneDReader(DecodeHints hints) : readers() {
if (hints.containsFormat(BarcodeFormat_EAN_13) ||
hints.containsFormat(BarcodeFormat_EAN_8) ||
hints.containsFormat(BarcodeFormat_UPC_A) ||
hints.containsFormat(BarcodeFormat_UPC_E)) {
readers.push_back(Ref<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()));
}
}
using zxing::Ref;
using zxing::Result;
using zxing::oned::MultiFormatOneDReader;
Ref<Result> MultiFormatOneDReader::decodeRow(int rowNumber, Ref<BitArray> row) {
int size = readers.size();
for (int i = 0; i < size; i++) {
OneDReader* reader = readers[i];
Ref<Result> result = reader->decodeRow(rowNumber, row);
if (!result.empty()) {
return result;
}
}
return Ref<Result>();
}
MultiFormatOneDReader::MultiFormatOneDReader(DecodeHints hints) : readers() {
if (hints.containsFormat(BarcodeFormat::EAN_13) ||
hints.containsFormat(BarcodeFormat::EAN_8) ||
hints.containsFormat(BarcodeFormat::UPC_A) ||
hints.containsFormat(BarcodeFormat::UPC_E)) {
readers.push_back(Ref<OneDReader>(new MultiFormatUPCEANReader(hints)));
}
if (hints.containsFormat(BarcodeFormat::CODE_39)) {
readers.push_back(Ref<OneDReader>(new Code39Reader()));
}
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
* ZXing
@ -25,63 +26,81 @@
#include <zxing/oned/OneDResultPoint.h>
#include <zxing/common/Array.h>
#include <zxing/ReaderException.h>
#include <zxing/NotFoundException.h>
#include <math.h>
namespace zxing {
namespace oned {
MultiFormatUPCEANReader::MultiFormatUPCEANReader(DecodeHints hints) : readers() {
if (hints.containsFormat(BarcodeFormat_EAN_13)) {
readers.push_back(Ref<OneDReader>(new EAN13Reader()));
} else if (hints.containsFormat(BarcodeFormat_UPC_A)) {
readers.push_back(Ref<OneDReader>(new UPCAReader()));
}
if (hints.containsFormat(BarcodeFormat_EAN_8)) {
readers.push_back(Ref<OneDReader>(new EAN8Reader()));
}
if (hints.containsFormat(BarcodeFormat_UPC_E)) {
readers.push_back(Ref<OneDReader>(new UPCEReader()));
}
if (readers.size() == 0) {
readers.push_back(Ref<OneDReader>(new EAN13Reader()));
// UPC-A is covered by EAN-13
readers.push_back(Ref<OneDReader>(new EAN8Reader()));
readers.push_back(Ref<OneDReader>(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>();
}
using zxing::NotFoundException;
using zxing::Ref;
using zxing::Result;
using zxing::oned::MultiFormatUPCEANReader;
MultiFormatUPCEANReader::MultiFormatUPCEANReader(DecodeHints hints) : readers() {
if (hints.containsFormat(BarcodeFormat::EAN_13)) {
readers.push_back(Ref<UPCEANReader>(new EAN13Reader()));
} else if (hints.containsFormat(BarcodeFormat::UPC_A)) {
readers.push_back(Ref<UPCEANReader>(new UPCAReader()));
}
if (hints.containsFormat(BarcodeFormat::EAN_8)) {
readers.push_back(Ref<UPCEANReader>(new EAN8Reader()));
}
if (hints.containsFormat(BarcodeFormat::UPC_E)) {
readers.push_back(Ref<UPCEANReader>(new UPCEReader()));
}
if (readers.size() == 0) {
readers.push_back(Ref<UPCEANReader>(new EAN13Reader()));
// UPC-A is covered by EAN-13
readers.push_back(Ref<UPCEANReader>(new EAN8Reader()));
readers.push_back(Ref<UPCEANReader>(new UPCEReader()));
}
}
#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__
#define __MULTI_FORMAT_UPC_EAN_READER_H__
/*
@ -23,16 +24,17 @@
namespace zxing {
namespace oned {
class MultiFormatUPCEANReader : public OneDReader {
private:
std::vector<Ref<OneDReader> > readers;
public:
MultiFormatUPCEANReader(DecodeHints hints);
Ref<Result> decodeRow(int rowNumber, Ref<BitArray> row);
};
class UPCEANReader;
class MultiFormatUPCEANReader;
}
}
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

View file

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

View file

@ -1,3 +1,4 @@
// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*-
/*
* UPCAReader.cpp
* ZXing
@ -20,46 +21,47 @@
#include "UPCAReader.h"
#include <zxing/ReaderException.h>
namespace zxing {
namespace oned {
UPCAReader::UPCAReader() : ean13Reader() {
}
using zxing::oned::UPCAReader;
using zxing::Ref;
using zxing::Result;
Ref<Result> UPCAReader::decodeRow(int rowNumber, Ref<BitArray> row) {
return maybeReturnResult(ean13Reader.decodeRow(rowNumber, row));
}
Ref<Result> UPCAReader::decodeRow(int rowNumber, Ref<BitArray> row, int startGuardBegin,
int startGuardEnd) {
return maybeReturnResult(ean13Reader.decodeRow(rowNumber, row, startGuardBegin,
startGuardEnd));
}
Ref<Result> UPCAReader::decode(Ref<BinaryBitmap> image, DecodeHints hints) {
return maybeReturnResult(ean13Reader.decode(image, hints));
}
int UPCAReader::decodeMiddle(Ref<BitArray> row, int startGuardBegin, int startGuardEnd,
std::string& resultString) {
return ean13Reader.decodeMiddle(row, startGuardBegin, startGuardEnd, resultString);
}
Ref<Result> UPCAReader::maybeReturnResult(Ref<Result> result) {
if (result.empty()) {
return result;
}
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 Ref<Result>();
}
BarcodeFormat UPCAReader::getBarcodeFormat(){
return BarcodeFormat_UPC_A;
}
}
UPCAReader::UPCAReader() : ean13Reader() {
}
Ref<Result> UPCAReader::decodeRow(int rowNumber, Ref<BitArray> row) {
return maybeReturnResult(ean13Reader.decodeRow(rowNumber, row));
}
Ref<Result> UPCAReader::decodeRow(int rowNumber,
Ref<BitArray> row,
Range const& startGuardRange) {
return maybeReturnResult(ean13Reader.decodeRow(rowNumber, row, startGuardRange));
}
Ref<Result> UPCAReader::decode(Ref<BinaryBitmap> image, DecodeHints hints) {
return maybeReturnResult(ean13Reader.decode(image, hints));
}
int UPCAReader::decodeMiddle(Ref<BitArray> row,
Range const& startRange,
std::string& resultString) {
return ean13Reader.decodeMiddle(row, startRange, resultString);
}
Ref<Result> UPCAReader::maybeReturnResult(Ref<Result> result) {
if (result.empty()) {
return result;
}
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 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__
#define __UPCA_READER_H__
/*
@ -24,26 +25,26 @@
namespace zxing {
namespace oned {
class UPCAReader : public UPCEANReader {
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 UPCAReader;
}
}
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

View file

@ -1,3 +1,4 @@
// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*-
/*
* UPCEANReader.cpp
* ZXing
@ -20,292 +21,280 @@
#include "UPCEANReader.h"
#include <zxing/oned/OneDResultPoint.h>
#include <zxing/ReaderException.h>
#include <zxing/NotFoundException.h>
#include <zxing/ChecksumException.h>
namespace zxing {
namespace oned {
using zxing::Ref;
using zxing::Result;
using zxing::NotFoundException;
using zxing::ChecksumException;
using zxing::oned::UPCEANReader;
using namespace std; // remove
/**
* Start/end guard pattern.
*/
static const int START_END_PATTERN[3] = {1, 1, 1};
#define LEN(v) ((int)(sizeof(v)/sizeof(v[0])))
/**
* Pattern marking the middle of a UPC/EAN pattern, separating the two halves.
*/
static const int MIDDLE_PATTERN_LEN = 5;
static const int MIDDLE_PATTERN[MIDDLE_PATTERN_LEN] = {1, 1, 1, 1, 1};
namespace {
/**
* "Odd", or "L" patterns used to encode UPC/EAN digits.
*/
const int L_PATTERNS_LEN = 10;
const int L_PATTERNS_SUB_LEN = 4;
const int L_PATTERNS[L_PATTERNS_LEN][L_PATTERNS_SUB_LEN] = {
{3, 2, 1, 1}, // 0
{2, 2, 2, 1}, // 1
{2, 1, 2, 2}, // 2
{1, 4, 1, 1}, // 3
{1, 1, 3, 2}, // 4
{1, 2, 3, 1}, // 5
{1, 1, 1, 4}, // 6
{1, 3, 1, 2}, // 7
{1, 2, 1, 3}, // 8
{3, 1, 1, 2} // 9
};
/**
* Start/end guard pattern.
*/
const int START_END_PATTERN_[] = {1, 1, 1};
const int START_END_PATTERN_LEN = LEN(START_END_PATTERN_);
/**
* As above but also including the "even", or "G" patterns used to encode UPC/EAN digits.
*/
const int L_AND_G_PATTERNS_LEN = 20;
const int L_AND_G_PATTERNS_SUB_LEN = 4;
const int L_AND_G_PATTERNS[L_AND_G_PATTERNS_LEN][L_AND_G_PATTERNS_SUB_LEN] = {
{3, 2, 1, 1}, // 0
{2, 2, 2, 1}, // 1
{2, 1, 2, 2}, // 2
{1, 4, 1, 1}, // 3
{1, 1, 3, 2}, // 4
{1, 2, 3, 1}, // 5
{1, 1, 1, 4}, // 6
{1, 3, 1, 2}, // 7
{1, 2, 1, 3}, // 8
{3, 1, 1, 2}, // 9
{1, 1, 2, 3}, // 10 reversed 0
{1, 2, 2, 2}, // 11 reversed 1
{2, 2, 1, 2}, // 12 reversed 2
{1, 1, 4, 1}, // 13 reversed 3
{2, 3, 1, 1}, // 14 reversed 4
{1, 3, 2, 1}, // 15 reversed 5
{4, 1, 1, 1}, // 16 reversed 6
{2, 1, 3, 1}, // 17 reversed 7
{3, 1, 2, 1}, // 18 reversed 8
{2, 1, 1, 3} // 19 reversed 9
};
/**
* Pattern marking the middle of a UPC/EAN pattern, separating the two halves.
*/
const int MIDDLE_PATTERN_[] = {1, 1, 1, 1, 1};
const int MIDDLE_PATTERN_LEN = LEN(MIDDLE_PATTERN_);
/**
* "Odd", or "L" patterns used to encode UPC/EAN digits.
*/
const int L_PATTERNS_[][4] = {
{3, 2, 1, 1}, // 0
{2, 2, 2, 1}, // 1
{2, 1, 2, 2}, // 2
{1, 4, 1, 1}, // 3
{1, 1, 3, 2}, // 4
{1, 2, 3, 1}, // 5
{1, 1, 1, 4}, // 6
{1, 3, 1, 2}, // 7
{1, 2, 1, 3}, // 8
{3, 1, 1, 2} // 9
};
const int L_PATTERNS_LEN = LEN(L_PATTERNS_);
int UPCEANReader::getMIDDLE_PATTERN_LEN() {
return MIDDLE_PATTERN_LEN;
/**
* As above but also including the "even", or "G" patterns used to encode UPC/EAN digits.
*/
const int L_AND_G_PATTERNS_[][4] = {
{3, 2, 1, 1}, // 0
{2, 2, 2, 1}, // 1
{2, 1, 2, 2}, // 2
{1, 4, 1, 1}, // 3
{1, 1, 3, 2}, // 4
{1, 2, 3, 1}, // 5
{1, 1, 1, 4}, // 6
{1, 3, 1, 2}, // 7
{1, 2, 1, 3}, // 8
{3, 1, 1, 2}, // 9
{1, 1, 2, 3}, // 10 reversed 0
{1, 2, 2, 2}, // 11 reversed 1
{2, 2, 1, 2}, // 12 reversed 2
{1, 1, 4, 1}, // 13 reversed 3
{2, 3, 1, 1}, // 14 reversed 4
{1, 3, 2, 1}, // 15 reversed 5
{4, 1, 1, 1}, // 16 reversed 6
{2, 1, 3, 1}, // 17 reversed 7
{3, 1, 2, 1}, // 18 reversed 8
{2, 1, 1, 3} // 19 reversed 9
};
const int L_AND_G_PATTERNS_LEN = LEN(L_AND_G_PATTERNS_);
}
const int UPCEANReader::MAX_AVG_VARIANCE = (int)(PATTERN_MATCH_RESULT_SCALE_FACTOR * 0.48f);
const int UPCEANReader::MAX_INDIVIDUAL_VARIANCE = (int)(PATTERN_MATCH_RESULT_SCALE_FACTOR * 0.7f);
#define VECTOR_INIT(v) v, v + sizeof(v)/sizeof(v[0])
const vector<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;
}
const int* UPCEANReader::getMIDDLE_PATTERN() {
return MIDDLE_PATTERN;
}
UPCEANReader::UPCEANReader() {
}
Ref<Result> UPCEANReader::decodeRow(int rowNumber, Ref<BitArray> row) {
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() {
startRange = findGuardPattern(row, nextStart, false, START_END_PATTERN, counters);
// std::cerr << "sr " << startRange[0] << " " << startRange[1] << std::endl;
int start = startRange[0];
nextStart = startRange[1];
// Make sure there is a quiet zone at least as big as the start pattern before the barcode.
// If this check would run off the left edge of the image, do not accept this barcode,
// as it is very likely to be a false positive.
int quietStart = start - (nextStart - start);
if (quietStart >= 0) {
foundStart = row->isRange(quietStart, start, false);
}
}
return startRange;
}
UPCEANReader::Range UPCEANReader::findGuardPattern(Ref<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/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 oned {
class UPCEANReader : public OneDReader {
private:
enum {MAX_AVG_VARIANCE = (unsigned int) (PATTERN_MATCH_RESULT_SCALE_FACTOR * 420/1000)};
enum {MAX_INDIVIDUAL_VARIANCE = (int) (PATTERN_MATCH_RESULT_SCALE_FACTOR * 700/1000)};
static bool findStartGuardPattern(Ref<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 MultiFormatUPCEANReader;
class UPCEANReader;
}
}
class zxing::oned::UPCEANReader : public OneDReader {
friend class MultiFormatUPCEANReader;
private:
std::string decodeRowStringBuffer;
// UPCEANExtensionSupport extensionReader;
// EANManufacturerOrgSupport eanManSupport;
static const int MAX_AVG_VARIANCE;
static const int MAX_INDIVIDUAL_VARIANCE;
static Range findStartGuardPattern(Ref<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

View file

@ -18,125 +18,125 @@
#include "UPCEReader.h"
#include <zxing/ReaderException.h>
namespace zxing {
namespace oned {
using std::string;
using std::vector;
using zxing::Ref;
using zxing::String;
using zxing::oned::UPCEReader;
/**
* The pattern that marks the middle, and end, of a UPC-E pattern.
* There is no "second half" to a UPC-E barcode.
*/
static const int MIDDLE_END_PATTERN[6] = {1, 1, 1, 1, 1, 1};
#define VECTOR_INIT(v) v, v + sizeof(v)/sizeof(v[0])
/**
* See {@link #L_AND_G_PATTERNS}; these values similarly represent patterns of
* even-odd parity encodings of digits that imply both the number system (0 or 1)
* used, and the check digit.
*/
static const int NUMSYS_AND_CHECK_DIGIT_PATTERNS[2][10] = {
{0x38, 0x34, 0x32, 0x31, 0x2C, 0x26, 0x23, 0x2A, 0x29, 0x25},
{0x07, 0x0B, 0x0D, 0x0E, 0x13, 0x19, 0x1C, 0x15, 0x16, 0x1A}
};
namespace {
/**
* The pattern that marks the middle, and end, of a UPC-E pattern.
* There is no "second half" to a UPC-E barcode.
*/
const int MIDDLE_END_PATTERN_[6] = {1, 1, 1, 1, 1, 1};
const vector<int> MIDDLE_END_PATTERN (VECTOR_INIT(MIDDLE_END_PATTERN_));
UPCEReader::UPCEReader() {
/**
* See {@link #L_AND_G_PATTERNS}; these values similarly represent patterns of
* even-odd parity encodings of digits that imply both the number system (0 or 1)
* used, and the check digit.
*/
const int NUMSYS_AND_CHECK_DIGIT_PATTERNS[2][10] = {
{0x38, 0x34, 0x32, 0x31, 0x2C, 0x26, 0x23, 0x2A, 0x29, 0x25},
{0x07, 0x0B, 0x0D, 0x0E, 0x13, 0x19, 0x1C, 0x15, 0x16, 0x1A}
};
}
UPCEReader::UPCEReader() {
}
int UPCEReader::decodeMiddle(Ref<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];
}
int UPCEReader::decodeMiddle(Ref<BitArray> row, int startGuardBegin, int startGuardEnd,
std::string& resultString) {
(void)startGuardBegin;
const int countersLen = 4;
int counters[countersLen] = { 0, 0, 0, 0 };
int end = row->getSize();
int rowOffset = startGuardEnd;
int lgPatternFound = 0;
for (int x = 0; x < 6 && rowOffset < end; x++) {
int bestMatch = decodeDigit(row, counters, countersLen, rowOffset,
UPC_EAN_PATTERNS_L_AND_G_PATTERNS);
if (bestMatch < 0) {
return -1;
}
resultString.append(1, (char) ('0' + bestMatch % 10));
for (int i = 0; i < countersLen; i++) {
rowOffset += counters[i];
}
if (bestMatch >= 10) {
lgPatternFound |= 1 << (5 - x);
}
}
if (!determineNumSysAndCheckDigit(resultString, lgPatternFound)) {
return -1;
}
return rowOffset;
}
bool UPCEReader::decodeEnd(Ref<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;
if (bestMatch >= 10) {
lgPatternFound |= 1 << (5 - x);
}
}
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__
#define __UPC_E_READER_H__
@ -22,23 +23,25 @@
namespace zxing {
namespace oned {
class UPCEReader : public UPCEANReader {
private:
static bool determineNumSysAndCheckDigit(std::string& resultString, int lgPatternFound);
protected:
bool decodeEnd(Ref<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 UPCEReader;
}
}
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

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

View file

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

View file

@ -49,8 +49,7 @@ namespace zxing {
cout << "(2) detected, have detectorResult " << detectorResult.object_ << "\n" << flush;
#endif
std::vector<Ref<ResultPoint> > points(detectorResult->getPoints());
ArrayRef< Ref<ResultPoint> > points (detectorResult->getPoints());
#ifdef DEBUG
cout << "(3) extracted points " << &points << "\n" << flush;
@ -68,7 +67,7 @@ namespace zxing {
#endif
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
cout << "(5) created result " << result.object_ << ", returning\n" << flush;
#endif

View file

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

View file

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

View file

@ -26,7 +26,7 @@ namespace qrcode {
using namespace std;
DataBlock::DataBlock(int numDataCodewords, ArrayRef<unsigned char> codewords) :
DataBlock::DataBlock(int numDataCodewords, ArrayRef<char> codewords) :
numDataCodewords_(numDataCodewords), codewords_(codewords) {
}
@ -34,12 +34,12 @@ int DataBlock::getNumDataCodewords() {
return numDataCodewords_;
}
ArrayRef<unsigned char> DataBlock::getCodewords() {
ArrayRef<char> DataBlock::getCodewords() {
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) {
@ -63,7 +63,7 @@ std::vector<Ref<DataBlock> > DataBlock::getDataBlocks(ArrayRef<unsigned char> ra
for (int i = 0; i < ecBlock->getCount(); i++) {
int numDataCodewords = ecBlock->getDataCodewords();
int numBlockCodewords = ecBlocks.getECCodewords() + numDataCodewords;
ArrayRef<unsigned char> buffer(numBlockCodewords);
ArrayRef<char> buffer(numBlockCodewords);
Ref<DataBlock> blockRef(new DataBlock(numDataCodewords, buffer));
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");
}

View file

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

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