Issue 165
[zxing.git] / cpp / core / src / 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 "BitMatrixParser.h"
22 #include "DataMask.h"
23
24 namespace qrcode {
25   namespace decoder {
26     
27     using namespace common;
28     
29     int BitMatrixParser::copyBit(size_t i, size_t j, int versionBits) {
30       return bitMatrix_->get(i, j) ? 
31         (versionBits << 1) | 0x1 
32         : versionBits << 1;
33     }
34     
35     BitMatrixParser::BitMatrixParser(Ref<BitMatrix> bitMatrix) : 
36     bitMatrix_(bitMatrix), parsedVersion_(0), parsedFormatInfo_() {
37       int dimension = bitMatrix->getDimension();
38       if ((dimension < 21) || (dimension & 0x03) != 1) {
39         throw new ReaderException("Dimension must be 1 mod 4 and >= 21");
40       }
41     }
42     
43     Ref<FormatInformation> BitMatrixParser::readFormatInformation() {
44       if (parsedFormatInfo_ != 0) {
45         return parsedFormatInfo_;
46       }
47       
48       // Read top-left format info bits
49       int formatInfoBits = 0;
50       for (int j = 0; j < 6; j++) {
51         formatInfoBits = copyBit(8, j, formatInfoBits);
52       }
53       // .. and skip a bit in the timing pattern ...
54       formatInfoBits = copyBit(8, 7, formatInfoBits);
55       formatInfoBits = copyBit(8, 8, formatInfoBits);
56       formatInfoBits = copyBit(7, 8, formatInfoBits);
57       // .. and skip a bit in the timing pattern ...
58       for (int i = 5; i >= 0; i--) {
59         formatInfoBits = copyBit(i, 8, formatInfoBits);
60       }
61       
62       parsedFormatInfo_ = FormatInformation::decodeFormatInformation(formatInfoBits);
63       if (parsedFormatInfo_ != 0) {
64         return parsedFormatInfo_;
65       }
66       
67       // Hmm, failed. Try the top-right/bottom-left pattern
68       int dimension = bitMatrix_->getDimension();
69       formatInfoBits = 0;
70       int iMin = dimension - 8;
71       for (int i = dimension - 1; i >= iMin; i--) {
72         formatInfoBits = copyBit(i, 8, formatInfoBits);
73       }
74       for (int j = dimension - 7; j < dimension; j++) {
75         formatInfoBits = copyBit(8, j, formatInfoBits);
76       }
77       
78       parsedFormatInfo_ = FormatInformation::decodeFormatInformation(formatInfoBits);
79       if (parsedFormatInfo_ != 0) {
80         return parsedFormatInfo_;
81       }
82       throw new ReaderException("Could not decode format information");
83     }
84     
85     Version *BitMatrixParser::readVersion() {
86       if (parsedVersion_ != 0) {
87         return parsedVersion_;
88       }
89       
90       int dimension = bitMatrix_->getDimension();
91       
92       int provisionalVersion = (dimension - 17) >> 2;
93       if (provisionalVersion <= 6) {
94         return Version::getVersionForNumber(provisionalVersion);
95       }
96       
97       // Read top-right version info: 3 wide by 6 tall
98       int versionBits = 0;
99       for (int i = 5; i >= 0; i--) {
100         int jMin = dimension - 11;
101         for (int j = dimension - 9; j >= jMin; j--) {
102           versionBits = copyBit(i, j, versionBits);
103         }
104       }
105       
106       parsedVersion_ = Version::decodeVersionInformation(versionBits);
107       if (parsedVersion_ != 0) {
108         return parsedVersion_;
109       }
110       
111       // Hmm, failed. Try bottom left: 6 wide by 3 tall
112       versionBits = 0;
113       for (int j = 5; j >= 0; j--) {
114         int iMin = dimension - 11;
115         for (int i = dimension - 9; i >= iMin; i--) {
116           versionBits = copyBit(i, j, versionBits);
117         }
118       }
119       
120       parsedVersion_ = Version::decodeVersionInformation(versionBits);
121       if (parsedVersion_ != 0) {
122         return parsedVersion_;
123       }
124       throw new ReaderException("Could not decode version");
125     }
126     
127     ArrayRef<unsigned char> BitMatrixParser::readCodewords() {
128       Ref<FormatInformation> formatInfo = readFormatInformation();
129       Version *version = readVersion();
130       
131       // Get the data mask for the format used in this QR Code. This will exclude
132       // some bits from reading as we wind through the bit matrix.
133       DataMask &dataMask = DataMask::forReference((int) formatInfo->getDataMask());
134       int dimension = bitMatrix_->getDimension();
135       dataMask.unmaskBitMatrix(bitMatrix_->getBits(), dimension);
136       
137       Ref<BitMatrix> functionPattern = version->buildFunctionPattern();
138       
139       bool readingUp = true;
140       ArrayRef<unsigned char> result(version->getTotalCodewords());
141       int resultOffset = 0;
142       int currentByte = 0;
143       int bitsRead = 0;
144       // Read columns in pairs, from right to left
145       size_t D = functionPattern.object_->dimension_;
146       for (int j = dimension - 1; j > 0; j -= 2) {
147         if (j == 6) {
148           // Skip whole column with vertical alignment pattern;
149           // saves time and makes the other code proceed more cleanly
150           j--;
151         }
152         // Read alternatingly from bottom to top then top to bottom
153         for (int count = 0; count < dimension; count++) {
154           int i = readingUp ? dimension - 1 - count : count;
155           for (int col = 0; col < 2; col++) {
156             // Ignore bits covered by the function pattern
157             if (functionPattern.object_->dimension_ != D) {
158               cout << "function pattern dimension changed from " << D << " to " << functionPattern.object_->dimension_ << "\n";
159               D = functionPattern.object_->dimension_;
160             }
161             if (!functionPattern->get(i, j - col)) {
162               // Read a bit
163               bitsRead++;
164               currentByte <<= 1;
165               if (bitMatrix_->get(i, j - col)) {
166                 currentByte |= 1;
167               }
168               // If we've made a whole byte, save it off
169               if (bitsRead == 8) {
170                 result[resultOffset++] = (unsigned char) currentByte;
171                 bitsRead = 0;
172                 currentByte = 0;
173               }
174             }
175           }
176         }
177         readingUp = !readingUp; // switch directions
178       }
179       if (resultOffset != version->getTotalCodewords()) {
180         throw new ReaderException("Did not read all codewords");
181       }
182       return result;
183     }
184     
185   }
186 }