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