Tiny style bits
[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 ReaderException = com.google.zxing.ReaderException;\r
18 using BitMatrix = com.google.zxing.common.BitMatrix;\r
19 namespace com.google.zxing.datamatrix.decoder\r
20 {\r
21         \r
22         /// <author>  bbrown@google.com (Brian Brown)\r
23         /// </author>\r
24         /// <author>www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source \r
25         /// </author>\r
26         sealed class BitMatrixParser\r
27         {\r
28                 \r
29                 //UPGRADE_NOTE: Final was removed from the declaration of 'mappingBitMatrix '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"\r
30                 private BitMatrix mappingBitMatrix;\r
31                 //UPGRADE_NOTE: Final was removed from the declaration of 'readMappingMatrix '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"\r
32                 private BitMatrix readMappingMatrix;\r
33                 //UPGRADE_NOTE: Final was removed from the declaration of 'version '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"\r
34                 private Version version;\r
35                 \r
36                 /// <param name="bitMatrix">{@link BitMatrix} to parse\r
37                 /// </param>\r
38                 /// <throws>  ReaderException if dimension is < 10 or > 144 or not 0 mod 2 </throws>\r
39                 internal BitMatrixParser(BitMatrix bitMatrix)\r
40                 {\r
41                         int dimension = bitMatrix.Dimension;\r
42                         if (dimension < 10 || dimension > 144 || (dimension & 0x01) != 0)\r
43                         {\r
44                                 throw ReaderException.Instance;\r
45                         }\r
46                         \r
47                         version = readVersion(bitMatrix);\r
48                         this.mappingBitMatrix = extractDataRegion(bitMatrix);\r
49                         // TODO(bbrown): Make this work for rectangular symbols\r
50                         this.readMappingMatrix = new BitMatrix(this.mappingBitMatrix.Dimension);\r
51                 }\r
52                 \r
53                 /// <summary> <p>Creates the version object based on the dimension of the original bit matrix from \r
54                 /// the datamatrix code.</p>\r
55                 /// \r
56                 /// <p>See ISO 16022:2006 Table 7 - ECC 200 symbol attributes</p>\r
57                 /// \r
58                 /// </summary>\r
59                 /// <param name="bitMatrix">Original {@link BitMatrix} including alignment patterns\r
60                 /// </param>\r
61                 /// <returns> {@link Version} encapsulating the Data Matrix Code's "version"\r
62                 /// </returns>\r
63                 /// <throws>  ReaderException if the dimensions of the mapping matrix are not valid </throws>\r
64                 /// <summary> Data Matrix dimensions.\r
65                 /// </summary>\r
66                 internal Version readVersion(BitMatrix bitMatrix)\r
67                 {\r
68                         \r
69                         if (version != null)\r
70                         {\r
71                                 return version;\r
72                         }\r
73                         \r
74                         // TODO(bbrown): make this work for rectangular dimensions as well.\r
75                         int numRows = bitMatrix.Dimension;\r
76                         int numColumns = numRows;\r
77                         \r
78                         return Version.getVersionForDimensions(numRows, numColumns);\r
79                 }\r
80                 \r
81                 /// <summary> <p>Reads the bits in the {@link BitMatrix} representing the mapping matrix (No alignment patterns)\r
82                 /// in the correct order in order to reconstitute the codewords bytes contained within the\r
83                 /// Data Matrix Code.</p>\r
84                 /// \r
85                 /// </summary>\r
86                 /// <returns> bytes encoded within the Data Matrix Code\r
87                 /// </returns>\r
88                 /// <throws>  ReaderException if the exact number of bytes expected is not read </throws>\r
89                 internal sbyte[] readCodewords()\r
90                 {\r
91                         \r
92                         sbyte[] result = new sbyte[version.TotalCodewords];\r
93                         int resultOffset = 0;\r
94                         \r
95                         int row = 4;\r
96                         int column = 0;\r
97                         // TODO(bbrown): Data Matrix can be rectangular, assuming square for now\r
98                         int numRows = mappingBitMatrix.Dimension;\r
99                         int numColumns = numRows;\r
100                         \r
101                         bool corner1Read = false;\r
102                         bool corner2Read = false;\r
103                         bool corner3Read = false;\r
104                         bool corner4Read = false;\r
105                         \r
106                         // Read all of the codewords\r
107                         do \r
108                         {\r
109                                 // Check the four corner cases\r
110                                 if ((row == numRows) && (column == 0) && !corner1Read)\r
111                                 {\r
112                                         result[resultOffset++] = (sbyte) readCorner1(numRows, numColumns);\r
113                                         row -= 2;\r
114                                         column += 2;\r
115                                         corner1Read = true;\r
116                                 }\r
117                                 else if ((row == numRows - 2) && (column == 0) && ((numColumns & 0x03) != 0) && !corner2Read)\r
118                                 {\r
119                                         result[resultOffset++] = (sbyte) readCorner2(numRows, numColumns);\r
120                                         row -= 2;\r
121                                         column += 2;\r
122                                         corner2Read = true;\r
123                                 }\r
124                                 else if ((row == numRows + 4) && (column == 2) && ((numColumns & 0x07) == 0) && !corner3Read)\r
125                                 {\r
126                                         result[resultOffset++] = (sbyte) readCorner3(numRows, numColumns);\r
127                                         row -= 2;\r
128                                         column += 2;\r
129                                         corner3Read = true;\r
130                                 }\r
131                                 else if ((row == numRows - 2) && (column == 0) && ((numColumns & 0x07) == 4) && !corner4Read)\r
132                                 {\r
133                                         result[resultOffset++] = (sbyte) readCorner4(numRows, numColumns);\r
134                                         row -= 2;\r
135                                         column += 2;\r
136                                         corner4Read = true;\r
137                                 }\r
138                                 else\r
139                                 {\r
140                                         // Sweep upward diagonally to the right\r
141                                         do \r
142                                         {\r
143                                                 if ((row < numRows) && (column >= 0) && !readMappingMatrix.get_Renamed(column, row))\r
144                                                 {\r
145                                                         result[resultOffset++] = (sbyte) readUtah(row, column, numRows, numColumns);\r
146                                                 }\r
147                                                 row -= 2;\r
148                                                 column += 2;\r
149                                         }\r
150                                         while ((row >= 0) && (column < numColumns));\r
151                                         row += 1;\r
152                                         column += 3;\r
153                                         \r
154                                         // Sweep downward diagonally to the left\r
155                                         do \r
156                                         {\r
157                                                 if ((row >= 0) && (column < numColumns) && !readMappingMatrix.get_Renamed(column, row))\r
158                                                 {\r
159                                                         result[resultOffset++] = (sbyte) readUtah(row, column, numRows, numColumns);\r
160                                                 }\r
161                                                 row += 2;\r
162                                                 column -= 2;\r
163                                         }\r
164                                         while ((row < numRows) && (column >= 0));\r
165                                         row += 3;\r
166                                         column += 1;\r
167                                 }\r
168                         }\r
169                         while ((row < numRows) || (column < numColumns));\r
170                         \r
171                         if (resultOffset != version.TotalCodewords)\r
172                         {\r
173                                 throw ReaderException.Instance;\r
174                         }\r
175                         return result;\r
176                 }\r
177                 \r
178                 /// <summary> <p>Reads a bit of the mapping matrix accounting for boundary wrapping.</p>\r
179                 /// \r
180                 /// </summary>\r
181                 /// <param name="row">Row to read in the mapping matrix\r
182                 /// </param>\r
183                 /// <param name="column">Column to read in the mapping matrix\r
184                 /// </param>\r
185                 /// <param name="numRows">Number of rows in the mapping matrix\r
186                 /// </param>\r
187                 /// <param name="numColumns">Number of columns in the mapping matrix\r
188                 /// </param>\r
189                 /// <returns> value of the given bit in the mapping matrix\r
190                 /// </returns>\r
191                 internal bool readModule(int row, int column, int numRows, int numColumns)\r
192                 {\r
193                         // Adjust the row and column indices based on boundary wrapping\r
194                         if (row < 0)\r
195                         {\r
196                                 row += numRows;\r
197                                 column += 4 - ((numRows + 4) & 0x07);\r
198                         }\r
199                         if (column < 0)\r
200                         {\r
201                                 column += numColumns;\r
202                                 row += 4 - ((numColumns + 4) & 0x07);\r
203                         }\r
204                         readMappingMatrix.set_Renamed(column, row);\r
205                         return mappingBitMatrix.get_Renamed(column, row);\r
206                 }\r
207                 \r
208                 /// <summary> <p>Reads the 8 bits of the standard Utah-shaped pattern.</p>\r
209                 /// \r
210                 /// <p>See ISO 16022:2006, 5.8.1 Figure 6</p>\r
211                 /// \r
212                 /// </summary>\r
213                 /// <param name="row">Current row in the mapping matrix, anchored at the 8th bit (LSB) of the pattern\r
214                 /// </param>\r
215                 /// <param name="column">Current column in the mapping matrix, anchored at the 8th bit (LSB) of the pattern\r
216                 /// </param>\r
217                 /// <param name="numRows">Number of rows in the mapping matrix\r
218                 /// </param>\r
219                 /// <param name="numColumns">Number of columns in the mapping matrix\r
220                 /// </param>\r
221                 /// <returns> byte from the utah shape\r
222                 /// </returns>\r
223                 internal int readUtah(int row, int column, int numRows, int numColumns)\r
224                 {\r
225                         int currentByte = 0;\r
226                         if (readModule(row - 2, column - 2, numRows, numColumns))\r
227                         {\r
228                                 currentByte |= 1;\r
229                         }\r
230                         currentByte <<= 1;\r
231                         if (readModule(row - 2, column - 1, numRows, numColumns))\r
232                         {\r
233                                 currentByte |= 1;\r
234                         }\r
235                         currentByte <<= 1;\r
236                         if (readModule(row - 1, column - 2, numRows, numColumns))\r
237                         {\r
238                                 currentByte |= 1;\r
239                         }\r
240                         currentByte <<= 1;\r
241                         if (readModule(row - 1, column - 1, numRows, numColumns))\r
242                         {\r
243                                 currentByte |= 1;\r
244                         }\r
245                         currentByte <<= 1;\r
246                         if (readModule(row - 1, column, numRows, numColumns))\r
247                         {\r
248                                 currentByte |= 1;\r
249                         }\r
250                         currentByte <<= 1;\r
251                         if (readModule(row, column - 2, numRows, numColumns))\r
252                         {\r
253                                 currentByte |= 1;\r
254                         }\r
255                         currentByte <<= 1;\r
256                         if (readModule(row, column - 1, numRows, numColumns))\r
257                         {\r
258                                 currentByte |= 1;\r
259                         }\r
260                         currentByte <<= 1;\r
261                         if (readModule(row, column, numRows, numColumns))\r
262                         {\r
263                                 currentByte |= 1;\r
264                         }\r
265                         return currentByte;\r
266                 }\r
267                 \r
268                 /// <summary> <p>Reads the 8 bits of the special corner condition 1.</p>\r
269                 /// \r
270                 /// <p>See ISO 16022:2006, Figure F.3</p>\r
271                 /// \r
272                 /// </summary>\r
273                 /// <param name="numRows">Number of rows in the mapping matrix\r
274                 /// </param>\r
275                 /// <param name="numColumns">Number of columns in the mapping matrix\r
276                 /// </param>\r
277                 /// <returns> byte from the Corner condition 1\r
278                 /// </returns>\r
279                 internal int readCorner1(int numRows, int numColumns)\r
280                 {\r
281                         int currentByte = 0;\r
282                         if (readModule(numRows - 1, 0, numRows, numColumns))\r
283                         {\r
284                                 currentByte |= 1;\r
285                         }\r
286                         currentByte <<= 1;\r
287                         if (readModule(numRows - 1, 1, numRows, numColumns))\r
288                         {\r
289                                 currentByte |= 1;\r
290                         }\r
291                         currentByte <<= 1;\r
292                         if (readModule(numRows - 1, 2, numRows, numColumns))\r
293                         {\r
294                                 currentByte |= 1;\r
295                         }\r
296                         currentByte <<= 1;\r
297                         if (readModule(0, numColumns - 2, numRows, numColumns))\r
298                         {\r
299                                 currentByte |= 1;\r
300                         }\r
301                         currentByte <<= 1;\r
302                         if (readModule(0, numColumns - 1, numRows, numColumns))\r
303                         {\r
304                                 currentByte |= 1;\r
305                         }\r
306                         currentByte <<= 1;\r
307                         if (readModule(1, numColumns - 1, numRows, numColumns))\r
308                         {\r
309                                 currentByte |= 1;\r
310                         }\r
311                         currentByte <<= 1;\r
312                         if (readModule(2, numColumns - 1, numRows, numColumns))\r
313                         {\r
314                                 currentByte |= 1;\r
315                         }\r
316                         currentByte <<= 1;\r
317                         if (readModule(3, numColumns - 1, numRows, numColumns))\r
318                         {\r
319                                 currentByte |= 1;\r
320                         }\r
321                         return currentByte;\r
322                 }\r
323                 \r
324                 /// <summary> <p>Reads the 8 bits of the special corner condition 2.</p>\r
325                 /// \r
326                 /// <p>See ISO 16022:2006, Figure F.4</p>\r
327                 /// \r
328                 /// </summary>\r
329                 /// <param name="numRows">Number of rows in the mapping matrix\r
330                 /// </param>\r
331                 /// <param name="numColumns">Number of columns in the mapping matrix\r
332                 /// </param>\r
333                 /// <returns> byte from the Corner condition 2\r
334                 /// </returns>\r
335                 internal int readCorner2(int numRows, int numColumns)\r
336                 {\r
337                         int currentByte = 0;\r
338                         if (readModule(numRows - 3, 0, numRows, numColumns))\r
339                         {\r
340                                 currentByte |= 1;\r
341                         }\r
342                         currentByte <<= 1;\r
343                         if (readModule(numRows - 2, 0, numRows, numColumns))\r
344                         {\r
345                                 currentByte |= 1;\r
346                         }\r
347                         currentByte <<= 1;\r
348                         if (readModule(numRows - 1, 0, numRows, numColumns))\r
349                         {\r
350                                 currentByte |= 1;\r
351                         }\r
352                         currentByte <<= 1;\r
353                         if (readModule(0, numColumns - 4, numRows, numColumns))\r
354                         {\r
355                                 currentByte |= 1;\r
356                         }\r
357                         currentByte <<= 1;\r
358                         if (readModule(0, numColumns - 3, numRows, numColumns))\r
359                         {\r
360                                 currentByte |= 1;\r
361                         }\r
362                         currentByte <<= 1;\r
363                         if (readModule(0, numColumns - 2, numRows, numColumns))\r
364                         {\r
365                                 currentByte |= 1;\r
366                         }\r
367                         currentByte <<= 1;\r
368                         if (readModule(0, numColumns - 1, numRows, numColumns))\r
369                         {\r
370                                 currentByte |= 1;\r
371                         }\r
372                         currentByte <<= 1;\r
373                         if (readModule(1, numColumns - 1, numRows, numColumns))\r
374                         {\r
375                                 currentByte |= 1;\r
376                         }\r
377                         return currentByte;\r
378                 }\r
379                 \r
380                 /// <summary> <p>Reads the 8 bits of the special corner condition 3.</p>\r
381                 /// \r
382                 /// <p>See ISO 16022:2006, Figure F.5</p>\r
383                 /// \r
384                 /// </summary>\r
385                 /// <param name="numRows">Number of rows in the mapping matrix\r
386                 /// </param>\r
387                 /// <param name="numColumns">Number of columns in the mapping matrix\r
388                 /// </param>\r
389                 /// <returns> byte from the Corner condition 3\r
390                 /// </returns>\r
391                 internal int readCorner3(int numRows, int numColumns)\r
392                 {\r
393                         int currentByte = 0;\r
394                         if (readModule(numRows - 1, 0, numRows, numColumns))\r
395                         {\r
396                                 currentByte |= 1;\r
397                         }\r
398                         currentByte <<= 1;\r
399                         if (readModule(numRows - 1, numColumns - 1, numRows, numColumns))\r
400                         {\r
401                                 currentByte |= 1;\r
402                         }\r
403                         currentByte <<= 1;\r
404                         if (readModule(0, numColumns - 3, numRows, numColumns))\r
405                         {\r
406                                 currentByte |= 1;\r
407                         }\r
408                         currentByte <<= 1;\r
409                         if (readModule(0, numColumns - 2, numRows, numColumns))\r
410                         {\r
411                                 currentByte |= 1;\r
412                         }\r
413                         currentByte <<= 1;\r
414                         if (readModule(0, numColumns - 1, numRows, numColumns))\r
415                         {\r
416                                 currentByte |= 1;\r
417                         }\r
418                         currentByte <<= 1;\r
419                         if (readModule(1, numColumns - 3, numRows, numColumns))\r
420                         {\r
421                                 currentByte |= 1;\r
422                         }\r
423                         currentByte <<= 1;\r
424                         if (readModule(1, numColumns - 2, numRows, numColumns))\r
425                         {\r
426                                 currentByte |= 1;\r
427                         }\r
428                         currentByte <<= 1;\r
429                         if (readModule(1, numColumns - 1, numRows, numColumns))\r
430                         {\r
431                                 currentByte |= 1;\r
432                         }\r
433                         return currentByte;\r
434                 }\r
435                 \r
436                 /// <summary> <p>Reads the 8 bits of the special corner condition 4.</p>\r
437                 /// \r
438                 /// <p>See ISO 16022:2006, Figure F.6</p>\r
439                 /// \r
440                 /// </summary>\r
441                 /// <param name="numRows">Number of rows in the mapping matrix\r
442                 /// </param>\r
443                 /// <param name="numColumns">Number of columns in the mapping matrix\r
444                 /// </param>\r
445                 /// <returns> byte from the Corner condition 4\r
446                 /// </returns>\r
447                 internal int readCorner4(int numRows, int numColumns)\r
448                 {\r
449                         int currentByte = 0;\r
450                         if (readModule(numRows - 3, 0, numRows, numColumns))\r
451                         {\r
452                                 currentByte |= 1;\r
453                         }\r
454                         currentByte <<= 1;\r
455                         if (readModule(numRows - 2, 0, numRows, numColumns))\r
456                         {\r
457                                 currentByte |= 1;\r
458                         }\r
459                         currentByte <<= 1;\r
460                         if (readModule(numRows - 1, 0, numRows, numColumns))\r
461                         {\r
462                                 currentByte |= 1;\r
463                         }\r
464                         currentByte <<= 1;\r
465                         if (readModule(0, numColumns - 2, numRows, numColumns))\r
466                         {\r
467                                 currentByte |= 1;\r
468                         }\r
469                         currentByte <<= 1;\r
470                         if (readModule(0, numColumns - 1, numRows, numColumns))\r
471                         {\r
472                                 currentByte |= 1;\r
473                         }\r
474                         currentByte <<= 1;\r
475                         if (readModule(1, numColumns - 1, numRows, numColumns))\r
476                         {\r
477                                 currentByte |= 1;\r
478                         }\r
479                         currentByte <<= 1;\r
480                         if (readModule(2, numColumns - 1, numRows, numColumns))\r
481                         {\r
482                                 currentByte |= 1;\r
483                         }\r
484                         currentByte <<= 1;\r
485                         if (readModule(3, numColumns - 1, numRows, numColumns))\r
486                         {\r
487                                 currentByte |= 1;\r
488                         }\r
489                         return currentByte;\r
490                 }\r
491                 \r
492                 /// <summary> <p>Extracts the data region from a {@link BitMatrix} that contains\r
493                 /// alignment patterns.</p>\r
494                 /// \r
495                 /// </summary>\r
496                 /// <param name="bitMatrix">Original {@link BitMatrix} with alignment patterns\r
497                 /// </param>\r
498                 /// <returns> BitMatrix that has the alignment patterns removed\r
499                 /// </returns>\r
500                 internal BitMatrix extractDataRegion(BitMatrix bitMatrix)\r
501                 {\r
502                         int symbolSizeRows = version.SymbolSizeRows;\r
503                         int symbolSizeColumns = version.SymbolSizeColumns;\r
504                         \r
505                         // TODO(bbrown): Make this work with rectangular codes\r
506                         if (bitMatrix.Dimension != symbolSizeRows)\r
507                         {\r
508                                 throw new System.ArgumentException("Dimension of bitMarix must match the version size");\r
509                         }\r
510                         \r
511                         int dataRegionSizeRows = version.DataRegionSizeRows;\r
512                         int dataRegionSizeColumns = version.DataRegionSizeColumns;\r
513                         \r
514                         int numDataRegionsRow = symbolSizeRows / dataRegionSizeRows;\r
515                         int numDataRegionsColumn = symbolSizeColumns / dataRegionSizeColumns;\r
516                         \r
517                         int sizeDataRegionRow = numDataRegionsRow * dataRegionSizeRows;\r
518                         //int sizeDataRegionColumn = numDataRegionsColumn * dataRegionSizeColumns;\r
519                         \r
520                         // TODO(bbrown): Make this work with rectangular codes\r
521                         BitMatrix bitMatrixWithoutAlignment = new BitMatrix(sizeDataRegionRow);\r
522                         for (int dataRegionRow = 0; dataRegionRow < numDataRegionsRow; ++dataRegionRow)\r
523                         {\r
524                                 int dataRegionRowOffset = dataRegionRow * dataRegionSizeRows;\r
525                                 for (int dataRegionColumn = 0; dataRegionColumn < numDataRegionsColumn; ++dataRegionColumn)\r
526                                 {\r
527                                         int dataRegionColumnOffset = dataRegionColumn * dataRegionSizeColumns;\r
528                                         for (int i = 0; i < dataRegionSizeRows; ++i)\r
529                                         {\r
530                                                 int readRowOffset = dataRegionRow * (dataRegionSizeRows + 2) + 1 + i;\r
531                                                 int writeRowOffset = dataRegionRowOffset + i;\r
532                                                 for (int j = 0; j < dataRegionSizeColumns; ++j)\r
533                                                 {\r
534                                                         int readColumnOffset = dataRegionColumn * (dataRegionSizeColumns + 2) + 1 + j;\r
535                                                         if (bitMatrix.get_Renamed(readColumnOffset, readRowOffset))\r
536                                                         {\r
537                                                                 int writeColumnOffset = dataRegionColumnOffset + j;\r
538                                                                 bitMatrixWithoutAlignment.set_Renamed(writeColumnOffset, writeRowOffset);\r
539                                                         }\r
540                                                 }\r
541                                         }\r
542                                 }\r
543                         }\r
544                         return bitMatrixWithoutAlignment;\r
545                 }\r
546         }\r
547 }