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