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