finished updating the library files of zxing library. haven't complied it yet.

This commit is contained in:
favoritas37 2013-07-04 16:52:02 +03:00
parent d1fbe4ef20
commit 6e0972273a
28 changed files with 664 additions and 856 deletions

View File

@ -106,7 +106,6 @@ HEADERS += QZXing_global.h \
zxing/qrcode/decoder/DataMask.h \
zxing/qrcode/decoder/DataBlock.h \
zxing/qrcode/decoder/BitMatrixParser.h \
zxing/qrcode/detector/QREdgeDetector.h \
zxing/qrcode/detector/FinderPatternInfo.h \
zxing/qrcode/detector/FinderPatternFinder.h \
zxing/qrcode/detector/FinderPattern.h \
@ -187,7 +186,6 @@ SOURCES += CameraImageWrapper.cpp \
zxing/oned/CodaBarReader.cpp \
zxing/oned/Code93Reader.cpp \
zxing/qrcode/QRCodeReader.cpp \
zxing/qrcode/detector/QREdgeDetector.cpp \
zxing/multi/MultipleBarcodeReader.cpp \
zxing/multi/GenericMultipleBarcodeReader.cpp \
zxing/multi/ByQuadrantReader.cpp \

View File

@ -1,4 +1,8 @@
// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*-
#ifndef __NOT_FOUND_EXCEPTION_H__
#define __NOT_FOUND_EXCEPTION_H__
/*
* Copyright 20011 ZXing authors
*
@ -15,14 +19,17 @@
* limitations under the License.
*/
#include <zxing/NotFoundException.h>
#include <zxing/ReaderException.h>
namespace zxing {
NotFoundException::NotFoundException(const char *msg)
: ReaderException(msg) {}
NotFoundException::~NotFoundException() throw() {
}
class NotFoundException : public ReaderException {
public:
NotFoundException() throw() {}
NotFoundException(const char *msg) throw() : ReaderException(msg) {}
~NotFoundException() throw() {}
};
}
#endif // __NOT_FOUND_EXCEPTION_H__

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

@ -33,46 +33,12 @@ namespace zxing {
}
//TODO: see if any of the other files in the qrcode tree need tryHarder
Ref<Result> QRCodeReader::decode(Ref<BinaryBitmap> image, DecodeHints hints) {
#ifdef DEBUG
cout << "decoding image " << image.object_ << ":\n" << flush;
#endif
Detector detector(image->getBlackMatrix());
#ifdef DEBUG
cout << "(1) created detector " << &detector << "\n" << flush;
#endif
Ref<DetectorResult> detectorResult(detector.detect(hints));
#ifdef DEBUG
cout << "(2) detected, have detectorResult " << detectorResult.object_ << "\n" << flush;
#endif
std::vector<Ref<ResultPoint> > points(detectorResult->getPoints());
#ifdef DEBUG
cout << "(3) extracted points " << &points << "\n" << flush;
cout << "found " << points.size() << " points:\n";
for (size_t i = 0; i < points.size(); i++) {
cout << " " << points[i]->getX() << "," << points[i]->getY() << "\n";
}
cout << "bits:\n";
cout << *(detectorResult->getBits()) << "\n";
#endif
ArrayRef< Ref<ResultPoint> > points (detectorResult->getPoints());
Ref<DecoderResult> decoderResult(decoder_.decode(detectorResult->getBits()));
#ifdef DEBUG
cout << "(4) decoded, have decoderResult " << decoderResult.object_ << "\n" << flush;
#endif
Ref<Result> result(
new Result(decoderResult->getText(), decoderResult->getRawBytes(), points, BarcodeFormat_QR_CODE));
#ifdef DEBUG
cout << "(5) created result " << result.object_ << ", returning\n" << flush;
#endif
new Result(decoderResult->getText(), decoderResult->getRawBytes(), points, BarcodeFormat::QR_CODE));
return result;
}

View File

@ -26,22 +26,23 @@
#include <zxing/DecodeHints.h>
namespace zxing {
namespace qrcode {
namespace qrcode {
class QRCodeReader : public Reader {
private:
Decoder decoder_;
class QRCodeReader : public Reader {
private:
Decoder decoder_;
protected:
Decoder& getDecoder();
protected:
Decoder& getDecoder();
public:
QRCodeReader();
virtual Ref<Result> decode(Ref<BinaryBitmap> image, DecodeHints hints);
virtual ~QRCodeReader();
public:
QRCodeReader();
virtual ~QRCodeReader();
};
}
Ref<Result> decode(Ref<BinaryBitmap> image, DecodeHints hints);
};
}
}
#endif // __QR_CODE_READER_H__

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

@ -20,13 +20,16 @@
#include <zxing/qrcode/Version.h>
#include <zxing/qrcode/FormatInformation.h>
#include <zxing/FormatException.h>
#include <limits>
#include <iostream>
#include <cstdarg>
using std::vector;
using std::numeric_limits;
namespace zxing {
namespace qrcode {
using namespace std;
ECB::ECB(int count, int dataCodewords) :
count_(count), dataCodewords_(dataCodewords) {
@ -94,9 +97,14 @@ ECBlocks& Version::getECBlocksForLevel(ErrorCorrectionLevel &ecLevel) {
Version *Version::getProvisionalVersionForDimension(int dimension) {
if (dimension % 4 != 1) {
throw ReaderException("Dimension must be 1 mod 4");
throw FormatException();
}
try {
return Version::getVersionForNumber((dimension - 17) >> 2);
} catch (IllegalArgumentException const& ignored) {
(void)ignored;
throw FormatException();
}
return Version::getVersionForNumber((dimension - 17) >> 2);
}
Version *Version::getVersionForNumber(int versionNumber) {
@ -196,12 +204,6 @@ Ref<BitMatrix> Version::buildFunctionPattern() {
functionPattern->setRegion(0, dimension - 11, 6, 3);
}
//#ifdef DEBUG
// cout << "version " << versionNumber_ << " built function pattern:\n";
// cout << *functionPattern;
//#endif
return functionPattern;
}
@ -553,5 +555,6 @@ int Version::buildVersions() {
new ECB(61, 16)))));
return VERSIONS.size();
}
}
}

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

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

@ -51,16 +51,16 @@ private:
std::string& result,
int count,
zxing::common::CharacterSetECI* currentCharacterSetECI,
ArrayRef< ArrayRef<unsigned char> >& byteSegments,
ArrayRef< ArrayRef<char> >& byteSegments,
Hashtable const& hints);
static void decodeAlphanumericSegment(Ref<BitSource> bits, std::string &result, int count, bool fc1InEffect);
static void decodeNumericSegment(Ref<BitSource> bits, std::string &result, int count);
static void append(std::string &ost, const unsigned char *bufIn, size_t nIn, const char *src);
static void append(std::string &ost, const char *bufIn, size_t nIn, const char *src);
static void append(std::string &ost, std::string const& in, const char *src);
public:
static Ref<DecoderResult> decode(ArrayRef<unsigned char> bytes,
static Ref<DecoderResult> decode(ArrayRef<char> bytes,
Version *version,
ErrorCorrectionLevel const& ecLevel,
Hashtable const& hints);

View File

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

@ -32,7 +32,6 @@ private:
int characterCountBitsForVersions0To9_;
int characterCountBitsForVersions10To26_;
int characterCountBitsForVersions27AndHigher_;
int bits_;
std::string name_;
Mode(int cbv0_9, int cbv10_26, int cbv27, int bits, char const* name);

View File

@ -31,7 +31,7 @@ int BitMatrixParser::copyBit(size_t x, size_t y, int versionBits) {
BitMatrixParser::BitMatrixParser(Ref<BitMatrix> bitMatrix) :
bitMatrix_(bitMatrix), parsedVersion_(0), parsedFormatInfo_() {
size_t dimension = bitMatrix->getDimension();
size_t dimension = bitMatrix->getHeight();
if ((dimension < 21) || (dimension & 0x03) != 1) {
throw ReaderException("Dimension must be 1 mod 4 and >= 21");
}
@ -57,7 +57,7 @@ Ref<FormatInformation> BitMatrixParser::readFormatInformation() {
}
// Read the top-right/bottom-left pattern
int dimension = bitMatrix_->getDimension();
int dimension = bitMatrix_->getHeight();
int formatInfoBits2 = 0;
int jMin = dimension - 7;
for (int j = dimension - 1; j >= jMin; j--) {
@ -79,7 +79,7 @@ Version *BitMatrixParser::readVersion() {
return parsedVersion_;
}
int dimension = bitMatrix_->getDimension();
int dimension = bitMatrix_->getHeight();
int provisionalVersion = (dimension - 17) >> 2;
if (provisionalVersion <= 6) {
@ -116,19 +116,16 @@ 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();
// cerr << *bitMatrix_ << endl;
// cerr << bitMatrix_->getDimension() << endl;
// Get the data mask for the format used in this QR Code. This will exclude
// some bits from reading as we wind through the bit matrix.
DataMask &dataMask = DataMask::forReference((int)formatInfo->getDataMask());
// cout << (int)formatInfo->getDataMask() << endl;
int dimension = bitMatrix_->getDimension();
int dimension = bitMatrix_->getHeight();
dataMask.unmaskBitMatrix(*bitMatrix_, dimension);
@ -141,7 +138,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 +163,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

@ -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;
}
@ -71,10 +71,10 @@ std::vector<Ref<DataBlock> > DataBlock::getDataBlocks(ArrayRef<unsigned char> ra
// All blocks have the same amount of data, except that the last n
// (where n may be 0) have 1 more byte. Figure out where these start.
int shorterBlocksTotalCodewords = result[0]->codewords_.size();
int shorterBlocksTotalCodewords = result[0]->codewords_->size();
int longerBlocksStartAt = result.size() - 1;
while (longerBlocksStartAt >= 0) {
int numCodewords = result[longerBlocksStartAt]->codewords_.size();
int numCodewords = result[longerBlocksStartAt]->codewords_->size();
if (numCodewords == shorterBlocksTotalCodewords) {
break;
}
@ -99,7 +99,7 @@ std::vector<Ref<DataBlock> > DataBlock::getDataBlocks(ArrayRef<unsigned char> ra
result[j]->codewords_[shorterBlocksNumDataCodewords] = rawCodewords[rawCodewordsOffset++];
}
// Now add in error correction blocks
int max = result[0]->codewords_.size();
int max = result[0]->codewords_->size();
for (int i = shorterBlocksNumDataCodewords; i < max; i++) {
for (int j = 0; j < numResultBlocks; j++) {
int iOffset = j < longerBlocksStartAt ? i : i + 1;
@ -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

@ -24,9 +24,6 @@
#include <zxing/FormatException.h>
#include <zxing/common/StringUtils.h>
#include <iostream>
#include <qglobal.h>
#ifndef NO_ICONV
#include <iconv.h>
#endif
@ -47,370 +44,382 @@ using namespace zxing::qrcode;
using namespace zxing::common;
const char DecodedBitStreamParser::ALPHANUMERIC_CHARS[] =
{ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B',
'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
'Y', 'Z', ' ', '$', '%', '*', '+', '-', '.', '/', ':'
};
{ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B',
'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
'Y', 'Z', ' ', '$', '%', '*', '+', '-', '.', '/', ':'
};
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
if (nIn == 0) {
return;
}
if (nIn == 0) {
return;
}
iconv_t cd = iconv_open(StringUtils::UTF8, src);
if (cd == (iconv_t)-1) {
result.append((const char *)bufIn, nIn);
return;
}
const int maxOut = 4 * nIn + 1;
unsigned char* bufOut = new unsigned char[maxOut];
/*ICONV_CONST*/ char *fromPtr = (/*ICONV_CONST*/ char *)bufIn;
size_t nFrom = nIn;
char *toPtr = (char *)bufOut;
size_t nTo = maxOut;
while (nFrom > 0) {
#if defined(Q_OS_SYMBIAN)
size_t oneway = iconv(cd, (const char**)&fromPtr, &nFrom, &toPtr, &nTo); // for Symbian and Mingw
#else
size_t oneway = iconv(cd, (char**)&fromPtr, &nFrom, &toPtr, &nTo); // for Harmattan
#endif
if (oneway == (size_t)(-1)) {
iconv_close(cd);
delete[] bufOut;
throw ReaderException("error converting characters");
}
}
iconv_close(cd);
int nResult = maxOut - nTo;
bufOut[nResult] = '\0';
result.append((const char *)bufOut);
delete[] bufOut;
#else
iconv_t cd = iconv_open(StringUtils::UTF8, src);
if (cd == (iconv_t)-1) {
result.append((const char *)bufIn, nIn);
return;
}
const int maxOut = 4 * nIn + 1;
char* bufOut = new char[maxOut];
ICONV_CONST char *fromPtr = (ICONV_CONST char *)bufIn;
size_t nFrom = nIn;
char *toPtr = (char *)bufOut;
size_t nTo = maxOut;
while (nFrom > 0) {
size_t oneway = iconv(cd, &fromPtr, &nFrom, &toPtr, &nTo);
if (oneway == (size_t)(-1)) {
iconv_close(cd);
delete[] bufOut;
throw ReaderException("error converting characters");
}
}
iconv_close(cd);
int nResult = maxOut - nTo;
bufOut[nResult] = '\0';
result.append((const char *)bufOut);
delete[] bufOut;
#else
result.append((const char *)bufIn, nIn);
#endif
}
void DecodedBitStreamParser::decodeHanziSegment(Ref<BitSource> bits_,
string& result,
int count) {
BitSource& bits (*bits_);
// Don't crash trying to read more bits than we have available.
if (count * 13 > bits.available()) {
throw FormatException();
}
BitSource& bits (*bits_);
// Don't crash trying to read more bits than we have available.
if (count * 13 > bits.available()) {
throw FormatException();
}
// 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];
int offset = 0;
while (count > 0) {
// Each 13 bits encodes a 2-byte character
int twoBytes = bits.readBits(13);
int assembledTwoBytes = ((twoBytes / 0x060) << 8) | (twoBytes % 0x060);
if (assembledTwoBytes < 0x003BF) {
// In the 0xA1A1 to 0xAAFE range
assembledTwoBytes += 0x0A1A1;
} else {
// In the 0xB0A1 to 0xFAFE range
assembledTwoBytes += 0x0A6A1;
}
buffer[offset] = (unsigned char) ((assembledTwoBytes >> 8) & 0xFF);
buffer[offset + 1] = (unsigned char) (assembledTwoBytes & 0xFF);
offset += 2;
count--;
}
try {
append(result, buffer, nBytes, StringUtils::GB2312);
} catch (ReaderException const& re) {
delete [] buffer;
throw FormatException();
// Each character will require 2 bytes. Read the characters as 2-byte pairs
// and decode as GB2312 afterwards
size_t nBytes = 2 * count;
char* buffer = new char[nBytes];
int offset = 0;
while (count > 0) {
// Each 13 bits encodes a 2-byte character
int twoBytes = bits.readBits(13);
int assembledTwoBytes = ((twoBytes / 0x060) << 8) | (twoBytes % 0x060);
if (assembledTwoBytes < 0x003BF) {
// In the 0xA1A1 to 0xAAFE range
assembledTwoBytes += 0x0A1A1;
} else {
// In the 0xB0A1 to 0xFAFE range
assembledTwoBytes += 0x0A6A1;
}
buffer[offset] = (char) ((assembledTwoBytes >> 8) & 0xFF);
buffer[offset + 1] = (char) (assembledTwoBytes & 0xFF);
offset += 2;
count--;
}
try {
append(result, buffer, nBytes, StringUtils::GB2312);
} catch (ReaderException const& ignored) {
(void)ignored;
delete [] buffer;
throw FormatException();
}
delete [] buffer;
}
void DecodedBitStreamParser::decodeKanjiSegment(Ref<BitSource> bits, std::string &result, int count) {
// Each character will require 2 bytes. Read the characters as 2-byte pairs
// and decode as Shift_JIS afterwards
size_t nBytes = 2 * count;
unsigned char* buffer = new unsigned char[nBytes];
int offset = 0;
while (count > 0) {
// Each 13 bits encodes a 2-byte character
// Each character will require 2 bytes. Read the characters as 2-byte pairs
// and decode as Shift_JIS afterwards
size_t nBytes = 2 * count;
char* buffer = new char[nBytes];
int offset = 0;
while (count > 0) {
// Each 13 bits encodes a 2-byte character
int twoBytes = bits->readBits(13);
int assembledTwoBytes = ((twoBytes / 0x0C0) << 8) | (twoBytes % 0x0C0);
if (assembledTwoBytes < 0x01F00) {
// In the 0x8140 to 0x9FFC range
assembledTwoBytes += 0x08140;
} else {
// In the 0xE040 to 0xEBBF range
assembledTwoBytes += 0x0C140;
}
buffer[offset] = (unsigned char)(assembledTwoBytes >> 8);
buffer[offset + 1] = (unsigned char)assembledTwoBytes;
offset += 2;
count--;
int twoBytes = bits->readBits(13);
int assembledTwoBytes = ((twoBytes / 0x0C0) << 8) | (twoBytes % 0x0C0);
if (assembledTwoBytes < 0x01F00) {
// In the 0x8140 to 0x9FFC range
assembledTwoBytes += 0x08140;
} else {
// In the 0xE040 to 0xEBBF range
assembledTwoBytes += 0x0C140;
}
buffer[offset] = (char)(assembledTwoBytes >> 8);
buffer[offset + 1] = (char)assembledTwoBytes;
offset += 2;
count--;
}
try {
append(result, buffer, nBytes, StringUtils::SHIFT_JIS);
delete[] buffer;
} catch (ReaderException const& ignored) {
(void)ignored;
delete [] buffer;
throw FormatException();
}
delete[] buffer;
}
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_);
// Don't crash trying to read more bits than we have available.
if (count << 3 > bits.available()) {
throw FormatException();
}
int nBytes = count;
BitSource& bits (*bits_);
// Don't crash trying to read more bits than we have available.
if (count << 3 > bits.available()) {
throw FormatException();
}
ArrayRef<unsigned char> bytes_ (count);
unsigned char* readBytes = &(*bytes_)[0];
for (int i = 0; i < count; i++) {
readBytes[i] = (unsigned char) bits.readBits(8);
}
string encoding;
if (currentCharacterSetECI == 0) {
// The spec isn't clear on this mode; see
// section 6.4.5: t does not say which encoding to assuming
// upon decoding. I have seen ISO-8859-1 used as well as
// Shift_JIS -- without anything like an ECI designator to
// give a hint.
encoding = StringUtils::guessEncoding(readBytes, count, hints);
} else {
encoding = currentCharacterSetECI->name();
}
try {
append(result, readBytes, nBytes, encoding.c_str());
} catch (ReaderException const& re) {
throw FormatException();
}
byteSegments->values().push_back(bytes_);
ArrayRef<char> bytes_ (count);
char* readBytes = &(*bytes_)[0];
for (int i = 0; i < count; i++) {
readBytes[i] = (char) bits.readBits(8);
}
string encoding;
if (currentCharacterSetECI == 0) {
// The spec isn't clear on this mode; see
// section 6.4.5: t does not say which encoding to assuming
// upon decoding. I have seen ISO-8859-1 used as well as
// Shift_JIS -- without anything like an ECI designator to
// give a hint.
encoding = StringUtils::guessEncoding(readBytes, count, hints);
} else {
encoding = currentCharacterSetECI->name();
}
try {
append(result, readBytes, nBytes, encoding.c_str());
} catch (ReaderException const& ignored) {
(void)ignored;
throw FormatException();
}
byteSegments->values().push_back(bytes_);
}
void DecodedBitStreamParser::decodeNumericSegment(Ref<BitSource> bits, std::string &result, int count) {
int nBytes = count;
unsigned char* bytes = new unsigned char[nBytes];
int i = 0;
// Read three digits at a time
while (count >= 3) {
// Each 10 bits encodes three digits
if (bits->available() < 10) {
throw ReaderException("format exception");
}
int threeDigitsBits = bits->readBits(10);
if (threeDigitsBits >= 1000) {
ostringstream s;
s << "Illegal value for 3-digit unit: " << threeDigitsBits;
delete[] bytes;
throw ReaderException(s.str().c_str());
}
bytes[i++] = ALPHANUMERIC_CHARS[threeDigitsBits / 100];
bytes[i++] = ALPHANUMERIC_CHARS[(threeDigitsBits / 10) % 10];
bytes[i++] = ALPHANUMERIC_CHARS[threeDigitsBits % 10];
count -= 3;
int nBytes = count;
char* bytes = new char[nBytes];
int i = 0;
// Read three digits at a time
while (count >= 3) {
// Each 10 bits encodes three digits
if (bits->available() < 10) {
throw ReaderException("format exception");
}
if (count == 2) {
if (bits->available() < 7) {
throw ReaderException("format exception");
}
// Two digits left over to read, encoded in 7 bits
int twoDigitsBits = bits->readBits(7);
if (twoDigitsBits >= 100) {
ostringstream s;
s << "Illegal value for 2-digit unit: " << twoDigitsBits;
delete[] bytes;
throw ReaderException(s.str().c_str());
}
bytes[i++] = ALPHANUMERIC_CHARS[twoDigitsBits / 10];
bytes[i++] = ALPHANUMERIC_CHARS[twoDigitsBits % 10];
} else if (count == 1) {
if (bits->available() < 4) {
throw ReaderException("format exception");
}
// One digit left over to read
int digitBits = bits->readBits(4);
if (digitBits >= 10) {
ostringstream s;
s << "Illegal value for digit unit: " << digitBits;
delete[] bytes;
throw ReaderException(s.str().c_str());
}
bytes[i++] = ALPHANUMERIC_CHARS[digitBits];
int threeDigitsBits = bits->readBits(10);
if (threeDigitsBits >= 1000) {
ostringstream s;
s << "Illegal value for 3-digit unit: " << threeDigitsBits;
delete[] bytes;
throw ReaderException(s.str().c_str());
}
append(result, bytes, nBytes, StringUtils::ASCII);
delete[] bytes;
bytes[i++] = ALPHANUMERIC_CHARS[threeDigitsBits / 100];
bytes[i++] = ALPHANUMERIC_CHARS[(threeDigitsBits / 10) % 10];
bytes[i++] = ALPHANUMERIC_CHARS[threeDigitsBits % 10];
count -= 3;
}
if (count == 2) {
if (bits->available() < 7) {
throw ReaderException("format exception");
}
// Two digits left over to read, encoded in 7 bits
int twoDigitsBits = bits->readBits(7);
if (twoDigitsBits >= 100) {
ostringstream s;
s << "Illegal value for 2-digit unit: " << twoDigitsBits;
delete[] bytes;
throw ReaderException(s.str().c_str());
}
bytes[i++] = ALPHANUMERIC_CHARS[twoDigitsBits / 10];
bytes[i++] = ALPHANUMERIC_CHARS[twoDigitsBits % 10];
} else if (count == 1) {
if (bits->available() < 4) {
throw ReaderException("format exception");
}
// One digit left over to read
int digitBits = bits->readBits(4);
if (digitBits >= 10) {
ostringstream s;
s << "Illegal value for digit unit: " << digitBits;
delete[] bytes;
throw ReaderException(s.str().c_str());
}
bytes[i++] = ALPHANUMERIC_CHARS[digitBits];
}
append(result, bytes, nBytes, StringUtils::ASCII);
delete[] bytes;
}
char DecodedBitStreamParser::toAlphaNumericChar(size_t value) {
if (value >= sizeof(DecodedBitStreamParser::ALPHANUMERIC_CHARS)) {
throw FormatException();
}
return ALPHANUMERIC_CHARS[value];
if (value >= sizeof(DecodedBitStreamParser::ALPHANUMERIC_CHARS)) {
throw FormatException();
}
return ALPHANUMERIC_CHARS[value];
}
void DecodedBitStreamParser::decodeAlphanumericSegment(Ref<BitSource> bits_,
string& result,
int count,
bool fc1InEffect) {
BitSource& bits (*bits_);
ostringstream bytes;
// Read two characters at a time
while (count > 1) {
if (bits.available() < 11) {
throw FormatException();
}
int nextTwoCharsBits = bits.readBits(11);
bytes << toAlphaNumericChar(nextTwoCharsBits / 45);
bytes << toAlphaNumericChar(nextTwoCharsBits % 45);
count -= 2;
BitSource& bits (*bits_);
ostringstream bytes;
// Read two characters at a time
while (count > 1) {
if (bits.available() < 11) {
throw FormatException();
}
if (count == 1) {
// special case: one character left
if (bits.available() < 6) {
throw FormatException();
}
bytes << toAlphaNumericChar(bits.readBits(6));
int nextTwoCharsBits = bits.readBits(11);
bytes << toAlphaNumericChar(nextTwoCharsBits / 45);
bytes << toAlphaNumericChar(nextTwoCharsBits % 45);
count -= 2;
}
if (count == 1) {
// special case: one character left
if (bits.available() < 6) {
throw FormatException();
}
// See section 6.4.8.1, 6.4.8.2
string s = bytes.str();
if (fc1InEffect) {
// We need to massage the result a bit if in an FNC1 mode:
ostringstream r;
for (size_t i = 0; i < s.length(); i++) {
if (s[i] != '%') {
r << s[i];
} else {
if (i < s.length() - 1 && s[i + 1] == '%') {
// %% is rendered as %
r << s[i++];
} else {
// In alpha mode, % should be converted to FNC1 separator 0x1D
r << (char)0x1D;
}
}
bytes << toAlphaNumericChar(bits.readBits(6));
}
// See section 6.4.8.1, 6.4.8.2
string s = bytes.str();
if (fc1InEffect) {
// We need to massage the result a bit if in an FNC1 mode:
ostringstream r;
for (size_t i = 0; i < s.length(); i++) {
if (s[i] != '%') {
r << s[i];
} else {
if (i < s.length() - 1 && s[i + 1] == '%') {
// %% is rendered as %
r << s[i++];
} else {
// In alpha mode, % should be converted to FNC1 separator 0x1D
r << (char)0x1D;
}
s = r.str();
}
}
append(result, s, StringUtils::ASCII);
s = r.str();
}
append(result, s, StringUtils::ASCII);
}
namespace {
int parseECIValue(BitSource bits) {
int parseECIValue(BitSource& bits) {
int firstByte = bits.readBits(8);
if ((firstByte & 0x80) == 0) {
// just one byte
return firstByte & 0x7F;
// just one byte
return firstByte & 0x7F;
}
if ((firstByte & 0xC0) == 0x80) {
// two bytes
int secondByte = bits.readBits(8);
return ((firstByte & 0x3F) << 8) | secondByte;
// two bytes
int secondByte = bits.readBits(8);
return ((firstByte & 0x3F) << 8) | secondByte;
}
if ((firstByte & 0xE0) == 0xC0) {
// three bytes
int secondThirdBytes = bits.readBits(16);
return ((firstByte & 0x1F) << 16) | secondThirdBytes;
// three bytes
int secondThirdBytes = bits.readBits(16);
return ((firstByte & 0x1F) << 16) | secondThirdBytes;
}
throw FormatException();
}
}
}
Ref<DecoderResult>
DecodedBitStreamParser::decode(ArrayRef<unsigned char> bytes,
DecodedBitStreamParser::decode(ArrayRef<char> bytes,
Version* version,
ErrorCorrectionLevel const& ecLevel,
Hashtable const& hints) {
Ref<BitSource> bits_ (new BitSource(bytes));
BitSource& bits (*bits_);
string result;
Ref<BitSource> bits_ (new BitSource(bytes));
BitSource& bits (*bits_);
string result;
result.reserve(50);
ArrayRef< ArrayRef<char> > byteSegments (0);
try {
CharacterSetECI* currentCharacterSetECI = 0;
bool fc1InEffect = false;
ArrayRef< ArrayRef<unsigned char> > byteSegments (size_t(0));
Mode* mode = 0;
do {
// While still another segment to read...
if (bits.available() < 4) {
// OK, assume we're done. Really, a TERMINATOR mode should have been recorded here
mode = &Mode::TERMINATOR;
// While still another segment to read...
if (bits.available() < 4) {
// OK, assume we're done. Really, a TERMINATOR mode should have been recorded here
mode = &Mode::TERMINATOR;
} else {
try {
mode = &Mode::forBits(bits.readBits(4)); // mode is encoded by 4 bits
} catch (IllegalArgumentException const& iae) {
throw iae;
// throw FormatException.getFormatInstance();
}
}
if (mode != &Mode::TERMINATOR) {
if ((mode == &Mode::FNC1_FIRST_POSITION) || (mode == &Mode::FNC1_SECOND_POSITION)) {
// We do little with FNC1 except alter the parsed result a bit according to the spec
fc1InEffect = true;
} else if (mode == &Mode::STRUCTURED_APPEND) {
if (bits.available() < 16) {
throw FormatException();
}
// not really supported; all we do is ignore it
// Read next 8 bits (symbol sequence #) and 8 bits (parity data), then continue
bits.readBits(16);
} else if (mode == &Mode::ECI) {
// Count doesn't apply to ECI
int value = parseECIValue(bits);
currentCharacterSetECI = CharacterSetECI::getCharacterSetECIByValue(value);
if (currentCharacterSetECI == 0) {
throw FormatException();
}
} else {
try {
mode = &Mode::forBits(bits.readBits(4)); // mode is encoded by 4 bits
} catch (IllegalArgumentException const& iae) {
throw iae;
// throw FormatException.getFormatInstance();
// First handle Hanzi mode which does not start with character count
if (mode == &Mode::HANZI) {
//chinese mode contains a sub set indicator right after mode indicator
int subset = bits.readBits(4);
int countHanzi = bits.readBits(mode->getCharacterCountBits(version));
if (subset == GB2312_SUBSET) {
decodeHanziSegment(bits_, result, countHanzi);
}
}
if (mode != &Mode::TERMINATOR) {
if ((mode == &Mode::FNC1_FIRST_POSITION) || (mode == &Mode::FNC1_SECOND_POSITION)) {
// We do little with FNC1 except alter the parsed result a bit according to the spec
fc1InEffect = true;
} else if (mode == &Mode::STRUCTURED_APPEND) {
// not really supported; all we do is ignore it
// Read next 8 bits (symbol sequence #) and 8 bits (parity data), then continue
bits.readBits(16);
} else if (mode == &Mode::ECI) {
// Count doesn't apply to ECI
int value = parseECIValue(bits);
currentCharacterSetECI = CharacterSetECI::getCharacterSetECIByValue(value);
if (currentCharacterSetECI == 0) {
throw FormatException();
}
} else {
// "Normal" QR code modes:
// How many characters will follow, encoded in this mode?
int count = bits.readBits(mode->getCharacterCountBits(version));
if (mode == &Mode::NUMERIC) {
decodeNumericSegment(bits_, result, count);
} else if (mode == &Mode::ALPHANUMERIC) {
decodeAlphanumericSegment(bits_, result, count, fc1InEffect);
} else if (mode == &Mode::BYTE) {
decodeByteSegment(bits_, result, count, currentCharacterSetECI, byteSegments, hints);
} else if (mode == &Mode::KANJI) {
decodeKanjiSegment(bits_, result, count);
} else {
// First handle Hanzi mode which does not start with character count
if (mode == &Mode::HANZI) {
//chinese mode contains a sub set indicator right after mode indicator
int subset = bits.readBits(4);
int countHanzi = bits.readBits(mode->getCharacterCountBits(version));
if (subset == GB2312_SUBSET) {
decodeHanziSegment(bits_, result, countHanzi);
}
} else {
// "Normal" QR code modes:
// How many characters will follow, encoded in this mode?
int count = bits.readBits(mode->getCharacterCountBits(version));
if (mode == &Mode::NUMERIC) {
decodeNumericSegment(bits_, result, count);
} else if (mode == &Mode::ALPHANUMERIC) {
decodeAlphanumericSegment(bits_, result, count, fc1InEffect);
} else if (mode == &Mode::BYTE) {
decodeByteSegment(bits_, result, count, currentCharacterSetECI, byteSegments, hints);
} else if (mode == &Mode::KANJI) {
decodeKanjiSegment(bits_, result, count);
} else {
throw FormatException();
}
}
throw FormatException();
}
}
}
}
} while (mode != &Mode::TERMINATOR);
return Ref<DecoderResult>(new DecoderResult(bytes, Ref<String>(new String(result)), byteSegments, (string)ecLevel));
} catch (IllegalArgumentException const& iae) {
(void)iae;
// from readBits() calls
throw FormatException();
}
return Ref<DecoderResult>(new DecoderResult(bytes, Ref<String>(new String(result)), byteSegments, (string)ecLevel));
}

View File

@ -1,3 +1,4 @@
// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*-
/*
* Decoder.cpp
* zxing
@ -25,18 +26,22 @@
#include <zxing/qrcode/decoder/DataBlock.h>
#include <zxing/qrcode/decoder/DecodedBitStreamParser.h>
#include <zxing/ReaderException.h>
#include <zxing/ChecksumException.h>
#include <zxing/common/reedsolomon/ReedSolomonException.h>
namespace zxing {
namespace qrcode {
using zxing::qrcode::Decoder;
using zxing::DecoderResult;
using zxing::Ref;
using namespace std;
// VC++
using zxing::ArrayRef;
using zxing::BitMatrix;
Decoder::Decoder() :
rsDecoder_(GenericGF::QR_CODE_FIELD_256) {
rsDecoder_(GenericGF::QR_CODE_FIELD_256) {
}
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++) {
@ -46,13 +51,13 @@ void Decoder::correctErrors(ArrayRef<unsigned char> codewordBytes, int numDataCo
try {
rsDecoder_.decode(codewordInts, numECCodewords);
} catch (ReedSolomonException const& ex) {
ReaderException rex(ex.what());
throw rex;
} catch (ReedSolomonException const& ignored) {
(void)ignored;
throw ChecksumException();
}
for (int i = 0; i < numDataCodewords; i++) {
codewordBytes[i] = (unsigned char)codewordInts[i];
codewordBytes[i] = (char)codewordInts[i];
}
}
@ -60,12 +65,14 @@ Ref<DecoderResult> Decoder::decode(Ref<BitMatrix> bits) {
// Construct a parser and read version, error-correction level
BitMatrixParser parser(bits);
// std::cerr << *bits << std::endl;
Version *version = parser.readVersion();
ErrorCorrectionLevel &ecLevel = parser.readFormatInformation()->getErrorCorrectionLevel();
// Read codewords
ArrayRef<unsigned char> codewords(parser.readCodewords());
ArrayRef<char> codewords(parser.readCodewords());
// Separate into data blocks
@ -77,14 +84,14 @@ Ref<DecoderResult> Decoder::decode(Ref<BitMatrix> bits) {
for (size_t i = 0; i < dataBlocks.size(); i++) {
totalBytes += dataBlocks[i]->getNumDataCodewords();
}
ArrayRef<unsigned char> resultBytes(totalBytes);
ArrayRef<char> resultBytes(totalBytes);
int resultOffset = 0;
// Error-correct and copy data blocks together into a stream of bytes
for (size_t j = 0; j < dataBlocks.size(); j++) {
Ref<DataBlock> 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++) {
@ -98,5 +105,3 @@ Ref<DecoderResult> Decoder::decode(Ref<BitMatrix> bits) {
DecodedBitStreamParser::Hashtable());
}
}
}

View File

@ -19,6 +19,7 @@
* limitations under the License.
*/
#include <zxing/ZXing.h>
#include <zxing/qrcode/decoder/Mode.h>
#include <zxing/common/Counted.h>
#include <zxing/ReaderException.h>
@ -28,6 +29,9 @@
using zxing::qrcode::Mode;
using std::ostringstream;
// VC++
using zxing::qrcode::Version;
Mode Mode::TERMINATOR(0, 0, 0, 0x00, "TERMINATOR");
Mode Mode::NUMERIC(10, 12, 14, 0x01, "NUMERIC");
Mode Mode::ALPHANUMERIC(9, 11, 13, 0x02, "ALPHANUMERIC");
@ -39,39 +43,39 @@ Mode Mode::FNC1_FIRST_POSITION(0, 0, 0, 0x05, "FNC1_FIRST_POSITION");
Mode Mode::FNC1_SECOND_POSITION(0, 0, 0, 0x09, "FNC1_SECOND_POSITION");
Mode Mode::HANZI(8, 10, 12, 0x0D, "HANZI");
Mode::Mode(int cbv0_9, int cbv10_26, int cbv27, int bits, char const* name) :
characterCountBitsForVersions0To9_(cbv0_9), characterCountBitsForVersions10To26_(cbv10_26),
characterCountBitsForVersions27AndHigher_(cbv27), bits_(bits), name_(name) {
Mode::Mode(int cbv0_9, int cbv10_26, int cbv27, int /* bits */, char const* name) :
characterCountBitsForVersions0To9_(cbv0_9), characterCountBitsForVersions10To26_(cbv10_26),
characterCountBitsForVersions27AndHigher_(cbv27), name_(name) {
}
Mode& Mode::forBits(int bits) {
switch (bits) {
case 0x0:
return TERMINATOR;
case 0x1:
return NUMERIC;
case 0x2:
return ALPHANUMERIC;
case 0x3:
return STRUCTURED_APPEND;
case 0x4:
return BYTE;
case 0x5:
return FNC1_FIRST_POSITION;
case 0x7:
return ECI;
case 0x8:
return KANJI;
case 0x9:
return FNC1_SECOND_POSITION;
case 0xD:
// 0xD is defined in GBT 18284-2000, may not be supported in foreign country
return HANZI;
default:
ostringstream s;
s << "Illegal mode bits: " << bits;
throw ReaderException(s.str().c_str());
}
switch (bits) {
case 0x0:
return TERMINATOR;
case 0x1:
return NUMERIC;
case 0x2:
return ALPHANUMERIC;
case 0x3:
return STRUCTURED_APPEND;
case 0x4:
return BYTE;
case 0x5:
return FNC1_FIRST_POSITION;
case 0x7:
return ECI;
case 0x8:
return KANJI;
case 0x9:
return FNC1_SECOND_POSITION;
case 0xD:
// 0xD is defined in GBT 18284-2000, may not be supported in foreign country
return HANZI;
default:
ostringstream s;
s << "Illegal mode bits: " << bits;
throw ReaderException(s.str().c_str());
}
}
int Mode::getCharacterCountBits(Version *version) {

View File

@ -37,21 +37,21 @@ private:
Ref<BitMatrix> image_;
std::vector<AlignmentPattern *> *possibleCenters_;
size_t startX_;
size_t startY_;
size_t width_;
size_t height_;
int startX_;
int startY_;
int width_;
int height_;
float moduleSize_;
static float centerFromEnd(std::vector<int> &stateCount, int end);
bool foundPatternCross(std::vector<int> &stateCount);
float crossCheckVertical(size_t startI, size_t centerJ, int maxCount, int originalStateCountTotal);
float crossCheckVertical(int startI, int centerJ, int maxCount, int originalStateCountTotal);
Ref<AlignmentPattern> handlePossibleCenter(std::vector<int> &stateCount, size_t i, size_t j);
Ref<AlignmentPattern> handlePossibleCenter(std::vector<int> &stateCount, int i, int j);
public:
AlignmentPatternFinder(Ref<BitMatrix> image, size_t startX, size_t startY, size_t width, size_t height,
AlignmentPatternFinder(Ref<BitMatrix> image, int startX, int startY, int width, int height,
float moduleSize, Ref<ResultPointCallback>const& callback);
~AlignmentPatternFinder();
Ref<AlignmentPattern> find();

View File

@ -1,3 +1,4 @@
// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*-
#ifndef __DETECTOR_H__
#define __DETECTOR_H__
@ -40,7 +41,8 @@ private:
Ref<ResultPointCallback> callback_;
protected:
Ref<BitMatrix> getImage();
Ref<BitMatrix> getImage() const;
Ref<ResultPointCallback> getResultPointCallback() const;
static Ref<BitMatrix> sampleGrid(Ref<BitMatrix> image, int dimension, Ref<PerspectiveTransform>);
static int computeDimension(Ref<ResultPoint> topLeft, Ref<ResultPoint> topRight, Ref<ResultPoint> bottomLeft,
@ -53,14 +55,15 @@ protected:
float allowanceFactor);
Ref<DetectorResult> processFinderPatternInfo(Ref<FinderPatternInfo> info);
public:
virtual Ref<PerspectiveTransform> createTransform(Ref<ResultPoint> topLeft, Ref<ResultPoint> topRight, Ref <
ResultPoint > bottomLeft, Ref<ResultPoint> alignmentPattern, int dimension);
Detector(Ref<BitMatrix> image);
Ref<DetectorResult> detect(DecodeHints const& hints);
};
}
}
#endif // __DETECTOR_H__
#endif // __DETECTOR_H__

View File

@ -32,9 +32,10 @@ namespace zxing {
float estimatedModuleSize_;
int count_;
FinderPattern(float posX, float posY, float estimatedModuleSize, int count);
public:
FinderPattern(float posX, float posY, float estimatedModuleSize);
FinderPattern(float posX, float posY, float estimatedModuleSize, int count);
int getCount() const;
float getEstimatedModuleSize() const;
void incrementCount();

View File

@ -1,3 +1,4 @@
// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*-
#ifndef __FINDER_PATTERN_FINDER_H__
#define __FINDER_PATTERN_FINDER_H__
@ -60,6 +61,10 @@ protected:
bool haveMultiplyConfirmedCenters();
std::vector<Ref<FinderPattern> > selectBestPatterns();
static std::vector<Ref<FinderPattern> > orderBestPatterns(std::vector<Ref<FinderPattern> > patterns);
Ref<BitMatrix> getImage();
std::vector<Ref<FinderPattern> >& getPossibleCenters();
public:
static float distance(Ref<ResultPoint> p1, Ref<ResultPoint> p2);
FinderPatternFinder(Ref<BitMatrix> image, Ref<ResultPointCallback>const&);

View File

@ -21,10 +21,9 @@
#include <zxing/qrcode/detector/AlignmentPattern.h>
namespace zxing {
namespace qrcode {
using namespace std;
using std::abs;
using zxing::Ref;
using zxing::qrcode::AlignmentPattern;
AlignmentPattern::AlignmentPattern(float posX, float posY, float estimatedModuleSize) :
ResultPoint(posX,posY), estimatedModuleSize_(estimatedModuleSize) {
@ -43,9 +42,6 @@ Ref<AlignmentPattern> AlignmentPattern::combineEstimate(float i, float j, float
float combinedY = (getY() + i) / 2.0f;
float combinedModuleSize = (estimatedModuleSize_ + newModuleSize) / 2.0f;
Ref<AlignmentPattern> result
(new AlignmentPattern(combinedX, combinedY, combinedModuleSize));
(new AlignmentPattern(combinedX, combinedY, combinedModuleSize));
return result;
}
}
}

View File

@ -1,9 +1,5 @@
// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*-
/*
* AlignmentPatternFinder.cpp
* zxing
*
* Created by Christian Brunschen on 14/05/2008.
* Copyright 2008 ZXing authors All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -19,25 +15,31 @@
* limitations under the License.
*/
#include "AlignmentPatternFinder.h"
#include <zxing/qrcode/detector/AlignmentPatternFinder.h>
#include <zxing/ReaderException.h>
#include <zxing/common/BitArray.h>
#include <vector>
#include <cmath>
#include <cstdlib>
namespace zxing {
namespace qrcode {
using std::abs;
using std::vector;
using zxing::Ref;
using zxing::qrcode::AlignmentPatternFinder;
using zxing::qrcode::AlignmentPattern;
using namespace std;
// VC++
float AlignmentPatternFinder::centerFromEnd(vector<int> &stateCount, int end) {
using zxing::BitMatrix;
using zxing::ResultPointCallback;
float AlignmentPatternFinder::centerFromEnd(vector<int>& stateCount, int end) {
return (float)(end - stateCount[2]) - stateCount[1] / 2.0f;
}
bool AlignmentPatternFinder::foundPatternCross(vector<int> &stateCount) {
float maxVariance = moduleSize_ / 2.0f;
for (size_t i = 0; i < 3; i++) {
for (int i = 0; i < 3; i++) {
if (abs(moduleSize_ - stateCount[i]) >= maxVariance) {
return false;
}
@ -45,8 +47,8 @@ bool AlignmentPatternFinder::foundPatternCross(vector<int> &stateCount) {
return true;
}
float AlignmentPatternFinder::crossCheckVertical(size_t startI, size_t centerJ, int maxCount,
int originalStateCountTotal) {
float AlignmentPatternFinder::crossCheckVertical(int startI, int centerJ, int maxCount,
int originalStateCountTotal) {
int maxI = image_->getHeight();
vector<int> stateCount(3, 0);
@ -59,14 +61,14 @@ float AlignmentPatternFinder::crossCheckVertical(size_t startI, size_t centerJ,
}
// If already too many modules in this state or ran off the edge:
if (i < 0 || stateCount[1] > maxCount) {
return NAN;
return nan();
}
while (i >= 0 && !image_->get(centerJ, i) && stateCount[0] <= maxCount) {
stateCount[0]++;
i--;
}
if (stateCount[0] > maxCount) {
return NAN;
return nan();
}
// Now also count down from center
@ -76,25 +78,25 @@ float AlignmentPatternFinder::crossCheckVertical(size_t startI, size_t centerJ,
i++;
}
if (i == maxI || stateCount[1] > maxCount) {
return NAN;
return nan();
}
while (i < maxI && !image_->get(centerJ, i) && stateCount[2] <= maxCount) {
stateCount[2]++;
i++;
}
if (stateCount[2] > maxCount) {
return NAN;
return nan();
}
int stateCountTotal = stateCount[0] + stateCount[1] + stateCount[2];
if (5 * abs(stateCountTotal - originalStateCountTotal) >= 2 * originalStateCountTotal) {
return NAN;
return nan();
}
return foundPatternCross(stateCount) ? centerFromEnd(stateCount, i) : NAN;
return foundPatternCross(stateCount) ? centerFromEnd(stateCount, i) : nan();
}
Ref<AlignmentPattern> AlignmentPatternFinder::handlePossibleCenter(vector<int> &stateCount, size_t i, size_t j) {
Ref<AlignmentPattern> AlignmentPatternFinder::handlePossibleCenter(vector<int> &stateCount, int i, int j) {
int stateCountTotal = stateCount[0] + stateCount[1] + stateCount[2];
float centerJ = centerFromEnd(stateCount, j);
float centerI = crossCheckVertical(i, (int)centerJ, 2 * stateCount[1], stateCountTotal);
@ -120,15 +122,15 @@ Ref<AlignmentPattern> AlignmentPatternFinder::handlePossibleCenter(vector<int> &
return result;
}
AlignmentPatternFinder::AlignmentPatternFinder(Ref<BitMatrix> image, size_t startX, size_t startY, size_t width,
size_t height, float moduleSize,
AlignmentPatternFinder::AlignmentPatternFinder(Ref<BitMatrix> image, int startX, int startY, int width,
int height, float moduleSize,
Ref<ResultPointCallback>const& callback) :
image_(image), possibleCenters_(new vector<AlignmentPattern *> ()), startX_(startX), startY_(startY),
width_(width), height_(height), moduleSize_(moduleSize), callback_(callback) {
}
AlignmentPatternFinder::~AlignmentPatternFinder() {
for (size_t i = 0; i < possibleCenters_->size(); i++) {
for (int i = 0; i < int(possibleCenters_->size()); i++) {
(*possibleCenters_)[i]->release();
(*possibleCenters_)[i] = 0;
}
@ -136,20 +138,20 @@ AlignmentPatternFinder::~AlignmentPatternFinder() {
}
Ref<AlignmentPattern> AlignmentPatternFinder::find() {
size_t maxJ = startX_ + width_;
size_t middleI = startY_ + (height_ >> 1);
int maxJ = startX_ + width_;
int middleI = startY_ + (height_ >> 1);
// Ref<BitArray> luminanceRow(new BitArray(width_));
// We are looking for black/white/black modules in 1:1:1 ratio;
// this tracks the number of black/white/black modules seen so far
vector<int> stateCount(3, 0);
for (size_t iGen = 0; iGen < height_; iGen++) {
for (int iGen = 0; iGen < height_; iGen++) {
// Search from middle outwards
size_t i = middleI + ((iGen & 0x01) == 0 ? ((iGen + 1) >> 1) : -((iGen + 1) >> 1));
int i = middleI + ((iGen & 0x01) == 0 ? ((iGen + 1) >> 1) : -((iGen + 1) >> 1));
// image_->getBlackRow(i, luminanceRow, startX_, width_);
stateCount[0] = 0;
stateCount[1] = 0;
stateCount[2] = 0;
size_t j = startX_;
int j = startX_;
// Burn off leading white pixels before anything else; if we start in the middle of
// a white run, it doesn't make sense to count its length, since we don't know if the
// white run continued to the left of the start point
@ -204,6 +206,3 @@ Ref<AlignmentPattern> AlignmentPatternFinder::find() {
throw zxing::ReaderException("Could not find alignment pattern");
}
}
}

View File

@ -27,21 +27,39 @@
#include <zxing/qrcode/Version.h>
#include <zxing/common/GridSampler.h>
#include <zxing/DecodeHints.h>
#include <cmath>
#include <zxing/common/detector/MathUtils.h>
#include <sstream>
#include <cstdlib>
namespace zxing {
namespace qrcode {
using std::ostringstream;
using std::abs;
using std::min;
using std::max;
using zxing::qrcode::Detector;
using zxing::Ref;
using zxing::BitMatrix;
using zxing::ResultPointCallback;
using zxing::DetectorResult;
using zxing::PerspectiveTransform;
using zxing::qrcode::AlignmentPattern;
using zxing::common::detector::MathUtils;
using namespace std;
// VC++
using zxing::DecodeHints;
using zxing::qrcode::FinderPatternFinder;
using zxing::qrcode::FinderPatternInfo;
using zxing::ResultPoint;
Detector::Detector(Ref<BitMatrix> image) :
image_(image) {
image_(image) {
}
Ref<BitMatrix> Detector::getImage() {
return image_;
Ref<BitMatrix> Detector::getImage() const {
return image_;
}
Ref<ResultPointCallback> Detector::getResultPointCallback() const {
return callback_;
}
Ref<DetectorResult> Detector::detect(DecodeHints const& hints) {
@ -87,6 +105,7 @@ Ref<DetectorResult> Detector::processFinderPatternInfo(Ref<FinderPatternInfo> in
alignmentPattern = findAlignmentInRegion(moduleSize, estAlignmentX, estAlignmentY, (float)i);
break;
} catch (zxing::ReaderException const& re) {
(void)re;
// try next round
}
}
@ -98,7 +117,7 @@ Ref<DetectorResult> Detector::processFinderPatternInfo(Ref<FinderPatternInfo> in
Ref<PerspectiveTransform> transform = createTransform(topLeft, topRight, bottomLeft, alignmentPattern, dimension);
Ref<BitMatrix> bits(sampleGrid(image_, dimension, transform));
std::vector<Ref<ResultPoint> > points(alignmentPattern == 0 ? 3 : 4);
ArrayRef< Ref<ResultPoint> > points(new Array< Ref<ResultPoint> >(alignmentPattern == 0 ? 3 : 4));
points[0].reset(bottomLeft);
points[1].reset(topLeft);
points[2].reset(topRight);
@ -106,12 +125,12 @@ Ref<DetectorResult> Detector::processFinderPatternInfo(Ref<FinderPatternInfo> in
points[3].reset(alignmentPattern);
}
Ref<DetectorResult> result(new DetectorResult(bits, points));
Ref<DetectorResult> result(new DetectorResult(bits, points));
return result;
}
Ref<PerspectiveTransform> Detector::createTransform(Ref<ResultPoint> topLeft, Ref<ResultPoint> topRight, Ref <
ResultPoint > bottomLeft, Ref<ResultPoint> alignmentPattern, int dimension) {
ResultPoint > bottomLeft, Ref<ResultPoint> alignmentPattern, int dimension) {
float dimMinusThree = (float)dimension - 3.5f;
float bottomRightX;
@ -121,17 +140,19 @@ Ref<PerspectiveTransform> Detector::createTransform(Ref<ResultPoint> topLeft, Re
if (alignmentPattern != 0) {
bottomRightX = alignmentPattern->getX();
bottomRightY = alignmentPattern->getY();
sourceBottomRightX = sourceBottomRightY = dimMinusThree - 3.0f;
sourceBottomRightX = dimMinusThree - 3.0f;
sourceBottomRightY = sourceBottomRightX;
} else {
// Don't have an alignment pattern, just make up the bottom-right point
bottomRightX = (topRight->getX() - topLeft->getX()) + bottomLeft->getX();
bottomRightY = (topRight->getY() - topLeft->getY()) + bottomLeft->getY();
sourceBottomRightX = sourceBottomRightY = dimMinusThree;
sourceBottomRightX = dimMinusThree;
sourceBottomRightY = dimMinusThree;
}
Ref<PerspectiveTransform> transform(PerspectiveTransform::quadrilateralToQuadrilateral(3.5f, 3.5f, dimMinusThree, 3.5f, sourceBottomRightX,
sourceBottomRightY, 3.5f, dimMinusThree, topLeft->getX(), topLeft->getY(), topRight->getX(),
topRight->getY(), bottomRightX, bottomRightY, bottomLeft->getX(), bottomLeft->getY()));
sourceBottomRightY, 3.5f, dimMinusThree, topLeft->getX(), topLeft->getY(), topRight->getX(),
topRight->getY(), bottomRightX, bottomRightY, bottomLeft->getX(), bottomLeft->getY()));
return transform;
}
@ -143,8 +164,10 @@ Ref<BitMatrix> Detector::sampleGrid(Ref<BitMatrix> image, int dimension, Ref<Per
int Detector::computeDimension(Ref<ResultPoint> topLeft, Ref<ResultPoint> topRight, Ref<ResultPoint> bottomLeft,
float moduleSize) {
int tltrCentersDimension = int(FinderPatternFinder::distance(topLeft, topRight) / moduleSize + 0.5f);
int tlblCentersDimension = int(FinderPatternFinder::distance(topLeft, bottomLeft) / moduleSize + 0.5f);
int tltrCentersDimension =
MathUtils::round(ResultPoint::distance(topLeft, topRight) / moduleSize);
int tlblCentersDimension =
MathUtils::round(ResultPoint::distance(topLeft, bottomLeft) / moduleSize);
int dimension = ((tltrCentersDimension + tlblCentersDimension) >> 1) + 7;
switch (dimension & 0x03) { // mod 4
case 0:
@ -169,13 +192,13 @@ float Detector::calculateModuleSize(Ref<ResultPoint> topLeft, Ref<ResultPoint> t
float Detector::calculateModuleSizeOneWay(Ref<ResultPoint> pattern, Ref<ResultPoint> otherPattern) {
float moduleSizeEst1 = sizeOfBlackWhiteBlackRunBothWays((int)pattern->getX(), (int)pattern->getY(),
(int)otherPattern->getX(), (int)otherPattern->getY());
(int)otherPattern->getX(), (int)otherPattern->getY());
float moduleSizeEst2 = sizeOfBlackWhiteBlackRunBothWays((int)otherPattern->getX(), (int)otherPattern->getY(),
(int)pattern->getX(), (int)pattern->getY());
if (isnan(moduleSizeEst1)) {
(int)pattern->getX(), (int)pattern->getY());
if (zxing::isnan(moduleSizeEst1)) {
return moduleSizeEst2;
}
if (isnan(moduleSizeEst2)) {
if (zxing::isnan(moduleSizeEst2)) {
return moduleSizeEst1;
}
// Average them, and divide by 7 since we've counted the width of 3 black modules,
@ -185,114 +208,107 @@ float Detector::calculateModuleSizeOneWay(Ref<ResultPoint> pattern, Ref<ResultPo
float Detector::sizeOfBlackWhiteBlackRunBothWays(int fromX, int fromY, int toX, int toY) {
float result = sizeOfBlackWhiteBlackRun(fromX, fromY, toX, toY);
float result = sizeOfBlackWhiteBlackRun(fromX, fromY, toX, toY);
// Now count other way -- don't run off image though of course
float scale = 1.0f;
int otherToX = fromX - (toX - fromX);
if (otherToX < 0) {
scale = (float) fromX / (float) (fromX - otherToX);
otherToX = 0;
} else if (otherToX >= (int)image_->getWidth()) {
scale = (float) (image_->getWidth() - 1 - fromX) / (float) (otherToX - fromX);
otherToX = image_->getWidth() - 1;
}
int otherToY = (int) (fromY - (toY - fromY) * scale);
// Now count other way -- don't run off image though of course
float scale = 1.0f;
int otherToX = fromX - (toX - fromX);
if (otherToX < 0) {
scale = (float) fromX / (float) (fromX - otherToX);
otherToX = 0;
} else if (otherToX >= (int)image_->getWidth()) {
scale = (float) (image_->getWidth() - 1 - fromX) / (float) (otherToX - fromX);
otherToX = image_->getWidth() - 1;
}
int otherToY = (int) (fromY - (toY - fromY) * scale);
scale = 1.0f;
if (otherToY < 0) {
scale = (float) fromY / (float) (fromY - otherToY);
otherToY = 0;
} else if (otherToY >= (int)image_->getHeight()) {
scale = (float) (image_->getHeight() - 1 - fromY) / (float) (otherToY - fromY);
otherToY = image_->getHeight() - 1;
}
otherToX = (int) (fromX + (otherToX - fromX) * scale);
scale = 1.0f;
if (otherToY < 0) {
scale = (float) fromY / (float) (fromY - otherToY);
otherToY = 0;
} else if (otherToY >= (int)image_->getHeight()) {
scale = (float) (image_->getHeight() - 1 - fromY) / (float) (otherToY - fromY);
otherToY = image_->getHeight() - 1;
}
otherToX = (int) (fromX + (otherToX - fromX) * scale);
result += sizeOfBlackWhiteBlackRun(fromX, fromY, otherToX, otherToY);
result += sizeOfBlackWhiteBlackRun(fromX, fromY, otherToX, otherToY);
// Middle pixel is double-counted this way; subtract 1
return result - 1.0f;
// Middle pixel is double-counted this way; subtract 1
return result - 1.0f;
}
float Detector::sizeOfBlackWhiteBlackRun(int fromX, int fromY, int toX, int toY) {
// Mild variant of Bresenham's algorithm;
// see http://en.wikipedia.org/wiki/Bresenham's_line_algorithm
bool steep = abs(toY - fromY) > abs(toX - fromX);
if (steep) {
int temp = fromX;
fromX = fromY;
fromY = temp;
temp = toX;
toX = toY;
toY = temp;
}
// Mild variant of Bresenham's algorithm;
// see http://en.wikipedia.org/wiki/Bresenham's_line_algorithm
bool steep = abs(toY - fromY) > abs(toX - fromX);
if (steep) {
int temp = fromX;
fromX = fromY;
fromY = temp;
temp = toX;
toX = toY;
toY = temp;
}
int dx = abs(toX - fromX);
int dy = abs(toY - fromY);
int error = -dx >> 1;
int xstep = fromX < toX ? 1 : -1;
int ystep = fromY < toY ? 1 : -1;
int dx = abs(toX - fromX);
int dy = abs(toY - fromY);
int error = -dx >> 1;
int xstep = fromX < toX ? 1 : -1;
int ystep = fromY < toY ? 1 : -1;
// In black pixels, looking for white, first or second time.
int state = 0;
// Loop up until x == toX, but not beyond
int xLimit = toX + xstep;
for (int x = fromX, y = fromY; x != xLimit; x += xstep) {
int realX = steep ? y : x;
int realY = steep ? x : y;
// In black pixels, looking for white, first or second time.
int state = 0;
// Loop up until x == toX, but not beyond
int xLimit = toX + xstep;
for (int x = fromX, y = fromY; x != xLimit; x += xstep) {
int realX = steep ? y : x;
int realY = steep ? x : y;
// Does current pixel mean we have moved white to black or vice versa?
if (!((state == 1) ^ image_->get(realX, realY))) {
if (state == 2) {
int diffX = x - fromX;
int diffY = y - fromY;
return (float) sqrt((double) (diffX * diffX + diffY * diffY));
}
state++;
// Does current pixel mean we have moved white to black or vice versa?
if (!((state == 1) ^ image_->get(realX, realY))) {
if (state == 2) {
return MathUtils::distance(x, y, fromX, fromY);
}
state++;
}
error += dy;
if (error > 0) {
if (y == toY) {
break;
}
y += ystep;
error -= dx;
error += dy;
if (error > 0) {
if (y == toY) {
break;
}
y += ystep;
error -= dx;
}
// Found black-white-black; give the benefit of the doubt that the next pixel outside the image
// is "white" so this last point at (toX+xStep,toY) is the right ending. This is really a
// small approximation; (toX+xStep,toY+yStep) might be really correct. Ignore this.
if (state == 2) {
int diffX = toX + xstep - fromX;
int diffY = toY - fromY;
return (float) sqrt((double) (diffX * diffX + diffY * diffY));
}
// else we didn't find even black-white-black; no estimate is really possible
return NAN;
}
// Found black-white-black; give the benefit of the doubt that the next pixel outside the image
// is "white" so this last point at (toX+xStep,toY) is the right ending. This is really a
// small approximation; (toX+xStep,toY+yStep) might be really correct. Ignore this.
if (state == 2) {
return MathUtils::distance(toX + xstep, toY, fromX, fromY);
}
// else we didn't find even black-white-black; no estimate is really possible
return nan();
}
Ref<AlignmentPattern> Detector::findAlignmentInRegion(float overallEstModuleSize, int estAlignmentX, int estAlignmentY,
float allowanceFactor) {
float allowanceFactor) {
// Look for an alignment pattern (3 modules in size) around where it
// should be
int allowance = (int)(allowanceFactor * overallEstModuleSize);
int alignmentAreaLeftX = max(0, estAlignmentX - allowance);
int alignmentAreaRightX = min((int)(image_->getWidth() - 1), estAlignmentX + allowance);
if (alignmentAreaRightX - alignmentAreaLeftX < overallEstModuleSize * 3) {
throw zxing::ReaderException("region too small to hold alignment pattern");
throw zxing::ReaderException("region too small to hold alignment pattern");
}
int alignmentAreaTopY = max(0, estAlignmentY - allowance);
int alignmentAreaBottomY = min((int)(image_->getHeight() - 1), estAlignmentY + allowance);
if (alignmentAreaBottomY - alignmentAreaTopY < overallEstModuleSize * 3) {
throw zxing::ReaderException("region too small to hold alignment pattern");
throw zxing::ReaderException("region too small to hold alignment pattern");
}
AlignmentPatternFinder alignmentFinder(image_, alignmentAreaLeftX, alignmentAreaTopY, alignmentAreaRightX
- alignmentAreaLeftX, alignmentAreaBottomY - alignmentAreaTopY, overallEstModuleSize, callback_);
return alignmentFinder.find();
}
}
}

View File

@ -1,168 +0,0 @@
// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*-
/*
* Created by Ralf Kistner on 7/12/2009.
* 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/qrcode/detector/QREdgeDetector.h>
#include <zxing/common/EdgeDetector.h>
#include <cstdlib>
using namespace std;
namespace zxing {
namespace qrcode {
static const float patternEdgeThreshold = 2;
static const int patternEdgeWidth = 3;
static const float patternEdgeSearchRatio = 1.1;
static const int patternEdgeSkip = 2;
static const float accurateEdgeThreshold = 3.3;
static const int accurateEdgeWidth = 7;
static const int accurateEdgeSkip = 2;
static Point guessLastPattern(Point topLeft, Point topRight, Point bottomLeft) {
return Point(topRight.x - topLeft.x + bottomLeft.x, topRight.y - topLeft.y + bottomLeft.y);
}
static Point rp(Ref<ResultPoint> rp) {
return Point(rp->getX(), rp->getY());
}
QREdgeDetector::QREdgeDetector(Ref<BitMatrix> image) : Detector(image) { }
Ref<PerspectiveTransform> QREdgeDetector::createTransform(Ref<ResultPoint> topLeft, Ref<ResultPoint> topRight, Ref <
ResultPoint > bottomLeft, Ref<ResultPoint> alignmentPattern, int dimension) {
if(alignmentPattern == NULL) {
Point corner = findCorner(*Detector::getImage(), rp(topLeft), rp(topRight), rp(bottomLeft), dimension);
return get1CornerTransform(rp(topLeft), rp(topRight), rp(bottomLeft), corner, dimension);
} else {
return Detector::createTransform(topLeft, topRight, bottomLeft, alignmentPattern, dimension);
}
}
Point QREdgeDetector::findCorner(const BitMatrix& image, Point topLeft, Point topRight, Point bottomLeft, int dimension) {
(void)dimension;
Point bottomRight = guessLastPattern(topLeft, topRight, bottomLeft);
Line bottomEst = findPatternEdge(image, bottomLeft, topLeft, bottomRight, false);
Line rightEst = findPatternEdge(image, topRight, topLeft, bottomRight, true);
//return EdgeDetector::intersection(bottomEst, rightEst);
Line bottom = EdgeDetector::findLine(image, bottomEst, false, accurateEdgeWidth, accurateEdgeThreshold, accurateEdgeSkip);
Line right = EdgeDetector::findLine(image, rightEst, true, accurateEdgeWidth, accurateEdgeThreshold, accurateEdgeSkip);
return EdgeDetector::intersection(bottom, right);
}
Line QREdgeDetector::findPatternEdge(const BitMatrix& image, Point pattern, Point opposite, Point direction, bool invert) {
Point start = endOfReverseBlackWhiteBlackRun(image, pattern, opposite);
float dx = pattern.x - start.x;
float dy = pattern.y - start.y;
float dist = sqrt(dx*dx + dy*dy);
float dirX = direction.x - pattern.x;
float dirY = direction.y - pattern.y;
float dirSize = sqrt(dirX*dirX + dirY*dirY);
float nx = dirX/dirSize;
float ny = dirY/dirSize;
float search = dist * patternEdgeSearchRatio;
Point a(start.x + nx*search, start.y + ny*search);
Point b(start.x - nx*search, start.y - ny*search);
return EdgeDetector::findLine(image, Line(a, b), invert, patternEdgeWidth, patternEdgeThreshold, patternEdgeSkip);
}
Ref<PerspectiveTransform> QREdgeDetector::get1CornerTransform(Point topLeft, Point topRight, Point bottomLeft, Point corner, int dimension) {
float dimMinusThree = (float) dimension - 3.5f;
Ref<PerspectiveTransform> transform(PerspectiveTransform::quadrilateralToQuadrilateral(3.5f, 3.5f, dimMinusThree, 3.5f, dimension,
dimension, 3.5f, dimMinusThree, topLeft.x, topLeft.y, topRight.x,
topRight.y, corner.x, corner.y, bottomLeft.x, bottomLeft.y));
return transform;
}
// Adapted from "sizeOfBlackWhiteBlackRun" in zxing::qrcode::Detector
Point QREdgeDetector::endOfReverseBlackWhiteBlackRun(const BitMatrix& image, Point from, Point to) {
int fromX = (int)from.x;
int fromY = (int)from.y;
int toX = (int)to.x;
int toY = (int)to.y;
bool steep = abs(toY - fromY) > abs(toX - fromX);
if (steep) {
int temp = fromX;
fromX = fromY;
fromY = temp;
temp = toX;
toX = toY;
toY = temp;
}
int dx = abs(toX - fromX);
int dy = abs(toY - fromY);
int error = -dx >> 1;
int ystep = fromY < toY ? -1 : 1;
int xstep = fromX < toX ? -1 : 1;
int state = 0; // In black pixels, looking for white, first or second time
// In case there are no points, prepopulate to from
int realX = fromX;
int realY = fromY;
for (int x = fromX, y = fromY; x != toX; x += xstep) {
realX = steep ? y : x;
realY = steep ? x : y;
if(realX < 0 || realY < 0 || realX >= (int)image.getWidth() || realY >= (int)image.getHeight())
break;
if (state == 1) { // In white pixels, looking for black
if (image.get(realX, realY)) {
state++;
}
} else {
if (!image.get(realX, realY)) {
state++;
}
}
if (state == 3) { // Found black, white, black, and stumbled back onto white; done
return Point(realX, realY);
}
error += dy;
if (error > 0) {
y += ystep;
error -= dx;
}
}
// B-W-B run not found, return the last point visited.
return Point(realX, realY);
}
} // namespace qrcode
} // namespace zxing

View File

@ -1,48 +0,0 @@
#ifndef __QREDGEDETECTOR_H__
#define __QREDGEDETECTOR_H__
/*
* QREdgeDetector.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/qrcode/detector/Detector.h>
#include <zxing/common/Point.h>
namespace zxing {
namespace qrcode {
class QREdgeDetector : public Detector {
public:
QREdgeDetector(Ref<BitMatrix> image);
virtual Ref<PerspectiveTransform> createTransform(Ref<ResultPoint> topLeft, Ref<ResultPoint> topRight, Ref <
ResultPoint > bottomLeft, Ref<ResultPoint> alignmentPattern, int dimension);
private:
Point findCorner(const BitMatrix& image, Point topLeft, Point topRight, Point bottomLeft, int dimension);
Line findPatternEdge(const BitMatrix& image, Point pattern, Point opposite, Point direction, bool invert);
Point endOfReverseBlackWhiteBlackRun(const BitMatrix& image, Point from, Point to);
Ref<PerspectiveTransform> get1CornerTransform(Point topLeft, Point topRight, Point bottomLeft, Point corner, int dimension);
};
}
}
#endif // QREDGEDETECTOR_H_

View File

@ -21,51 +21,49 @@
#include <zxing/qrcode/detector/FinderPattern.h>
namespace zxing {
namespace qrcode {
using std::abs;
using zxing::Ref;
using zxing::qrcode::FinderPattern;
FinderPattern::FinderPattern(float posX, float posY, float estimatedModuleSize)
: ResultPoint(posX,posY), estimatedModuleSize_(estimatedModuleSize), count_(1) {}
using namespace std;
FinderPattern::FinderPattern(float posX, float posY, float estimatedModuleSize, int count)
: ResultPoint(posX,posY), estimatedModuleSize_(estimatedModuleSize), count_(count) {}
FinderPattern::FinderPattern(float posX, float posY, float estimatedModuleSize) :
ResultPoint(posX,posY), estimatedModuleSize_(estimatedModuleSize), count_(1) {
}
int FinderPattern::getCount() const {
return count_;
}
FinderPattern::FinderPattern(float posX, float posY, float estimatedModuleSize, int count) :
ResultPoint(posX,posY), estimatedModuleSize_(estimatedModuleSize), count_(count) {
}
float FinderPattern::getEstimatedModuleSize() const {
return estimatedModuleSize_;
}
int FinderPattern::getCount() const {
return count_;
}
float FinderPattern::getEstimatedModuleSize() const {
return estimatedModuleSize_;
}
void FinderPattern::incrementCount() {
count_++;
}
void FinderPattern::incrementCount() {
count_++;
// cerr << "ic " << getX() << " " << getY() << " " << count_ << endl;
}
/*
bool FinderPattern::aboutEquals(float moduleSize, float i, float j) const {
return abs(i - posY_) <= moduleSize && abs(j - posX_) <= moduleSize && (abs(moduleSize - estimatedModuleSize_)
<= 1.0f || abs(moduleSize - estimatedModuleSize_) / estimatedModuleSize_ <= 0.1f);
}
bool FinderPattern::aboutEquals(float moduleSize, float i, float j) const {
return abs(i - posY_) <= moduleSize && abs(j - posX_) <= moduleSize && (abs(moduleSize - estimatedModuleSize_)
<= 1.0f || abs(moduleSize - estimatedModuleSize_) / estimatedModuleSize_ <= 0.1f);
}
*/
bool FinderPattern::aboutEquals(float moduleSize, float i, float j) const {
if (abs(i - getY()) <= moduleSize && abs(j - getX()) <= moduleSize) {
float moduleSizeDiff = abs(moduleSize - estimatedModuleSize_);
return moduleSizeDiff <= 1.0f || moduleSizeDiff <= estimatedModuleSize_;
}
return false;
}
Ref<FinderPattern> FinderPattern::combineEstimate(float i, float j, float newModuleSize) const {
int combinedCount = count_ + 1;
float combinedX = (count_ * getX() + j) / combinedCount;
float combinedY = (count_ * getY() + i) / combinedCount;
float combinedModuleSize = (count_ * getEstimatedModuleSize() + newModuleSize) / combinedCount;
return Ref<FinderPattern>(new FinderPattern(combinedX, combinedY, combinedModuleSize, combinedCount));
}
}
bool FinderPattern::aboutEquals(float moduleSize, float i, float j) const {
if (abs(i - getY()) <= moduleSize && abs(j - getX()) <= moduleSize) {
float moduleSizeDiff = abs(moduleSize - estimatedModuleSize_);
return moduleSizeDiff <= 1.0f || moduleSizeDiff <= estimatedModuleSize_;
}
return false;
}
Ref<FinderPattern> FinderPattern::combineEstimate(float i, float j, float newModuleSize) const {
// fprintf(stderr, "ce %f %f %f\n", i, j, newModuleSize);
int combinedCount = count_ + 1;
float combinedX = (count_ * getX() + j) / combinedCount;
float combinedY = (count_ * getY() + i) / combinedCount;
float combinedModuleSize = (count_ * getEstimatedModuleSize() + newModuleSize) / combinedCount;
return Ref<FinderPattern>(new FinderPattern(combinedX, combinedY, combinedModuleSize, combinedCount));
}

View File

@ -19,18 +19,28 @@
* limitations under the License.
*/
#include <algorithm>
#include <zxing/qrcode/detector/FinderPatternFinder.h>
#include <zxing/ReaderException.h>
#include <zxing/DecodeHints.h>
#include <vector>
#include <cmath>
#include <cstdlib>
#include <algorithm>
namespace zxing {
namespace qrcode {
using std::sort;
using std::max;
using std::abs;
using std::vector;
using zxing::Ref;
using zxing::qrcode::FinderPatternFinder;
using zxing::qrcode::FinderPattern;
using zxing::qrcode::FinderPatternInfo;
using namespace std;
// VC++
using zxing::BitMatrix;
using zxing::ResultPointCallback;
using zxing::ResultPoint;
using zxing::DecodeHints;
namespace {
class FurthestFromAverageComparator {
private:
@ -64,6 +74,8 @@ public:
}
};
}
int FinderPatternFinder::CENTER_QUORUM = 2;
int FinderPatternFinder::MIN_SKIP = 3;
int FinderPatternFinder::MAX_MODULES = 57;
@ -106,7 +118,7 @@ float FinderPatternFinder::crossCheckVertical(size_t startI, size_t centerJ, int
i--;
}
if (i < 0) {
return NAN;
return nan();
}
while (i >= 0 && !image_->get(centerJ, i) && stateCount[1] <= maxCount) {
stateCount[1]++;
@ -114,14 +126,14 @@ float FinderPatternFinder::crossCheckVertical(size_t startI, size_t centerJ, int
}
// If already too many modules in this state or ran off the edge:
if (i < 0 || stateCount[1] > maxCount) {
return NAN;
return nan();
}
while (i >= 0 && image_->get(centerJ, i) && stateCount[0] <= maxCount) {
stateCount[0]++;
i--;
}
if (stateCount[0] > maxCount) {
return NAN;
return nan();
}
// Now also count down from center
@ -131,31 +143,31 @@ float FinderPatternFinder::crossCheckVertical(size_t startI, size_t centerJ, int
i++;
}
if (i == maxI) {
return NAN;
return nan();
}
while (i < maxI && !image_->get(centerJ, i) && stateCount[3] < maxCount) {
stateCount[3]++;
i++;
}
if (i == maxI || stateCount[3] >= maxCount) {
return NAN;
return nan();
}
while (i < maxI && image_->get(centerJ, i) && stateCount[4] < maxCount) {
stateCount[4]++;
i++;
}
if (stateCount[4] >= maxCount) {
return NAN;
return nan();
}
// If we found a finder-pattern-like section, but its size is more than 40% different than
// the original, assume it's a false positive
int stateCountTotal = stateCount[0] + stateCount[1] + stateCount[2] + stateCount[3] + stateCount[4];
if (5 * abs(stateCountTotal - originalStateCountTotal) >= 2 * originalStateCountTotal) {
return NAN;
return nan();
}
return foundPatternCross(stateCount) ? centerFromEnd(stateCount, i) : NAN;
return foundPatternCross(stateCount) ? centerFromEnd(stateCount, i) : nan();
}
float FinderPatternFinder::crossCheckHorizontal(size_t startJ, size_t centerI, int maxCount,
@ -172,21 +184,21 @@ float FinderPatternFinder::crossCheckHorizontal(size_t startJ, size_t centerI, i
j--;
}
if (j < 0) {
return NAN;
return nan();
}
while (j >= 0 && !image_->get(j, centerI) && stateCount[1] <= maxCount) {
stateCount[1]++;
j--;
}
if (j < 0 || stateCount[1] > maxCount) {
return NAN;
return nan();
}
while (j >= 0 && image_->get(j, centerI) && stateCount[0] <= maxCount) {
stateCount[0]++;
j--;
}
if (stateCount[0] > maxCount) {
return NAN;
return nan();
}
j = startJ + 1;
@ -195,31 +207,31 @@ float FinderPatternFinder::crossCheckHorizontal(size_t startJ, size_t centerI, i
j++;
}
if (j == maxJ) {
return NAN;
return nan();
}
while (j < maxJ && !image_->get(j, centerI) && stateCount[3] < maxCount) {
stateCount[3]++;
j++;
}
if (j == maxJ || stateCount[3] >= maxCount) {
return NAN;
return nan();
}
while (j < maxJ && image_->get(j, centerI) && stateCount[4] < maxCount) {
stateCount[4]++;
j++;
}
if (stateCount[4] >= maxCount) {
return NAN;
return nan();
}
// If we found a finder-pattern-like section, but its size is significantly different than
// the original, assume it's a false positive
int stateCountTotal = stateCount[0] + stateCount[1] + stateCount[2] + stateCount[3] + stateCount[4];
if (5 * abs(stateCountTotal - originalStateCountTotal) >= originalStateCountTotal) {
return NAN;
return nan();
}
return foundPatternCross(stateCount) ? centerFromEnd(stateCount, j) : NAN;
return foundPatternCross(stateCount) ? centerFromEnd(stateCount, j) : nan();
}
bool FinderPatternFinder::handlePossibleCenter(int* stateCount, size_t i, size_t j) {
@ -308,7 +320,7 @@ bool FinderPatternFinder::haveMultiplyConfirmedCenters() {
return totalDeviation <= 0.05f * totalModuleSize;
}
vector<Ref<FinderPattern> > FinderPatternFinder::selectBestPatterns() {
vector< Ref<FinderPattern> > FinderPatternFinder::selectBestPatterns() {
size_t startSize = possibleCenters_.size();
if (startSize < 3) {
@ -537,5 +549,11 @@ Ref<FinderPatternInfo> FinderPatternFinder::find(DecodeHints const& hints) {
Ref<FinderPatternInfo> result(new FinderPatternInfo(patternInfo));
return result;
}
Ref<BitMatrix> FinderPatternFinder::getImage() {
return image_;
}
vector<Ref<FinderPattern> >& FinderPatternFinder::getPossibleCenters() {
return possibleCenters_;
}