45ffd2d04bdcf48c688c8848682135c8b512f4b4
[zxing.git] / core / src / com / google / zxing / datamatrix / decoder / BitMatrixParser.java
1 /*\r
2  * Copyright 2007 ZXing authors\r
3  *\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
7  *\r
8  *      http://www.apache.org/licenses/LICENSE-2.0\r
9  *\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
15  */\r
16 \r
17 package com.google.zxing.datamatrix.decoder;\r
18 \r
19 import com.google.zxing.FormatException;\r
20 import com.google.zxing.common.BitMatrix;\r
21 \r
22 /**\r
23  * @author bbrown@google.com (Brian Brown)\r
24  */\r
25 final class BitMatrixParser {\r
26 \r
27   private final BitMatrix mappingBitMatrix;\r
28   private final BitMatrix readMappingMatrix;\r
29   private final Version version;\r
30 \r
31   /**\r
32    * @param bitMatrix {@link BitMatrix} to parse\r
33    * @throws FormatException if dimension is < 8 or > 144 or not 0 mod 2\r
34    */\r
35   BitMatrixParser(BitMatrix bitMatrix) throws FormatException {\r
36     int dimension = bitMatrix.getHeight();\r
37     if (dimension < 8 || dimension > 144 || (dimension & 0x01) != 0) {\r
38       throw FormatException.getFormatInstance();\r
39     }\r
40     \r
41     version = readVersion(bitMatrix);\r
42     this.mappingBitMatrix = extractDataRegion(bitMatrix);\r
43     this.readMappingMatrix = new BitMatrix(this.mappingBitMatrix.getWidth(), this.mappingBitMatrix.getHeight());\r
44   }\r
45 \r
46   Version getVersion() {\r
47     return version;\r
48   }\r
49 \r
50   /**\r
51    * <p>Creates the version object based on the dimension of the original bit matrix from \r
52    * the datamatrix code.</p>\r
53    *\r
54    * <p>See ISO 16022:2006 Table 7 - ECC 200 symbol attributes</p>\r
55    * \r
56    * @param bitMatrix Original {@link BitMatrix} including alignment patterns\r
57    * @return {@link Version} encapsulating the Data Matrix Code's "version"\r
58    * @throws FormatException if the dimensions of the mapping matrix are not valid\r
59    * Data Matrix dimensions.\r
60    */\r
61   private static Version readVersion(BitMatrix bitMatrix) throws FormatException {\r
62     int numRows = bitMatrix.getHeight();\r
63     int numColumns = bitMatrix.getWidth();\r
64     return Version.getVersionForDimensions(numRows, numColumns);\r
65   }\r
66 \r
67   /**\r
68    * <p>Reads the bits in the {@link BitMatrix} representing the mapping matrix (No alignment patterns)\r
69    * in the correct order in order to reconstitute the codewords bytes contained within the\r
70    * Data Matrix Code.</p>\r
71    *\r
72    * @return bytes encoded within the Data Matrix Code\r
73    * @throws FormatException if the exact number of bytes expected is not read\r
74    */\r
75   byte[] readCodewords() throws FormatException {\r
76 \r
77     byte[] result = new byte[version.getTotalCodewords()];\r
78     int resultOffset = 0;\r
79     \r
80     int row = 4;\r
81     int column = 0;\r
82 \r
83     int numRows = mappingBitMatrix.getHeight();\r
84     int numColumns = mappingBitMatrix.getWidth();\r
85     \r
86     boolean corner1Read = false;\r
87     boolean corner2Read = false;\r
88     boolean corner3Read = false;\r
89     boolean corner4Read = false;\r
90     \r
91     // Read all of the codewords\r
92     do {\r
93       // Check the four corner cases\r
94       if ((row == numRows) && (column == 0) && !corner1Read) {\r
95         result[resultOffset++] = (byte) readCorner1(numRows, numColumns);\r
96         row -= 2;\r
97         column +=2;\r
98         corner1Read = true;\r
99       } else if ((row == numRows-2) && (column == 0) && ((numColumns & 0x03) != 0) && !corner2Read) {\r
100         result[resultOffset++] = (byte) readCorner2(numRows, numColumns);\r
101         row -= 2;\r
102         column +=2;\r
103         corner2Read = true;\r
104       } else if ((row == numRows+4) && (column == 2) && ((numColumns & 0x07) == 0) && !corner3Read) {\r
105         result[resultOffset++] = (byte) readCorner3(numRows, numColumns);\r
106         row -= 2;\r
107         column +=2;\r
108         corner3Read = true;\r
109       } else if ((row == numRows-2) && (column == 0) && ((numColumns & 0x07) == 4) && !corner4Read) {\r
110         result[resultOffset++] = (byte) readCorner4(numRows, numColumns);\r
111         row -= 2;\r
112         column +=2;\r
113         corner4Read = true;\r
114       } else {\r
115         // Sweep upward diagonally to the right\r
116         do {\r
117           if ((row < numRows) && (column >= 0) && !readMappingMatrix.get(column, row)) {\r
118             result[resultOffset++] = (byte) readUtah(row, column, numRows, numColumns);\r
119           }\r
120           row -= 2;\r
121           column +=2;\r
122         } while ((row >= 0) && (column < numColumns));\r
123         row += 1;\r
124         column +=3;\r
125         \r
126         // Sweep downward diagonally to the left\r
127         do {\r
128           if ((row >= 0) && (column < numColumns) && !readMappingMatrix.get(column, row)) {\r
129              result[resultOffset++] = (byte) readUtah(row, column, numRows, numColumns);\r
130           }\r
131           row += 2;\r
132           column -=2;\r
133         } while ((row < numRows) && (column >= 0));\r
134         row += 3;\r
135         column +=1;\r
136       }\r
137     } while ((row < numRows) || (column < numColumns));\r
138 \r
139     if (resultOffset != version.getTotalCodewords()) {\r
140       throw FormatException.getFormatInstance();\r
141     }\r
142     return result;\r
143   }\r
144   \r
145   /**\r
146    * <p>Reads a bit of the mapping matrix accounting for boundary wrapping.</p>\r
147    * \r
148    * @param row Row to read in the mapping matrix\r
149    * @param column Column to read in the mapping matrix\r
150    * @param numRows Number of rows in the mapping matrix\r
151    * @param numColumns Number of columns in the mapping matrix\r
152    * @return value of the given bit in the mapping matrix\r
153    */\r
154   boolean readModule(int row, int column, int numRows, int numColumns) {\r
155     // Adjust the row and column indices based on boundary wrapping\r
156     if (row < 0) {\r
157       row += numRows;\r
158       column += 4 - ((numRows + 4) & 0x07);\r
159     }\r
160     if (column < 0) {\r
161       column += numColumns;\r
162       row += 4 - ((numColumns + 4) & 0x07);\r
163     }\r
164     readMappingMatrix.set(column, row);\r
165     return mappingBitMatrix.get(column, row);\r
166   }\r
167   \r
168   /**\r
169    * <p>Reads the 8 bits of the standard Utah-shaped pattern.</p>\r
170    * \r
171    * <p>See ISO 16022:2006, 5.8.1 Figure 6</p>\r
172    * \r
173    * @param row Current row in the mapping matrix, anchored at the 8th bit (LSB) of the pattern\r
174    * @param column Current column in the mapping matrix, anchored at the 8th bit (LSB) of the pattern\r
175    * @param numRows Number of rows in the mapping matrix\r
176    * @param numColumns Number of columns in the mapping matrix\r
177    * @return byte from the utah shape\r
178    */\r
179   int readUtah(int row, int column, int numRows, int numColumns) {\r
180     int currentByte = 0;\r
181     if (readModule(row - 2, column - 2, numRows, numColumns)) {\r
182       currentByte |= 1;\r
183     }\r
184     currentByte <<= 1;\r
185     if (readModule(row - 2, column - 1, numRows, numColumns)) {\r
186       currentByte |= 1;\r
187     }\r
188     currentByte <<= 1;\r
189     if (readModule(row - 1, column - 2, numRows, numColumns)) {\r
190       currentByte |= 1;\r
191     }\r
192     currentByte <<= 1;\r
193     if (readModule(row - 1, column - 1, numRows, numColumns)) {\r
194       currentByte |= 1;\r
195     }\r
196     currentByte <<= 1;\r
197     if (readModule(row - 1, column, numRows, numColumns)) {\r
198       currentByte |= 1;\r
199     }\r
200     currentByte <<= 1;\r
201     if (readModule(row, column - 2, numRows, numColumns)) {\r
202       currentByte |= 1;\r
203     }\r
204     currentByte <<= 1;\r
205     if (readModule(row, column - 1, numRows, numColumns)) {\r
206       currentByte |= 1;\r
207     }\r
208     currentByte <<= 1;\r
209     if (readModule(row, column, numRows, numColumns)) {\r
210       currentByte |= 1;\r
211     }\r
212     return currentByte;\r
213   }\r
214   \r
215   /**\r
216    * <p>Reads the 8 bits of the special corner condition 1.</p>\r
217    * \r
218    * <p>See ISO 16022:2006, Figure F.3</p>\r
219    * \r
220    * @param numRows Number of rows in the mapping matrix\r
221    * @param numColumns Number of columns in the mapping matrix\r
222    * @return byte from the Corner condition 1\r
223    */\r
224   int readCorner1(int numRows, int numColumns) {\r
225     int currentByte = 0;\r
226     if (readModule(numRows - 1, 0, numRows, numColumns)) {\r
227       currentByte |= 1;\r
228     }\r
229     currentByte <<= 1;\r
230     if (readModule(numRows - 1, 1, numRows, numColumns)) {\r
231       currentByte |= 1;\r
232     }\r
233     currentByte <<= 1;\r
234     if (readModule(numRows - 1, 2, numRows, numColumns)) {\r
235       currentByte |= 1;\r
236     }\r
237     currentByte <<= 1;\r
238     if (readModule(0, numColumns - 2, numRows, numColumns)) {\r
239       currentByte |= 1;\r
240     }\r
241     currentByte <<= 1;\r
242     if (readModule(0, numColumns - 1, numRows, numColumns)) {\r
243       currentByte |= 1;\r
244     }\r
245     currentByte <<= 1;\r
246     if (readModule(1, numColumns - 1, numRows, numColumns)) {\r
247       currentByte |= 1;\r
248     }\r
249     currentByte <<= 1;\r
250     if (readModule(2, numColumns - 1, numRows, numColumns)) {\r
251       currentByte |= 1;\r
252     }\r
253     currentByte <<= 1;\r
254     if (readModule(3, numColumns - 1, numRows, numColumns)) {\r
255       currentByte |= 1;\r
256     }\r
257     return currentByte;\r
258   }\r
259   \r
260   /**\r
261    * <p>Reads the 8 bits of the special corner condition 2.</p>\r
262    * \r
263    * <p>See ISO 16022:2006, Figure F.4</p>\r
264    * \r
265    * @param numRows Number of rows in the mapping matrix\r
266    * @param numColumns Number of columns in the mapping matrix\r
267    * @return byte from the Corner condition 2\r
268    */\r
269   int readCorner2(int numRows, int numColumns) {\r
270     int currentByte = 0;\r
271     if (readModule(numRows - 3, 0, numRows, numColumns)) {\r
272       currentByte |= 1;\r
273     }\r
274     currentByte <<= 1;\r
275     if (readModule(numRows - 2, 0, numRows, numColumns)) {\r
276       currentByte |= 1;\r
277     }\r
278     currentByte <<= 1;\r
279     if (readModule(numRows - 1, 0, numRows, numColumns)) {\r
280       currentByte |= 1;\r
281     }\r
282     currentByte <<= 1;\r
283     if (readModule(0, numColumns - 4, numRows, numColumns)) {\r
284       currentByte |= 1;\r
285     }\r
286     currentByte <<= 1;\r
287     if (readModule(0, numColumns - 3, numRows, numColumns)) {\r
288       currentByte |= 1;\r
289     }\r
290     currentByte <<= 1;\r
291     if (readModule(0, numColumns - 2, numRows, numColumns)) {\r
292       currentByte |= 1;\r
293     }\r
294     currentByte <<= 1;\r
295     if (readModule(0, numColumns - 1, numRows, numColumns)) {\r
296       currentByte |= 1;\r
297     }\r
298     currentByte <<= 1;\r
299     if (readModule(1, numColumns - 1, numRows, numColumns)) {\r
300       currentByte |= 1;\r
301     }\r
302     return currentByte;\r
303   }\r
304   \r
305   /**\r
306    * <p>Reads the 8 bits of the special corner condition 3.</p>\r
307    * \r
308    * <p>See ISO 16022:2006, Figure F.5</p>\r
309    * \r
310    * @param numRows Number of rows in the mapping matrix\r
311    * @param numColumns Number of columns in the mapping matrix\r
312    * @return byte from the Corner condition 3\r
313    */\r
314   int readCorner3(int numRows, int numColumns) {\r
315     int currentByte = 0;\r
316     if (readModule(numRows - 1, 0, numRows, numColumns)) {\r
317       currentByte |= 1;\r
318     }\r
319     currentByte <<= 1;\r
320     if (readModule(numRows - 1, numColumns - 1, numRows, numColumns)) {\r
321       currentByte |= 1;\r
322     }\r
323     currentByte <<= 1;\r
324     if (readModule(0, numColumns - 3, numRows, numColumns)) {\r
325       currentByte |= 1;\r
326     }\r
327     currentByte <<= 1;\r
328     if (readModule(0, numColumns - 2, numRows, numColumns)) {\r
329       currentByte |= 1;\r
330     }\r
331     currentByte <<= 1;\r
332     if (readModule(0, numColumns - 1, numRows, numColumns)) {\r
333       currentByte |= 1;\r
334     }\r
335     currentByte <<= 1;\r
336     if (readModule(1, numColumns - 3, numRows, numColumns)) {\r
337       currentByte |= 1;\r
338     }\r
339     currentByte <<= 1;\r
340     if (readModule(1, numColumns - 2, numRows, numColumns)) {\r
341       currentByte |= 1;\r
342     }\r
343     currentByte <<= 1;\r
344     if (readModule(1, numColumns - 1, numRows, numColumns)) {\r
345       currentByte |= 1;\r
346     }\r
347     return currentByte;\r
348   }\r
349   \r
350   /**\r
351    * <p>Reads the 8 bits of the special corner condition 4.</p>\r
352    * \r
353    * <p>See ISO 16022:2006, Figure F.6</p>\r
354    * \r
355    * @param numRows Number of rows in the mapping matrix\r
356    * @param numColumns Number of columns in the mapping matrix\r
357    * @return byte from the Corner condition 4\r
358    */\r
359   int readCorner4(int numRows, int numColumns) {\r
360     int currentByte = 0;\r
361     if (readModule(numRows - 3, 0, numRows, numColumns)) {\r
362       currentByte |= 1;\r
363     }\r
364     currentByte <<= 1;\r
365     if (readModule(numRows - 2, 0, numRows, numColumns)) {\r
366       currentByte |= 1;\r
367     }\r
368     currentByte <<= 1;\r
369     if (readModule(numRows - 1, 0, numRows, numColumns)) {\r
370       currentByte |= 1;\r
371     }\r
372     currentByte <<= 1;\r
373     if (readModule(0, numColumns - 2, numRows, numColumns)) {\r
374       currentByte |= 1;\r
375     }\r
376     currentByte <<= 1;\r
377     if (readModule(0, numColumns - 1, numRows, numColumns)) {\r
378       currentByte |= 1;\r
379     }\r
380     currentByte <<= 1;\r
381     if (readModule(1, numColumns - 1, numRows, numColumns)) {\r
382       currentByte |= 1;\r
383     }\r
384     currentByte <<= 1;\r
385     if (readModule(2, numColumns - 1, numRows, numColumns)) {\r
386       currentByte |= 1;\r
387     }\r
388     currentByte <<= 1;\r
389     if (readModule(3, numColumns - 1, numRows, numColumns)) {\r
390       currentByte |= 1;\r
391     }\r
392     return currentByte;\r
393   }\r
394   \r
395   /**\r
396    * <p>Extracts the data region from a {@link BitMatrix} that contains\r
397    * alignment patterns.</p>\r
398    * \r
399    * @param bitMatrix Original {@link BitMatrix} with alignment patterns\r
400    * @return BitMatrix that has the alignment patterns removed\r
401    */\r
402   BitMatrix extractDataRegion(BitMatrix bitMatrix) {\r
403     int symbolSizeRows = version.getSymbolSizeRows();\r
404     int symbolSizeColumns = version.getSymbolSizeColumns();\r
405     \r
406     if (bitMatrix.getHeight() != symbolSizeRows) {\r
407       throw new IllegalArgumentException("Dimension of bitMarix must match the version size");\r
408     }\r
409     \r
410     int dataRegionSizeRows = version.getDataRegionSizeRows();\r
411     int dataRegionSizeColumns = version.getDataRegionSizeColumns();\r
412     \r
413     int numDataRegionsRow = symbolSizeRows / dataRegionSizeRows;\r
414     int numDataRegionsColumn = symbolSizeColumns / dataRegionSizeColumns;\r
415     \r
416     int sizeDataRegionRow = numDataRegionsRow * dataRegionSizeRows;\r
417     int sizeDataRegionColumn = numDataRegionsColumn * dataRegionSizeColumns;\r
418     \r
419     BitMatrix bitMatrixWithoutAlignment = new BitMatrix(sizeDataRegionColumn, sizeDataRegionRow);\r
420     for (int dataRegionRow = 0; dataRegionRow < numDataRegionsRow; ++dataRegionRow) {\r
421       int dataRegionRowOffset = dataRegionRow * dataRegionSizeRows;\r
422       for (int dataRegionColumn = 0; dataRegionColumn < numDataRegionsColumn; ++dataRegionColumn) {\r
423         int dataRegionColumnOffset = dataRegionColumn * dataRegionSizeColumns;\r
424         for (int i = 0; i < dataRegionSizeRows; ++i) {\r
425           int readRowOffset = dataRegionRow * (dataRegionSizeRows + 2) + 1 + i;\r
426           int writeRowOffset = dataRegionRowOffset + i;\r
427           for (int j = 0; j < dataRegionSizeColumns; ++j) {\r
428             int readColumnOffset = dataRegionColumn * (dataRegionSizeColumns + 2) + 1 + j;\r
429             if (bitMatrix.get(readColumnOffset, readRowOffset)) {\r
430               int writeColumnOffset = dataRegionColumnOffset + j;\r
431               bitMatrixWithoutAlignment.set(writeColumnOffset, writeRowOffset);\r
432             }\r
433           }\r
434         }\r
435       }\r
436     }\r
437     return bitMatrixWithoutAlignment;\r
438   }\r
439 \r
440 }