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