04cd06bc54e0c06978c807152fa839a18831fef1
[zxing.git] / cpp / core / src / zxing / qrcode / decoder / BitMatrixParser.cpp
1 /*
2  *  BitMatrixParser.cpp
3  *  zxing
4  *
5  *  Created by Christian Brunschen on 20/05/2008.
6  *  Copyright 2008 ZXing authors All rights reserved.
7  *
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
11  *
12  *      http://www.apache.org/licenses/LICENSE-2.0
13  *
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.
19  */
20
21 #include <zxing/qrcode/decoder/BitMatrixParser.h>
22 #include <zxing/qrcode/decoder/DataMask.h>
23
24
25 namespace zxing {
26 namespace qrcode {
27
28 int BitMatrixParser::copyBit(size_t x, size_t y, int versionBits) {
29   return bitMatrix_->get(x, y) ? (versionBits << 1) | 0x1 : versionBits << 1;
30 }
31
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");
37   }
38 }
39
40 Ref<FormatInformation> BitMatrixParser::readFormatInformation() {
41   if (parsedFormatInfo_ != 0) {
42     return parsedFormatInfo_;
43   }
44
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);
49   }
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);
57   }
58
59   parsedFormatInfo_ = FormatInformation::decodeFormatInformation(formatInfoBits);
60   if (parsedFormatInfo_ != 0) {
61     return parsedFormatInfo_;
62   }
63
64   // Hmm, failed. Try the top-right/bottom-left pattern
65   int dimension = bitMatrix_->getDimension();
66   formatInfoBits = 0;
67   int yMin = dimension - 8;
68   for (int y = dimension - 1; y >= yMin; y--) {
69     formatInfoBits = copyBit(8, y, formatInfoBits);
70   }
71   for (int x = dimension - 7; x < dimension; x++) {
72     formatInfoBits = copyBit(x, 8, formatInfoBits);
73   }
74
75   parsedFormatInfo_ = FormatInformation::decodeFormatInformation(formatInfoBits);
76   if (parsedFormatInfo_ != 0) {
77     return parsedFormatInfo_;
78   }
79   throw ReaderException("Could not decode format information");
80 }
81
82 Version *BitMatrixParser::readVersion() {
83   if (parsedVersion_ != 0) {
84     return parsedVersion_;
85   }
86
87   size_t dimension = bitMatrix_->getDimension();
88
89   int provisionalVersion = (dimension - 17) >> 2;
90   if (provisionalVersion <= 6) {
91     return Version::getVersionForNumber(provisionalVersion);
92   }
93
94   // Read top-right version info: 3 wide by 6 tall
95   int versionBits = 0;
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);
100     }
101   }
102
103   parsedVersion_ = Version::decodeVersionInformation(versionBits);
104   if (parsedVersion_ != 0) {
105     return parsedVersion_;
106   }
107
108   // Hmm, failed. Try bottom left: 6 wide by 3 tall
109   versionBits = 0;
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);
114     }
115   }
116
117   parsedVersion_ = Version::decodeVersionInformation(versionBits);
118   if (parsedVersion_ != 0) {
119     return parsedVersion_;
120   }
121   throw ReaderException("Could not decode version");
122 }
123
124 ArrayRef<unsigned char> BitMatrixParser::readCodewords() {
125   Ref<FormatInformation> formatInfo = readFormatInformation();
126   Version *version = readVersion();
127
128
129   //    cerr << *bitMatrix_ << endl;
130   //    cerr << bitMatrix_->getDimension() << endl;
131
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);
138
139
140   //            cerr << *bitMatrix_ << endl;
141   //    cerr << version->getTotalCodewords() << endl;
142
143   Ref<BitMatrix> functionPattern = version->buildFunctionPattern();
144
145
146   //    cout << *functionPattern << endl;
147
148   bool readingUp = true;
149   ArrayRef<unsigned char> result(version->getTotalCodewords());
150   int resultOffset = 0;
151   int currentByte = 0;
152   int bitsRead = 0;
153   // Read columns in pairs, from right to left
154   for (int x = dimension - 1; x > 0; x -= 2) {
155     if (x == 6) {
156       // Skip whole column with vertical alignment pattern;
157       // saves time and makes the other code proceed more cleanly
158       x--;
159     }
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)) {
166           // Read a bit
167           bitsRead++;
168           currentByte <<= 1;
169           if (bitMatrix_->get(x - col, y)) {
170             currentByte |= 1;
171           }
172           // If we've made a whole byte, save it off
173           if (bitsRead == 8) {
174             result[resultOffset++] = (unsigned char)currentByte;
175             bitsRead = 0;
176             currentByte = 0;
177           }
178         }
179       }
180     }
181     readingUp = !readingUp; // switch directions
182   }
183
184   if (resultOffset != version->getTotalCodewords()) {
185     throw ReaderException("Did not read all codewords");
186   }
187   return result;
188 }
189
190 }
191 }