2 * Copyright 2007 ZXing authors
\r
4 * Licensed under the Apache License, Version 2.0 (the "License");
\r
5 * you may not use this file except in compliance with the License.
\r
6 * You may obtain a copy of the License at
\r
8 * http://www.apache.org/licenses/LICENSE-2.0
\r
10 * Unless required by applicable law or agreed to in writing, software
\r
11 * distributed under the License is distributed on an "AS IS" BASIS,
\r
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
\r
13 * See the License for the specific language governing permissions and
\r
14 * limitations under the License.
\r
17 package com.google.zxing.qrcode.decoder;
\r
19 import com.google.zxing.FormatException;
\r
20 import com.google.zxing.common.BitMatrix;
\r
25 final class BitMatrixParser {
\r
27 private final BitMatrix bitMatrix;
\r
28 private Version parsedVersion;
\r
29 private FormatInformation parsedFormatInfo;
\r
32 * @param bitMatrix {@link BitMatrix} to parse
\r
33 * @throws FormatException if dimension is not >= 21 and 1 mod 4
\r
35 BitMatrixParser(BitMatrix bitMatrix) throws FormatException {
\r
36 int dimension = bitMatrix.getDimension();
\r
37 if (dimension < 21 || (dimension & 0x03) != 1) {
\r
38 throw FormatException.getFormatInstance();
\r
40 this.bitMatrix = bitMatrix;
\r
44 * <p>Reads format information from one of its two locations within the QR Code.</p>
\r
46 * @return {@link FormatInformation} encapsulating the QR Code's format info
\r
47 * @throws FormatException if both format information locations cannot be parsed as
\r
48 * the valid encoding of format information
\r
50 FormatInformation readFormatInformation() throws FormatException {
\r
52 if (parsedFormatInfo != null) {
\r
53 return parsedFormatInfo;
\r
56 // Read top-left format info bits
\r
57 int formatInfoBits = 0;
\r
58 for (int i = 0; i < 6; i++) {
\r
59 formatInfoBits = copyBit(i, 8, formatInfoBits);
\r
61 // .. and skip a bit in the timing pattern ...
\r
62 formatInfoBits = copyBit(7, 8, formatInfoBits);
\r
63 formatInfoBits = copyBit(8, 8, formatInfoBits);
\r
64 formatInfoBits = copyBit(8, 7, formatInfoBits);
\r
65 // .. and skip a bit in the timing pattern ...
\r
66 for (int j = 5; j >= 0; j--) {
\r
67 formatInfoBits = copyBit(8, j, formatInfoBits);
\r
70 parsedFormatInfo = FormatInformation.decodeFormatInformation(formatInfoBits);
\r
71 if (parsedFormatInfo != null) {
\r
72 return parsedFormatInfo;
\r
75 // Hmm, failed. Try the top-right/bottom-left pattern
\r
76 int dimension = bitMatrix.getDimension();
\r
78 int iMin = dimension - 8;
\r
79 for (int i = dimension - 1; i >= iMin; i--) {
\r
80 formatInfoBits = copyBit(i, 8, formatInfoBits);
\r
82 for (int j = dimension - 7; j < dimension; j++) {
\r
83 formatInfoBits = copyBit(8, j, formatInfoBits);
\r
86 parsedFormatInfo = FormatInformation.decodeFormatInformation(formatInfoBits);
\r
87 if (parsedFormatInfo != null) {
\r
88 return parsedFormatInfo;
\r
90 throw FormatException.getFormatInstance();
\r
94 * <p>Reads version information from one of its two locations within the QR Code.</p>
\r
96 * @return {@link Version} encapsulating the QR Code's version
\r
97 * @throws FormatException if both version information locations cannot be parsed as
\r
98 * the valid encoding of version information
\r
100 Version readVersion() throws FormatException {
\r
102 if (parsedVersion != null) {
\r
103 return parsedVersion;
\r
106 int dimension = bitMatrix.getDimension();
\r
108 int provisionalVersion = (dimension - 17) >> 2;
\r
109 if (provisionalVersion <= 6) {
\r
110 return Version.getVersionForNumber(provisionalVersion);
\r
113 // Read top-right version info: 3 wide by 6 tall
\r
114 int versionBits = 0;
\r
115 int ijMin = dimension - 11;
\r
116 for (int j = 5; j >= 0; j--) {
\r
117 for (int i = dimension - 9; i >= ijMin; i--) {
\r
118 versionBits = copyBit(i, j, versionBits);
\r
122 parsedVersion = Version.decodeVersionInformation(versionBits);
\r
123 if (parsedVersion != null && parsedVersion.getDimensionForVersion() == dimension) {
\r
124 return parsedVersion;
\r
127 // Hmm, failed. Try bottom left: 6 wide by 3 tall
\r
129 for (int i = 5; i >= 0; i--) {
\r
130 for (int j = dimension - 9; j >= ijMin; j--) {
\r
131 versionBits = copyBit(i, j, versionBits);
\r
135 parsedVersion = Version.decodeVersionInformation(versionBits);
\r
136 if (parsedVersion != null && parsedVersion.getDimensionForVersion() == dimension) {
\r
137 return parsedVersion;
\r
139 throw FormatException.getFormatInstance();
\r
142 private int copyBit(int i, int j, int versionBits) {
\r
143 return bitMatrix.get(i, j) ? (versionBits << 1) | 0x1 : versionBits << 1;
\r
147 * <p>Reads the bits in the {@link BitMatrix} representing the finder pattern in the
\r
148 * correct order in order to reconstitute the codewords bytes contained within the
\r
151 * @return bytes encoded within the QR Code
\r
152 * @throws FormatException if the exact number of bytes expected is not read
\r
154 byte[] readCodewords() throws FormatException {
\r
156 FormatInformation formatInfo = readFormatInformation();
\r
157 Version version = readVersion();
\r
159 // Get the data mask for the format used in this QR Code. This will exclude
\r
160 // some bits from reading as we wind through the bit matrix.
\r
161 DataMask dataMask = DataMask.forReference((int) formatInfo.getDataMask());
\r
162 int dimension = bitMatrix.getDimension();
\r
163 dataMask.unmaskBitMatrix(bitMatrix, dimension);
\r
165 BitMatrix functionPattern = version.buildFunctionPattern();
\r
167 boolean readingUp = true;
\r
168 byte[] result = new byte[version.getTotalCodewords()];
\r
169 int resultOffset = 0;
\r
170 int currentByte = 0;
\r
172 // Read columns in pairs, from right to left
\r
173 for (int j = dimension - 1; j > 0; j -= 2) {
\r
175 // Skip whole column with vertical alignment pattern;
\r
176 // saves time and makes the other code proceed more cleanly
\r
179 // Read alternatingly from bottom to top then top to bottom
\r
180 for (int count = 0; count < dimension; count++) {
\r
181 int i = readingUp ? dimension - 1 - count : count;
\r
182 for (int col = 0; col < 2; col++) {
\r
183 // Ignore bits covered by the function pattern
\r
184 if (!functionPattern.get(j - col, i)) {
\r
188 if (bitMatrix.get(j - col, i)) {
\r
191 // If we've made a whole byte, save it off
\r
192 if (bitsRead == 8) {
\r
193 result[resultOffset++] = (byte) currentByte;
\r
200 readingUp ^= true; // readingUp = !readingUp; // switch directions
\r
202 if (resultOffset != version.getTotalCodewords()) {
\r
203 throw FormatException.getFormatInstance();
\r