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 using ReaderException = com.google.zxing.ReaderException;
\r
18 using BitMatrix = com.google.zxing.common.BitMatrix;
\r
19 namespace com.google.zxing.qrcode.decoder
\r
22 /// <author> Sean Owen
\r
24 /// <author>www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source
\r
26 sealed class BitMatrixParser
\r
29 //UPGRADE_NOTE: Final was removed from the declaration of 'bitMatrix '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
\r
30 private BitMatrix bitMatrix;
\r
31 private Version parsedVersion;
\r
32 private FormatInformation parsedFormatInfo;
\r
34 /// <param name="bitMatrix">{@link BitMatrix} to parse
\r
36 /// <throws> ReaderException if dimension is not >= 21 and 1 mod 4 </throws>
\r
37 internal BitMatrixParser(BitMatrix bitMatrix)
\r
39 int dimension = bitMatrix.Dimension;
\r
40 if (dimension < 21 || (dimension & 0x03) != 1)
\r
42 throw ReaderException.Instance;
\r
44 this.bitMatrix = bitMatrix;
\r
47 /// <summary> <p>Reads format information from one of its two locations within the QR Code.</p>
\r
50 /// <returns> {@link FormatInformation} encapsulating the QR Code's format info
\r
52 /// <throws> ReaderException if both format information locations cannot be parsed as </throws>
\r
53 /// <summary> the valid encoding of format information
\r
55 internal FormatInformation readFormatInformation()
\r
58 if (parsedFormatInfo != null)
\r
60 return parsedFormatInfo;
\r
63 // Read top-left format info bits
\r
64 int formatInfoBits = 0;
\r
65 for (int i = 0; i < 6; i++)
\r
67 formatInfoBits = copyBit(i, 8, formatInfoBits);
\r
69 // .. and skip a bit in the timing pattern ...
\r
70 formatInfoBits = copyBit(7, 8, formatInfoBits);
\r
71 formatInfoBits = copyBit(8, 8, formatInfoBits);
\r
72 formatInfoBits = copyBit(8, 7, formatInfoBits);
\r
73 // .. and skip a bit in the timing pattern ...
\r
74 for (int j = 5; j >= 0; j--)
\r
76 formatInfoBits = copyBit(8, j, formatInfoBits);
\r
79 parsedFormatInfo = FormatInformation.decodeFormatInformation(formatInfoBits);
\r
80 if (parsedFormatInfo != null)
\r
82 return parsedFormatInfo;
\r
85 // Hmm, failed. Try the top-right/bottom-left pattern
\r
86 int dimension = bitMatrix.Dimension;
\r
88 int iMin = dimension - 8;
\r
89 for (int i = dimension - 1; i >= iMin; i--)
\r
91 formatInfoBits = copyBit(i, 8, formatInfoBits);
\r
93 for (int j = dimension - 7; j < dimension; j++)
\r
95 formatInfoBits = copyBit(8, j, formatInfoBits);
\r
98 parsedFormatInfo = FormatInformation.decodeFormatInformation(formatInfoBits);
\r
99 if (parsedFormatInfo != null)
\r
101 return parsedFormatInfo;
\r
103 throw ReaderException.Instance;
\r
106 /// <summary> <p>Reads version information from one of its two locations within the QR Code.</p>
\r
109 /// <returns> {@link Version} encapsulating the QR Code's version
\r
111 /// <throws> ReaderException if both version information locations cannot be parsed as </throws>
\r
112 /// <summary> the valid encoding of version information
\r
114 internal Version readVersion()
\r
117 if (parsedVersion != null)
\r
119 return parsedVersion;
\r
122 int dimension = bitMatrix.Dimension;
\r
124 int provisionalVersion = (dimension - 17) >> 2;
\r
125 if (provisionalVersion <= 6)
\r
127 return Version.getVersionForNumber(provisionalVersion);
\r
130 // Read top-right version info: 3 wide by 6 tall
\r
131 int versionBits = 0;
\r
132 int ijMin = dimension - 11;
\r
133 for (int j = 5; j >= 0; j--)
\r
135 for (int i = dimension - 9; i >= ijMin; i--)
\r
137 versionBits = copyBit(i, j, versionBits);
\r
141 parsedVersion = Version.decodeVersionInformation(versionBits);
\r
142 if (parsedVersion != null && parsedVersion.DimensionForVersion == dimension)
\r
144 return parsedVersion;
\r
147 // Hmm, failed. Try bottom left: 6 wide by 3 tall
\r
149 for (int i = 5; i >= 0; i--)
\r
151 for (int j = dimension - 9; j >= ijMin; j--)
\r
153 versionBits = copyBit(i, j, versionBits);
\r
157 parsedVersion = Version.decodeVersionInformation(versionBits);
\r
158 if (parsedVersion != null && parsedVersion.DimensionForVersion == dimension)
\r
160 return parsedVersion;
\r
162 throw ReaderException.Instance;
\r
165 private int copyBit(int i, int j, int versionBits)
\r
167 return bitMatrix.get_Renamed(i, j)?(versionBits << 1) | 0x1:versionBits << 1;
\r
170 /// <summary> <p>Reads the bits in the {@link BitMatrix} representing the finder pattern in the
\r
171 /// correct order in order to reconstitute the codewords bytes contained within the
\r
175 /// <returns> bytes encoded within the QR Code
\r
177 /// <throws> ReaderException if the exact number of bytes expected is not read </throws>
\r
178 internal sbyte[] readCodewords()
\r
181 FormatInformation formatInfo = readFormatInformation();
\r
182 Version version = readVersion();
\r
184 // Get the data mask for the format used in this QR Code. This will exclude
\r
185 // some bits from reading as we wind through the bit matrix.
\r
186 DataMask dataMask = DataMask.forReference((int) formatInfo.DataMask);
\r
187 int dimension = bitMatrix.Dimension;
\r
188 dataMask.unmaskBitMatrix(bitMatrix, dimension);
\r
190 BitMatrix functionPattern = version.buildFunctionPattern();
\r
192 bool readingUp = true;
\r
193 sbyte[] result = new sbyte[version.TotalCodewords];
\r
194 int resultOffset = 0;
\r
195 int currentByte = 0;
\r
197 // Read columns in pairs, from right to left
\r
198 for (int j = dimension - 1; j > 0; j -= 2)
\r
202 // Skip whole column with vertical alignment pattern;
\r
203 // saves time and makes the other code proceed more cleanly
\r
206 // Read alternatingly from bottom to top then top to bottom
\r
207 for (int count = 0; count < dimension; count++)
\r
209 int i = readingUp?dimension - 1 - count:count;
\r
210 for (int col = 0; col < 2; col++)
\r
212 // Ignore bits covered by the function pattern
\r
213 if (!functionPattern.get_Renamed(j - col, i))
\r
218 if (bitMatrix.get_Renamed(j - col, i))
\r
222 // If we've made a whole byte, save it off
\r
225 result[resultOffset++] = (sbyte) currentByte;
\r
232 readingUp ^= true; // readingUp = !readingUp; // switch directions
\r
234 if (resultOffset != version.TotalCodewords)
\r
236 throw ReaderException.Instance;
\r