1 // This file is part of OpenCV project.
2 // It is subject to the license terms in the LICENSE file found in the top-level directory
3 // of this distribution and at http://opencv.org/license.html.
4 //
5 // Tencent is pleased to support the open source community by making WeChat QRCode available.
6 // Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
7 //
8 // Modified from ZXing. Copyright ZXing authors.
9 // Licensed under the Apache License, Version 2.0 (the "License").
10 #include "../../../precomp.hpp"
11 #include "decoder.hpp"
12 #include "../error_correction_level.hpp"
13 #include "../version.hpp"
14 #include "datablock.hpp"
15 #include "decoded_bit_stream_parser.hpp"
16 #include "qrcode_decoder_metadata.hpp"
17
18 using zxing::DecoderResult;
19 using zxing::Ref;
20 using zxing::qrcode::Decoder;
21
22 // VC++
23 // The main class which implements QR Code decoding -- as opposed to locating
24 // and extracting the QR Code from an image.
25 using zxing::ArrayRef;
26 using zxing::BitMatrix;
27 using zxing::DetectorResult;
28 using zxing::ErrorHandler;
29
Decoder()30 Decoder::Decoder() : rsDecoder_(Ref<GenericGF>(GF_QR_CODE_FIELD_256)) {
31 possibleVersion_ = 0;
32 possibleFix_ = 0;
33 decoderState_ = NOTSTART;
34 }
35
36 // Convenience method that can decode a QR Code represented as a 2D array of
37 // booleans. "true" is taken to mean a black module.
decode(Ref<BitMatrix> bits,ErrorHandler & err_handler)38 Ref<DecoderResult> Decoder::decode(Ref<BitMatrix> bits, ErrorHandler &err_handler) {
39 string errMsg = "";
40
41 // Used for mirrored qrcode
42 int width = bits->getWidth();
43 int height = bits->getHeight();
44
45 Ref<BitMatrix> bits2(new BitMatrix(width, height, bits->getPtr(), err_handler));
46 if (err_handler.ErrCode()) return Ref<DecoderResult>();
47 Ref<DecoderResult> rst = decode(bits, false, err_handler);
48 if (err_handler.ErrCode() || rst == NULL) {
49 errMsg = err_handler.ErrMsg();
50 } else {
51 return rst;
52 }
53
54 err_handler.Reset();
55 Ref<DecoderResult> result = decode(bits2, true, err_handler);
56 if (err_handler.ErrCode()) {
57 return Ref<DecoderResult>();
58 } else {
59 // Success! Notify the caller that the code was mirrored.
60 result->setOther(Ref<QRCodeDecoderMetaData>(new QRCodeDecoderMetaData(true)));
61 return result;
62 }
63 };
64
decode(Ref<BitMatrix> bits,bool isMirror,ErrorHandler & err_handler)65 Ref<DecoderResult> Decoder::decode(Ref<BitMatrix> bits, bool isMirror, ErrorHandler &err_handler) {
66 // Ref<DecoderResult> Decoder::decode(BitMatrixParser& parser) {
67 // Construct a parser and read version, error-correction level
68 BitMatrixParser parser(bits, err_handler);
69 if (err_handler.ErrCode()) return Ref<DecoderResult>();
70
71 if (isMirror == true) {
72 // Revert the bit matrix
73 parser.remask();
74
75 // Will be attempting a mirrored reading of the version and format info.
76 parser.setMirror(true);
77
78 // Preemptively read the version.
79 parser.readVersion(err_handler);
80 if (err_handler.ErrCode()) {
81 err_handler = zxing::ReaderErrorHandler("Decoder::decode mirror & no mirror");
82 return Ref<DecoderResult>();
83 }
84
85 // Preemptively read the format information.
86 parser.readFormatInformation(err_handler);
87 if (err_handler.ErrCode()) return Ref<DecoderResult>();
88
89 /*
90 * Since we're here, this means we have successfully detected some kind
91 * of version and format information when mirrored. This is a good sign,
92 * that the QR code may be mirrored, and we should try once more with a
93 * mirrored content.
94 */
95 // Prepare for a mirrored reading.
96 parser.mirror();
97 }
98
99 decoderState_ = START;
100 possibleFix_ = 0;
101 Version *version = parser.readVersion(err_handler);
102 if (err_handler.ErrCode() || version == NULL) {
103 err_handler = ReaderErrorHandler("Decoder::decode mirror & no mirror");
104 return Ref<DecoderResult>();
105 }
106 decoderState_ = READVERSION;
107 float fixedPatternScore = estimateFixedPattern(bits, version, err_handler);
108 if (err_handler.ErrCode()) return Ref<DecoderResult>();
109
110 Ref<FormatInformation> formatInfo = parser.readFormatInformation(err_handler);
111 if (err_handler.ErrCode()) return Ref<DecoderResult>();
112 ErrorCorrectionLevel &ecLevel = formatInfo->getErrorCorrectionLevel();
113
114 decoderState_ = READERRORCORRECTIONLEVEL;
115
116 // Read codewords
117 ArrayRef<char> codewords(parser.readCodewords(err_handler));
118 if (err_handler.ErrCode()) {
119 err_handler = zxing::ReaderErrorHandler("Decoder::decode mirror & no mirror");
120 return Ref<DecoderResult>();
121 }
122
123 decoderState_ = READCODEWORDSORRECTIONLEVEL;
124 possibleFix_ = fixedPatternScore;
125
126 // Separate into data blocks
127 std::vector<Ref<DataBlock> > dataBlocks(
128 DataBlock::getDataBlocks(codewords, version, ecLevel, err_handler));
129 if (err_handler.ErrCode()) return Ref<DecoderResult>();
130
131 // Count total number of data bytes
132 int totalBytes = 0;
133 for (size_t i = 0; i < dataBlocks.size(); i++) {
134 totalBytes += dataBlocks[i]->getNumDataCodewords();
135 }
136 ArrayRef<char> resultBytes(totalBytes);
137 int resultOffset = 0;
138
139 // Error-correct and copy data blocks together into a stream of bytes
140 for (size_t j = 0; j < dataBlocks.size(); j++) {
141 err_handler.Reset();
142 Ref<DataBlock> dataBlock(dataBlocks[j]);
143 ArrayRef<char> codewordBytes = dataBlock->getCodewords();
144 int numDataCodewords = dataBlock->getNumDataCodewords();
145
146 correctErrors(codewordBytes, numDataCodewords, err_handler);
147 if (err_handler.ErrCode()) return Ref<DecoderResult>();
148
149 for (int i = 0; i < numDataCodewords; i++) {
150 resultBytes[resultOffset++] = codewordBytes[i];
151 }
152 }
153
154 decoderState_ = FINISH;
155 // return DecodedBitStreamParser::decode(resultBytes,
156 DecodedBitStreamParser dbs_parser;
157 Ref<DecoderResult> rst =
158 dbs_parser.decode(resultBytes, version, ecLevel, err_handler, version->getVersionNumber());
159
160 if (err_handler.ErrCode()) return Ref<DecoderResult>();
161 return rst;
162 }
163
164 // Given data and error-correction codewords received, possibly corrupted by
165 // errors, attempts to correct the errors in-place using Reed-Solomon error
166 // correction.</p> codewordBytes: data and error correction codewords
167 // numDataCodewords: number of codewords that are data bytes
correctErrors(ArrayRef<char> codewordBytes,int numDataCodewords,ErrorHandler & err_handler)168 void Decoder::correctErrors(ArrayRef<char> codewordBytes, int numDataCodewords,
169 ErrorHandler &err_handler) {
170 // First read into an arrya of ints
171 int numCodewords = codewordBytes->size();
172 ArrayRef<int> codewordInts(numCodewords);
173 for (int i = 0; i < numCodewords; i++) {
174 codewordInts[i] = codewordBytes[i] & 0xff;
175 }
176 int numECCodewords = numCodewords - numDataCodewords;
177 bool correctErrorsFinishished = false;
178
179 rsDecoder_.decode(codewordInts, numECCodewords, err_handler);
180 if (err_handler.ErrCode()) {
181 return;
182 }
183
184 correctErrorsFinishished = true;
185
186 // Copy back into array of bytes -- only need to worry about the bytes that
187 // were data We don't care about errors in the error-correction codewords
188 if (correctErrorsFinishished) {
189 for (int i = 0; i < numDataCodewords; i++) {
190 codewordBytes[i] = (char)codewordInts[i];
191 }
192 }
193 }
194
getPossibleVersion()195 unsigned int Decoder::getPossibleVersion() { return possibleVersion_; }
196
estimateFixedPattern(Ref<BitMatrix> bits,zxing::qrcode::Version * version,ErrorHandler & err_handler)197 float Decoder::estimateFixedPattern(Ref<BitMatrix> bits, zxing::qrcode::Version *version,
198 ErrorHandler &err_handler) {
199 Ref<BitMatrix> fixedPatternValue = version->buildFixedPatternValue(err_handler);
200 if (err_handler.ErrCode()) {
201 err_handler = zxing::ReaderErrorHandler("Decoder::decode mirror & no mirror");
202 return -1.0;
203 }
204 Ref<BitMatrix> fixedPatternTemplate = version->buildFixedPatternTemplate(err_handler);
205 if (err_handler.ErrCode()) {
206 err_handler = zxing::ReaderErrorHandler("Decoder::decode mirror & no mirror");
207 return -1.0;
208 }
209
210 int iSum = 0;
211 int iCount = 0;
212 for (int i = 0; i < bits->getHeight(); ++i) {
213 for (int j = 0; j < bits->getWidth(); ++j) {
214 if (fixedPatternTemplate->get(i, j)) {
215 iSum++;
216 if (bits->get(i, j) == fixedPatternValue->get(i, j)) iCount++;
217 }
218 }
219 }
220
221 float possbielFix = 2.0 * iCount / iSum - 1;
222 return possbielFix > 0 ? possbielFix : 0;
223 }
224