2 * Copyright 2007 Google Inc.
\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.ReaderException;
\r
20 import com.google.zxing.common.BitMatrix;
\r
23 * @author srowen@google.com (Sean Owen)
\r
25 final class BitMatrixParser {
\r
27 private final BitMatrix bitMatrix;
\r
28 private Version parsedVersion;
\r
29 private FormatInformation parsedFormatInfo;
\r
32 * @throws com.google.zxing.ReaderException
\r
33 * if dimension is not >= 21 and 1 mod 4
\r
35 BitMatrixParser(BitMatrix bitMatrix) throws ReaderException {
\r
36 int dimension = bitMatrix.getDimension();
\r
37 if (dimension < 21 || (dimension & 0x03) != 1) {
\r
38 throw new ReaderException("Dimension must be 1 mod 4 and >= 21");
\r
40 this.bitMatrix = bitMatrix;
\r
43 FormatInformation readFormatInformation() throws ReaderException {
\r
45 if (parsedFormatInfo != null) {
\r
46 return parsedFormatInfo;
\r
49 // Read top-left format info bits
\r
50 int formatInfoBits = 0;
\r
51 for (int j = 0; j < 6; j++) {
\r
52 formatInfoBits = copyBit(8, j, formatInfoBits);
\r
54 // .. and skip a bit in the timing pattern ...
\r
55 formatInfoBits = copyBit(8, 7, formatInfoBits);
\r
56 formatInfoBits = copyBit(8, 8, formatInfoBits);
\r
57 formatInfoBits = copyBit(7, 8, formatInfoBits);
\r
58 // .. and skip a bit in the timing pattern ...
\r
59 for (int i = 5; i >= 0; i--) {
\r
60 formatInfoBits = copyBit(i, 8, formatInfoBits);
\r
63 parsedFormatInfo = FormatInformation.decodeFormatInformation(formatInfoBits);
\r
64 if (parsedFormatInfo != null) {
\r
65 return parsedFormatInfo;
\r
68 // Hmm, failed. Try the top-right/bottom-left pattern
\r
69 int dimension = bitMatrix.getDimension();
\r
71 int iMin = dimension - 8;
\r
72 for (int i = dimension - 1; i >= iMin; i--) {
\r
73 formatInfoBits = copyBit(i, 8, formatInfoBits);
\r
75 for (int j = dimension - 7; j < dimension; j++) {
\r
76 formatInfoBits = copyBit(8, j, formatInfoBits);
\r
79 parsedFormatInfo = FormatInformation.decodeFormatInformation(formatInfoBits);
\r
80 if (parsedFormatInfo != null) {
\r
81 return parsedFormatInfo;
\r
83 throw new ReaderException("Could not decode format information");
\r
86 Version readVersion() throws ReaderException {
\r
88 if (parsedVersion != null) {
\r
89 return parsedVersion;
\r
92 int dimension = bitMatrix.getDimension();
\r
94 int provisionalVersion = (dimension - 17) >> 2;
\r
95 if (provisionalVersion <= 6) {
\r
96 return Version.getVersionForNumber(provisionalVersion);
\r
99 // Read top-right version info: 3 wide by 6 tall
\r
100 int versionBits = 0;
\r
101 for (int i = 5; i >= 0; i--) {
\r
102 int jMin = dimension - 11;
\r
103 for (int j = dimension - 9; j >= jMin; j--) {
\r
104 versionBits = copyBit(i, j, versionBits);
\r
108 parsedVersion = Version.decodeVersionInformation(versionBits);
\r
109 if (parsedVersion != null) {
\r
110 return parsedVersion;
\r
113 // Hmm, failed. Try bottom left: 6 wide by 3 tall
\r
115 for (int j = 5; j >= 0; j--) {
\r
116 int iMin = dimension - 11;
\r
117 for (int i = dimension - 11; i >= iMin; i--) {
\r
118 versionBits = copyBit(i, j, versionBits);
\r
122 parsedVersion = Version.decodeVersionInformation(versionBits);
\r
123 if (parsedVersion != null) {
\r
124 return parsedVersion;
\r
126 throw new ReaderException("Could not decode version");
\r
129 private int copyBit(int i, int j, int versionBits) {
\r
130 return bitMatrix.get(i, j) ? (versionBits << 1) | 0x1 : versionBits << 1;
\r
133 byte[] readCodewords() throws ReaderException {
\r
135 FormatInformation formatInfo = readFormatInformation();
\r
136 Version version = readVersion();
\r
138 DataMask dataMask = DataMask.forReference((int) formatInfo.getDataMask());
\r
139 int dimension = bitMatrix.getDimension();
\r
140 dataMask.unmaskBitMatrix(bitMatrix.getBits(), dimension);
\r
142 BitMatrix functionPattern = version.buildFunctionPattern();
\r
144 boolean readingUp = true;
\r
145 byte[] result = new byte[version.getTotalCodewords()];
\r
146 int resultOffset = 0;
\r
147 int currentByte = 0;
\r
149 for (int j = dimension - 1; j > 0; j -= 2) {
\r
151 // Skip whole column with vertical alignment pattern;
\r
152 // saves time and makes the other code proceed more cleanly
\r
155 for (int count = 0; count < dimension; count++) {
\r
156 int i = readingUp ? dimension - 1 - count : count;
\r
157 for (int col = 0; col < 2; col++) {
\r
158 if (!functionPattern.get(i, j - col)) {
\r
161 if (bitMatrix.get(i, j - col)) {
\r
164 if (bitsRead == 8) {
\r
165 result[resultOffset++] = (byte) currentByte;
\r
172 readingUp = !readingUp; // switch directions
\r
174 if (resultOffset != version.getTotalCodewords()) {
\r
175 throw new ReaderException("Did not read all codewords");
\r