5 * Created by Christian Brunschen on 20/05/2008.
6 * Copyright 2008 ZXing authors All rights reserved.
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
12 * http://www.apache.org/licenses/LICENSE-2.0
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
21 #include <zxing/qrcode/decoder/BitMatrixParser.h>
22 #include <zxing/qrcode/decoder/DataMask.h>
28 int BitMatrixParser::copyBit(size_t x, size_t y, int versionBits) {
29 return bitMatrix_->get(x, y) ? (versionBits << 1) | 0x1 : versionBits << 1;
32 BitMatrixParser::BitMatrixParser(Ref<BitMatrix> bitMatrix) :
33 bitMatrix_(bitMatrix), parsedVersion_(0), parsedFormatInfo_() {
34 size_t dimension = bitMatrix->getDimension();
35 if ((dimension < 21) || (dimension & 0x03) != 1) {
36 throw ReaderException("Dimension must be 1 mod 4 and >= 21");
40 Ref<FormatInformation> BitMatrixParser::readFormatInformation() {
41 if (parsedFormatInfo_ != 0) {
42 return parsedFormatInfo_;
45 // Read top-left format info bits
46 int formatInfoBits = 0;
47 for (int x = 0; x < 6; x++) {
48 formatInfoBits = copyBit(x, 8, formatInfoBits);
50 // .. and skip a bit in the timing pattern ...
51 formatInfoBits = copyBit(7, 8, formatInfoBits);
52 formatInfoBits = copyBit(8, 8, formatInfoBits);
53 formatInfoBits = copyBit(8, 7, formatInfoBits);
54 // .. and skip a bit in the timing pattern ...
55 for (int y = 5; y >= 0; y--) {
56 formatInfoBits = copyBit(8, y, formatInfoBits);
59 parsedFormatInfo_ = FormatInformation::decodeFormatInformation(formatInfoBits);
60 if (parsedFormatInfo_ != 0) {
61 return parsedFormatInfo_;
64 // Hmm, failed. Try the top-right/bottom-left pattern
65 int dimension = bitMatrix_->getDimension();
67 int yMin = dimension - 8;
68 for (int y = dimension - 1; y >= yMin; y--) {
69 formatInfoBits = copyBit(8, y, formatInfoBits);
71 for (int x = dimension - 7; x < dimension; x++) {
72 formatInfoBits = copyBit(x, 8, formatInfoBits);
75 parsedFormatInfo_ = FormatInformation::decodeFormatInformation(formatInfoBits);
76 if (parsedFormatInfo_ != 0) {
77 return parsedFormatInfo_;
79 throw ReaderException("Could not decode format information");
82 Version *BitMatrixParser::readVersion() {
83 if (parsedVersion_ != 0) {
84 return parsedVersion_;
87 int dimension = bitMatrix_->getDimension();
89 int provisionalVersion = (dimension - 17) >> 2;
90 if (provisionalVersion <= 6) {
91 return Version::getVersionForNumber(provisionalVersion);
94 // Read top-right version info: 3 wide by 6 tall
96 for (int y = 5; y >= 0; y--) {
97 int xMin = dimension - 11;
98 for (int x = dimension - 9; x >= xMin; x--) {
99 versionBits = copyBit(x, y, versionBits);
103 parsedVersion_ = Version::decodeVersionInformation(versionBits);
104 if (parsedVersion_ != 0 && parsedVersion_->getDimensionForVersion() == dimension) {
105 return parsedVersion_;
108 // Hmm, failed. Try bottom left: 6 wide by 3 tall
110 for (int x = 5; x >= 0; x--) {
111 int yMin = dimension - 11;
112 for (int y = dimension - 9; y >= yMin; y--) {
113 versionBits = copyBit(x, y, versionBits);
117 parsedVersion_ = Version::decodeVersionInformation(versionBits);
118 if (parsedVersion_ != 0 && parsedVersion_->getDimensionForVersion() == dimension) {
119 return parsedVersion_;
121 throw ReaderException("Could not decode version");
124 ArrayRef<unsigned char> BitMatrixParser::readCodewords() {
125 Ref<FormatInformation> formatInfo = readFormatInformation();
126 Version *version = readVersion();
129 // cerr << *bitMatrix_ << endl;
130 // cerr << bitMatrix_->getDimension() << endl;
132 // Get the data mask for the format used in this QR Code. This will exclude
133 // some bits from reading as we wind through the bit matrix.
134 DataMask &dataMask = DataMask::forReference((int)formatInfo->getDataMask());
135 // cout << (int)formatInfo->getDataMask() << endl;
136 int dimension = bitMatrix_->getDimension();
137 dataMask.unmaskBitMatrix(*bitMatrix_, dimension);
140 // cerr << *bitMatrix_ << endl;
141 // cerr << version->getTotalCodewords() << endl;
143 Ref<BitMatrix> functionPattern = version->buildFunctionPattern();
146 // cout << *functionPattern << endl;
148 bool readingUp = true;
149 ArrayRef<unsigned char> result(version->getTotalCodewords());
150 int resultOffset = 0;
153 // Read columns in pairs, from right to left
154 for (int x = dimension - 1; x > 0; x -= 2) {
156 // Skip whole column with vertical alignment pattern;
157 // saves time and makes the other code proceed more cleanly
160 // Read alternatingly from bottom to top then top to bottom
161 for (int counter = 0; counter < dimension; counter++) {
162 int y = readingUp ? dimension - 1 - counter : counter;
163 for (int col = 0; col < 2; col++) {
164 // Ignore bits covered by the function pattern
165 if (!functionPattern->get(x - col, y)) {
169 if (bitMatrix_->get(x - col, y)) {
172 // If we've made a whole byte, save it off
174 result[resultOffset++] = (unsigned char)currentByte;
181 readingUp = !readingUp; // switch directions
184 if (resultOffset != version->getTotalCodewords()) {
185 throw ReaderException("Did not read all codewords");