mirror of https://github.com/status-im/qzxing.git
I found that if QR-Code was generated with non standard charSet (and the message language is not English) than decoded QString contains wrong characters. So we must use QTextCodec to make it readable.
Now tagFound signal emits decoded string. If you want to know what code was detected and what charSet is used, use tagFoundAdvanced(QString tag, QString format, QString charSet) signal or functions foundedFormat() and charSet().
This commit is contained in:
parent
13720010fc
commit
4df9512790
|
@ -114,7 +114,7 @@ ArrayRef<char> CameraImageWrapper::getMatrix() const
|
|||
ArrayRef<char> tmpRow;
|
||||
tmpRow = getRow(y, ArrayRef<char>(width));
|
||||
#if __cplusplus > 199711L
|
||||
memcpy(m, tmpRow->values()..data(), width);
|
||||
memcpy(m, tmpRow->values().data(), width);
|
||||
#else
|
||||
memcpy(m, &tmpRow->values()[0], width);
|
||||
#endif
|
||||
|
|
|
@ -30,7 +30,7 @@ class
|
|||
#ifndef DISABLE_LIBRARY_FEATURES
|
||||
QZXINGSHARED_EXPORT
|
||||
#endif
|
||||
QZXing : public QObject{
|
||||
QZXing : public QObject {
|
||||
|
||||
Q_OBJECT
|
||||
Q_ENUMS(DecoderFormat)
|
||||
|
@ -75,6 +75,10 @@ public:
|
|||
}
|
||||
#endif
|
||||
|
||||
QString decoderFormatToString(int fmt);
|
||||
QString foundedFormat() const;
|
||||
QString charSet() const;
|
||||
|
||||
public slots:
|
||||
/**
|
||||
* The decoding function. Will try to decode the given image based on the enabled decoders.
|
||||
|
@ -85,13 +89,13 @@ public slots:
|
|||
* The smoothTransformation flag determines whether the transformation will be smooth or fast.
|
||||
* Smooth transformation provides better results but fast transformation is...faster.
|
||||
*/
|
||||
QString decodeImage(QImage &image, int maxWidth=-1, int maxHeight=-1, bool smoothTransformation = false);
|
||||
QString decodeImage(QImage &image, int maxWidth = -1, int maxHeight = -1, bool smoothTransformation = false);
|
||||
|
||||
/**
|
||||
* The decoding function. Will try to decode the given image based on the enabled decoders.
|
||||
* The input image is read from a local image file.
|
||||
*/
|
||||
QString decodeImageFromFile(QString imageFilePath, int maxWidth=-1, int maxHeight=-1, bool smoothTransformation = false);
|
||||
QString decodeImageFromFile(QString imageFilePath, int maxWidth = -1, int maxHeight = -1, bool smoothTransformation = false);
|
||||
|
||||
/**
|
||||
* The decoding function accessible from QML. (Suggested for Qt 4.x)
|
||||
|
@ -102,7 +106,7 @@ public slots:
|
|||
* The decoding function accessible from QML. Able to set the decoding
|
||||
* of a portion of the image. (Suggested for Qt 4.x)
|
||||
*/
|
||||
QString decodeSubImageQML(QObject* item,
|
||||
QString decodeSubImageQML(QObject *item,
|
||||
const double offsetX = 0 , const double offsetY = 0,
|
||||
const double width = 0, const double height = 0);
|
||||
|
||||
|
@ -123,6 +127,7 @@ public slots:
|
|||
QString decodeSubImageQML(const QUrl &imageUrl,
|
||||
const double offsetX = 0, const double offsetY = 0,
|
||||
const double width = 0, const double height = 0);
|
||||
|
||||
/**
|
||||
* Get the prossecing time in millisecond of the last decode operation.
|
||||
* Added mainly as a statistic measure.
|
||||
|
@ -140,7 +145,7 @@ public slots:
|
|||
* As argument it is possible to pass conjuction of decoders by using logic OR.
|
||||
* e.x. setDecoder ( DecoderFormat_QR_CODE | DecoderFormat_EAN_13 | DecoderFormat_CODE_39 )
|
||||
*/
|
||||
void setDecoder(const uint& hint);
|
||||
void setDecoder(const uint &hint);
|
||||
|
||||
signals:
|
||||
void decodingStarted();
|
||||
|
@ -149,10 +154,12 @@ signals:
|
|||
void enabledFormatsChanged();
|
||||
|
||||
private:
|
||||
zxing::MultiFormatReader* decoder;
|
||||
zxing::MultiFormatReader *decoder;
|
||||
DecoderFormatType enabledDecoders;
|
||||
ImageHandler* imageHandler;
|
||||
ImageHandler *imageHandler;
|
||||
int processingTime;
|
||||
QString foundedFmt;
|
||||
QString charSet_;
|
||||
|
||||
/**
|
||||
* If true, the decoding operation will take place at a different thread.
|
||||
|
|
|
@ -16,7 +16,7 @@ QImage ImageHandler::extractQImage(QObject *imageObj,
|
|||
{
|
||||
QGraphicsObject *item = qobject_cast<QGraphicsObject*>(imageObj);
|
||||
|
||||
if (!item ) {
|
||||
if (!item) {
|
||||
qDebug() << "Item is NULL";
|
||||
return QImage();
|
||||
}
|
||||
|
|
|
@ -44,6 +44,73 @@ QZXing::QZXing(QZXing::DecoderFormat decodeHints, QObject *parent) : QObject(par
|
|||
setDecoder(decodeHints);
|
||||
}
|
||||
|
||||
QString QZXing::decoderFormatToString(int fmt)
|
||||
{
|
||||
switch (fmt) {
|
||||
case 1:
|
||||
return "AZTEC";
|
||||
|
||||
case 2:
|
||||
return "CODABAR";
|
||||
|
||||
case 3:
|
||||
return "CODE_39";
|
||||
|
||||
case 4:
|
||||
return "CODE_93";
|
||||
|
||||
case 5:
|
||||
return "CODE_128";
|
||||
|
||||
case 6:
|
||||
return "DATA_MATRIX";
|
||||
|
||||
case 7:
|
||||
return "EAN_8";
|
||||
|
||||
case 8:
|
||||
return "EAN_13";
|
||||
|
||||
case 9:
|
||||
return "ITF";
|
||||
|
||||
case 10:
|
||||
return "MAXICODE";
|
||||
|
||||
case 11:
|
||||
return "PDF_417";
|
||||
|
||||
case 12:
|
||||
return "QR_CODE";
|
||||
|
||||
case 13:
|
||||
return "RSS_14";
|
||||
|
||||
case 14:
|
||||
return "RSS_EXPANDED";
|
||||
|
||||
case 15:
|
||||
return "UPC_A";
|
||||
|
||||
case 16:
|
||||
return "UPC_E";
|
||||
|
||||
case 17:
|
||||
return "UPC_EAN_EXTENSION";
|
||||
} // switch
|
||||
return QString();
|
||||
}
|
||||
|
||||
QString QZXing::foundedFormat() const
|
||||
{
|
||||
return foundedFmt;
|
||||
}
|
||||
|
||||
QString QZXing::charSet() const
|
||||
{
|
||||
return charSet_;
|
||||
}
|
||||
|
||||
void QZXing::setDecoder(const uint &hint)
|
||||
{
|
||||
unsigned int newHints = 0;
|
||||
|
@ -113,50 +180,59 @@ QString QZXing::decodeImage(QImage &image, int maxWidth, int maxHeight, bool smo
|
|||
|
||||
if(image.isNull())
|
||||
{
|
||||
qDebug() << "Image Null";
|
||||
qDebug() << "Image is Null";
|
||||
emit decodingFinished(false);
|
||||
processingTime = -1;
|
||||
processingTime = t.elapsed();
|
||||
return "";
|
||||
}
|
||||
|
||||
CameraImageWrapper* ciw;
|
||||
|
||||
try{
|
||||
if(maxWidth > 0 || maxHeight > 0)
|
||||
CameraImageWrapper *ciw = NULL;
|
||||
try {
|
||||
if ((maxWidth > 0) || (maxHeight > 0))
|
||||
ciw = CameraImageWrapper::Factory(image, maxWidth, maxHeight, smoothTransformation);
|
||||
else
|
||||
ciw = new CameraImageWrapper(image);
|
||||
|
||||
Ref<LuminanceSource> imageRef(ciw);
|
||||
GlobalHistogramBinarizer* binz = new GlobalHistogramBinarizer(imageRef);
|
||||
GlobalHistogramBinarizer *binz = new GlobalHistogramBinarizer(imageRef);
|
||||
|
||||
Ref<Binarizer> bz (binz);
|
||||
BinaryBitmap* bb = new BinaryBitmap(bz);
|
||||
Ref<Binarizer> bz(binz);
|
||||
BinaryBitmap *bb = new BinaryBitmap(bz);
|
||||
|
||||
Ref<BinaryBitmap> ref(bb);
|
||||
|
||||
res = decoder->decode(ref, DecodeHints((int)enabledDecoders));
|
||||
|
||||
QString string = QString(res->getText()->getText().c_str());
|
||||
processingTime = t.elapsed();
|
||||
qDebug() << "Deconding succeeded: " << string;
|
||||
if (!string.isEmpty() && (string.length() > 0)) {
|
||||
int fmt = res->getBarcodeFormat().value;
|
||||
foundedFmt = decoderFormatToString(fmt);
|
||||
charSet_ = QString::fromStdString(res->getCharSet());
|
||||
if (!charSet_.isEmpty()) {
|
||||
QTextCodec *codec = QTextCodec::codecForName(res->getCharSet().c_str());
|
||||
if (codec)
|
||||
string = codec->toUnicode(res->getText()->getText().c_str());
|
||||
}
|
||||
emit tagFound(string);
|
||||
emit tagFoundAdvanced(string, foundedFmt, charSet_);
|
||||
}
|
||||
processingTime = t.elapsed();
|
||||
emit decodingFinished(true);
|
||||
return string;
|
||||
}
|
||||
catch(zxing::Exception& /*e*/)
|
||||
catch(zxing::Exception &e)
|
||||
{
|
||||
qDebug() << "Deconding failed";
|
||||
emit error(QString(e.what()));
|
||||
emit decodingFinished(false);
|
||||
processingTime = -1;
|
||||
processingTime = t.elapsed();
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
QString QZXing::decodeImageFromFile(QString imageFilePath, int maxWidth, int maxHeight, bool smoothTransformation)
|
||||
{
|
||||
//used to have a check if this image exists
|
||||
//but was removed because if the image file path doesn't point to a valid image
|
||||
// used to have a check if this image exists
|
||||
// but was removed because if the image file path doesn't point to a valid image
|
||||
// then the QImage::isNull will return true and the decoding will fail eitherway.
|
||||
QImage tmpImage = QImage(imageFilePath);
|
||||
return decodeImage(tmpImage, maxWidth, maxHeight, smoothTransformation);
|
||||
|
@ -167,12 +243,13 @@ QString QZXing::decodeImageQML(QObject *item)
|
|||
return decodeSubImageQML(item);
|
||||
}
|
||||
|
||||
QString QZXing::decodeSubImageQML(QObject* item,
|
||||
QString QZXing::decodeSubImageQML(QObject *item,
|
||||
const double offsetX, const double offsetY,
|
||||
const double width, const double height)
|
||||
{
|
||||
if(item == NULL)
|
||||
{
|
||||
processingTime = 0;
|
||||
emit decodingFinished(false);
|
||||
return "";
|
||||
}
|
||||
|
@ -186,6 +263,7 @@ QString QZXing::decodeImageQML(const QUrl &imageUrl)
|
|||
{
|
||||
return decodeSubImageQML(imageUrl);
|
||||
}
|
||||
|
||||
QString QZXing::decodeSubImageQML(const QUrl &imageUrl,
|
||||
const double offsetX, const double offsetY,
|
||||
const double width, const double height)
|
||||
|
@ -214,7 +292,3 @@ uint QZXing::getEnabledFormats() const
|
|||
{
|
||||
return enabledDecoders;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -33,8 +33,8 @@ using zxing::BarcodeFormat;
|
|||
Result::Result(Ref<String> text,
|
||||
ArrayRef<char> rawBytes,
|
||||
ArrayRef< Ref<ResultPoint> > resultPoints,
|
||||
BarcodeFormat format) :
|
||||
text_(text), rawBytes_(rawBytes), resultPoints_(resultPoints), format_(format) {
|
||||
BarcodeFormat format, std::string charSet) :
|
||||
text_(text), rawBytes_(rawBytes), resultPoints_(resultPoints), format_(format), charSet_(charSet) {
|
||||
}
|
||||
|
||||
Result::~Result() {
|
||||
|
@ -59,3 +59,8 @@ ArrayRef< Ref<ResultPoint> >& Result::getResultPoints() {
|
|||
zxing::BarcodeFormat Result::getBarcodeFormat() const {
|
||||
return format_;
|
||||
}
|
||||
|
||||
std::string Result::getCharSet() const
|
||||
{
|
||||
return charSet_;
|
||||
}
|
||||
|
|
|
@ -35,18 +35,21 @@ private:
|
|||
ArrayRef<char> rawBytes_;
|
||||
ArrayRef< Ref<ResultPoint> > resultPoints_;
|
||||
BarcodeFormat format_;
|
||||
//NOTE: My
|
||||
std::string charSet_;
|
||||
|
||||
public:
|
||||
Result(Ref<String> text,
|
||||
ArrayRef<char> rawBytes,
|
||||
ArrayRef< Ref<ResultPoint> > resultPoints,
|
||||
BarcodeFormat format);
|
||||
BarcodeFormat format, std::string charSet = "");
|
||||
~Result();
|
||||
Ref<String> getText();
|
||||
ArrayRef<char> getRawBytes();
|
||||
ArrayRef< Ref<ResultPoint> > const& getResultPoints() const;
|
||||
ArrayRef< Ref<ResultPoint> >& getResultPoints();
|
||||
BarcodeFormat getBarcodeFormat() const;
|
||||
std::string getCharSet() const;
|
||||
|
||||
friend std::ostream& operator<<(std::ostream &out, Result& result);
|
||||
};
|
||||
|
|
|
@ -27,15 +27,15 @@ using namespace zxing;
|
|||
DecoderResult::DecoderResult(ArrayRef<char> rawBytes,
|
||||
Ref<String> text,
|
||||
ArrayRef< ArrayRef<char> >& byteSegments,
|
||||
string const& ecLevel) :
|
||||
string const& ecLevel, string charSet) :
|
||||
rawBytes_(rawBytes),
|
||||
text_(text),
|
||||
byteSegments_(byteSegments),
|
||||
ecLevel_(ecLevel) {}
|
||||
ecLevel_(ecLevel), charSet_(charSet) {}
|
||||
|
||||
DecoderResult::DecoderResult(ArrayRef<char> rawBytes,
|
||||
Ref<String> text)
|
||||
: rawBytes_(rawBytes), text_(text) {}
|
||||
: rawBytes_(rawBytes), text_(text),charSet_("") {}
|
||||
|
||||
ArrayRef<char> DecoderResult::getRawBytes() {
|
||||
return rawBytes_;
|
||||
|
@ -44,3 +44,8 @@ ArrayRef<char> DecoderResult::getRawBytes() {
|
|||
Ref<String> DecoderResult::getText() {
|
||||
return text_;
|
||||
}
|
||||
|
||||
string DecoderResult::charSet()
|
||||
{
|
||||
return charSet_;
|
||||
}
|
||||
|
|
|
@ -33,17 +33,21 @@ private:
|
|||
Ref<String> text_;
|
||||
ArrayRef< ArrayRef<char> > byteSegments_;
|
||||
std::string ecLevel_;
|
||||
std::string charSet_;
|
||||
|
||||
public:
|
||||
DecoderResult(ArrayRef<char> rawBytes,
|
||||
Ref<String> text,
|
||||
ArrayRef< ArrayRef<char> >& byteSegments,
|
||||
std::string const& ecLevel);
|
||||
std::string const& ecLevel,
|
||||
std::string charSet = "");
|
||||
|
||||
DecoderResult(ArrayRef<char> rawBytes, Ref<String> text);
|
||||
|
||||
ArrayRef<char> getRawBytes();
|
||||
Ref<String> getText();
|
||||
// NOTE: my
|
||||
std::string charSet();
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -31,14 +31,14 @@ namespace zxing {
|
|||
|
||||
QRCodeReader::QRCodeReader() :decoder_() {
|
||||
}
|
||||
//TODO: see if any of the other files in the qrcode tree need tryHarder
|
||||
//TODO : see if any of the other files in the qrcode tree need tryHarder
|
||||
Ref<Result> QRCodeReader::decode(Ref<BinaryBitmap> image, DecodeHints hints) {
|
||||
Detector detector(image->getBlackMatrix());
|
||||
Ref<DetectorResult> detectorResult(detector.detect(hints));
|
||||
ArrayRef< Ref<ResultPoint> > points (detectorResult->getPoints());
|
||||
Ref<DecoderResult> decoderResult(decoder_.decode(detectorResult->getBits()));
|
||||
Ref<Result> result(
|
||||
new Result(decoderResult->getText(), decoderResult->getRawBytes(), points, BarcodeFormat::QR_CODE));
|
||||
new Result(decoderResult->getText(), decoderResult->getRawBytes(), points, BarcodeFormat::QR_CODE, decoderResult->charSet()));
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
|
@ -47,7 +47,7 @@ private:
|
|||
static void decodeHanziSegment(Ref<BitSource> bits, std::string &result, int count);
|
||||
static void decodeKanjiSegment(Ref<BitSource> bits, std::string &result, int count);
|
||||
static void decodeByteSegment(Ref<BitSource> bits, std::string &result, int count);
|
||||
static void decodeByteSegment(Ref<BitSource> bits_,
|
||||
static std::string decodeByteSegment(Ref<BitSource> bits_,
|
||||
std::string& result,
|
||||
int count,
|
||||
zxing::common::CharacterSetECI* currentCharacterSetECI,
|
||||
|
|
|
@ -28,7 +28,7 @@
|
|||
#include <iconv.h>
|
||||
#endif
|
||||
|
||||
// Required for compatibility. TODO: test on Symbian
|
||||
// Required for compatibility. TODO : test on Symbian
|
||||
#ifdef ZXING_ICONV_CONST
|
||||
#undef ICONV_CONST
|
||||
#define ICONV_CONST const
|
||||
|
@ -46,11 +46,11 @@ 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',
|
||||
{ '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;}
|
||||
|
||||
|
@ -102,6 +102,7 @@ void DecodedBitStreamParser::append(std::string &result,
|
|||
result.append((const char *)bufOut);
|
||||
delete[] bufOut;
|
||||
#else
|
||||
Q_UNUSED(src);
|
||||
result.append((const char *)bufIn, nIn);
|
||||
#endif
|
||||
}
|
||||
|
@ -181,7 +182,7 @@ void DecodedBitStreamParser::decodeKanjiSegment(Ref<BitSource> bits, std::string
|
|||
delete[] buffer;
|
||||
}
|
||||
|
||||
void DecodedBitStreamParser::decodeByteSegment(Ref<BitSource> bits_,
|
||||
std::string DecodedBitStreamParser::decodeByteSegment(Ref<BitSource> bits_,
|
||||
string& result,
|
||||
int count,
|
||||
CharacterSetECI* currentCharacterSetECI,
|
||||
|
@ -217,6 +218,7 @@ void DecodedBitStreamParser::decodeByteSegment(Ref<BitSource> bits_,
|
|||
throw FormatException();
|
||||
}
|
||||
byteSegments->values().push_back(bytes_);
|
||||
return encoding;
|
||||
}
|
||||
|
||||
void DecodedBitStreamParser::decodeNumericSegment(Ref<BitSource> bits, std::string &result, int count) {
|
||||
|
@ -327,7 +329,7 @@ void DecodedBitStreamParser::decodeAlphanumericSegment(Ref<BitSource> bits_,
|
|||
}
|
||||
|
||||
namespace {
|
||||
int parseECIValue(BitSource& bits) {
|
||||
int parseECIValue(BitSource& bits) {
|
||||
int firstByte = bits.readBits(8);
|
||||
if ((firstByte & 0x80) == 0) {
|
||||
// just one byte
|
||||
|
@ -344,7 +346,7 @@ namespace {
|
|||
return ((firstByte & 0x1F) << 16) | secondThirdBytes;
|
||||
}
|
||||
throw FormatException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ref<DecoderResult>
|
||||
|
@ -357,8 +359,9 @@ DecodedBitStreamParser::decode(ArrayRef<char> bytes,
|
|||
string result;
|
||||
result.reserve(50);
|
||||
ArrayRef< ArrayRef<char> > byteSegments (0);
|
||||
try {
|
||||
CharacterSetECI* currentCharacterSetECI = 0;
|
||||
string charSet = "";
|
||||
try {
|
||||
bool fc1InEffect = false;
|
||||
Mode* mode = 0;
|
||||
do {
|
||||
|
@ -410,7 +413,7 @@ DecodedBitStreamParser::decode(ArrayRef<char> bytes,
|
|||
} else if (mode == &Mode::ALPHANUMERIC) {
|
||||
decodeAlphanumericSegment(bits_, result, count, fc1InEffect);
|
||||
} else if (mode == &Mode::BYTE) {
|
||||
decodeByteSegment(bits_, result, count, currentCharacterSetECI, byteSegments, hints);
|
||||
charSet = decodeByteSegment(bits_, result, count, currentCharacterSetECI, byteSegments, hints);
|
||||
} else if (mode == &Mode::KANJI) {
|
||||
decodeKanjiSegment(bits_, result, count);
|
||||
} else {
|
||||
|
@ -425,7 +428,6 @@ DecodedBitStreamParser::decode(ArrayRef<char> bytes,
|
|||
// from readBits() calls
|
||||
throw FormatException();
|
||||
}
|
||||
|
||||
return Ref<DecoderResult>(new DecoderResult(bytes, Ref<String>(new String(result)), byteSegments, (string)ecLevel));
|
||||
return Ref<DecoderResult>(new DecoderResult(bytes, Ref<String>(new String(result)), byteSegments, (string)ecLevel, charSet));
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue