mirror of
https://github.com/status-im/qzxing.git
synced 2025-02-13 03:16:40 +00:00
finished updating the library files of zxing library. haven't complied it yet.
This commit is contained in:
parent
d1fbe4ef20
commit
6e0972273a
@ -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 \
|
||||
|
@ -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__
|
@ -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);
|
||||
};
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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__
|
||||
|
@ -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)]
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -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&);
|
||||
|
@ -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();
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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");
|
||||
}
|
||||
|
||||
|
@ -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));
|
||||
}
|
||||
|
||||
|
@ -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());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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();
|
||||
|
@ -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__
|
||||
|
@ -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();
|
||||
|
@ -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&);
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -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");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -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
|
@ -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_
|
@ -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));
|
||||
}
|
||||
|
@ -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_;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user