--- /dev/null
+/*\r
+ * Copyright 2007 Google Inc.\r
+ *\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+\r
+package com.google.zxing.datamatrix.decoder;\r
+\r
+import com.google.zxing.ReaderException;\r
+import com.google.zxing.common.BitMatrix;\r
+\r
+/**\r
+ * @author bbrown@google.com (Brian Brown)\r
+ */\r
+final class BitMatrixParser {\r
+\r
+ private final BitMatrix mappingBitMatrix;\r
+ private final BitMatrix readMappingMatrix;\r
+ private Version version;\r
+// private FormatInformation parsedFormatInfo;\r
+\r
+ /**\r
+ * @param bitMatrix {@link BitMatrix} to parse\r
+ * @throws ReaderException if dimension is < 10 or > 144 or not 0 mod 2\r
+ */\r
+ BitMatrixParser(BitMatrix bitMatrix) throws ReaderException {\r
+ int dimension = bitMatrix.getDimension();\r
+ if (dimension < 10 || dimension > 144 || (dimension & 0x01) != 0) {\r
+ throw new ReaderException("Invalid dimension (" + dimension + ") Must be 0 mod 2 and >= 10 and <= 144");\r
+ }\r
+ \r
+ version = readVersion(bitMatrix);\r
+ this.mappingBitMatrix = ExtractDataRegion(bitMatrix, version);\r
+ // TODO(bbrown): Make this work for rectangular symbols\r
+ this.readMappingMatrix = new BitMatrix(this.mappingBitMatrix.getDimension());\r
+ }\r
+\r
+ /**\r
+ * <p>Creates the version object based on the dimension of the original bit matrix from \r
+ * the datamatrix code.</p>\r
+ *\r
+ * <p>See ISO 16022:2006 Table 7 - ECC 200 symbol attributes</p>\r
+ * \r
+ * @param bitMatrix Original {@link BitMatrix} including alignment patterns\r
+ * @return {@link Version} encapsulating the Data Matrix Code's "version"\r
+ * @throws ReaderException if the dimensions of the mapping matrix are not valid\r
+ * Data Matrix dimensions.\r
+ */\r
+ Version readVersion(BitMatrix bitMatrix) throws ReaderException {\r
+\r
+ if (version != null) {\r
+ return version;\r
+ }\r
+\r
+ // TODO(bbrown): make this work for rectangular dimensions as well.\r
+ int numRows = bitMatrix.getDimension();\r
+ int numColumns = numRows;\r
+ \r
+ return Version.getVersionForDimensions(numRows, numColumns);\r
+ }\r
+\r
+ /**\r
+ * <p>Reads the bits in the {@link BitMatrix} representing the mapping matrix (No alignment patterns)\r
+ * in the correct order in order to reconstitute the codewords bytes contained within the\r
+ * Data Matrix Code.</p>\r
+ *\r
+ * @return bytes encoded within the Data Matrix Code\r
+ * @throws ReaderException if the exact number of bytes expected is not read\r
+ */\r
+ byte[] readCodewords() throws ReaderException {\r
+\r
+ byte[] result = new byte[version.getTotalCodewords()];\r
+ int resultOffset = 0;\r
+ int currentByte = 0;\r
+ int bitsRead = 0;\r
+ \r
+ int row = 4;\r
+ int column = 0;\r
+ // TODO(bbrown): Data Matrix can be rectangular, assuming square for now\r
+ int numRows = mappingBitMatrix.getDimension();\r
+ int numColumns = numRows;\r
+ \r
+ boolean corner1Read = false;\r
+ boolean corner2Read = false;\r
+ boolean corner3Read = false;\r
+ boolean corner4Read = false;\r
+ \r
+ // Read all of the codewords\r
+ do {\r
+ // Check the four corner cases\r
+ if ((row == numRows) && (column == 0) && !corner1Read) {\r
+ result[resultOffset++] = (byte) readCorner1(numRows, numColumns);\r
+ row -= 2; column +=2;\r
+ corner1Read = true;\r
+ } else if ((row == numRows-2) && (column == 0) && ((numColumns & 0x03) != 0) && !corner2Read) {\r
+ result[resultOffset++] = (byte) readCorner2(numRows, numColumns);\r
+ row -= 2; column +=2;\r
+ corner2Read = true;\r
+ } else if ((row == numRows+4) && (column == 2) && ((numColumns & 0x07) == 0) && !corner3Read) {\r
+ result[resultOffset++] = (byte) readCorner3(numRows, numColumns);\r
+ row -= 2; column +=2;\r
+ corner3Read = true;\r
+ } else if ((row == numRows-2) && (column == 0) && ((numColumns & 0x07) == 4) && !corner4Read) {\r
+ result[resultOffset++] = (byte) readCorner4(numRows, numColumns);\r
+ row -= 2; column +=2;\r
+ corner4Read = true;\r
+ } else {\r
+ // Sweep upward diagonally to the right\r
+ do {\r
+ if ((row < numRows) && (column >= 0) && !readMappingMatrix.get(row, column)) {\r
+ result[resultOffset++] = (byte) readUtah(row, column, numRows, numColumns);\r
+ }\r
+ row -= 2; column +=2;\r
+ } while ((row >= 0) && (column < numColumns));\r
+ row += 1; column +=3;\r
+ \r
+ // Sweep downward giagonally to the left\r
+ do {\r
+ if ((row >= 0) && (column < numColumns) && !readMappingMatrix.get(row, column)) {\r
+ result[resultOffset++] = (byte) readUtah(row, column, numRows, numColumns);\r
+ }\r
+ row += 2; column -=2;\r
+ } while ((row < numRows) && (column >= 0));\r
+ row += 3; column +=1;\r
+ }\r
+ } while ((row < numRows) || (column < numColumns));\r
+\r
+ if (resultOffset != version.getTotalCodewords()) {\r
+ throw new ReaderException("Did not read all codewords");\r
+ }\r
+ return result;\r
+ }\r
+ \r
+ /**\r
+ * <p>Reads a bit of the mapping matrix accounting for boundry wrapping.</p>\r
+ * \r
+ * @param Row to read in the mapping matrix\r
+ * @param Column to read in the mapping matrix\r
+ * @param Number of rows in the mapping matrix\r
+ * @param Number of columns in the mapping matrix\r
+ * @return value of the given bit in the mapping matrix\r
+ */\r
+ boolean readModule(int row, int column, int numRows, int numColumns) {\r
+ // Adjust the row and column indicies based on boundry wrapping\r
+ if (row < 0) {\r
+ row += numRows;\r
+ column += 4 - ((numRows + 4) & 0x07);\r
+ }\r
+ if (column < 0) {\r
+ column += numColumns;\r
+ row += 4 - ((numColumns + 4) & 0x07);\r
+ }\r
+ readMappingMatrix.set(row, column);\r
+ return mappingBitMatrix.get(row, column);\r
+ }\r
+ \r
+ /**\r
+ * <p>Reads the 8 bits of the standard utah shaped pattern.</p>\r
+ * \r
+ * <p>See ISO 16022:2006, 5.8.1 Figure 6</p>\r
+ * \r
+ * @param Current row in the mapping matrix, anchored at the 8th bit (LSB) of the pattern\r
+ * @param Current column in the mapping matrix, anchored at the 8th bit (LSB) of the pattern\r
+ * @param Number of rows in the mapping matrix\r
+ * @param Number of columns in the mapping matrix\r
+ * @return byte from the utah shape\r
+ */\r
+ int readUtah(int row, int column, int numRows, int numColumns) {\r
+ int currentByte = 0;\r
+ if (readModule(row - 2, column - 2, numRows, numColumns)) {\r
+ currentByte |= 1;\r
+ }\r
+ currentByte <<= 1;\r
+ if (readModule(row - 2, column - 1, numRows, numColumns)) {\r
+ currentByte |= 1;\r
+ }\r
+ currentByte <<= 1;\r
+ if (readModule(row - 1, column - 2, numRows, numColumns)) {\r
+ currentByte |= 1;\r
+ }\r
+ currentByte <<= 1;\r
+ if (readModule(row - 1, column - 1, numRows, numColumns)) {\r
+ currentByte |= 1;\r
+ }\r
+ currentByte <<= 1;\r
+ if (readModule(row - 1, column, numRows, numColumns)) {\r
+ currentByte |= 1;\r
+ }\r
+ currentByte <<= 1;\r
+ if (readModule(row, column - 2, numRows, numColumns)) {\r
+ currentByte |= 1;\r
+ }\r
+ currentByte <<= 1;\r
+ if (readModule(row, column - 1, numRows, numColumns)) {\r
+ currentByte |= 1;\r
+ }\r
+ currentByte <<= 1;\r
+ if (readModule(row, column, numRows, numColumns)) {\r
+ currentByte |= 1;\r
+ }\r
+ return currentByte;\r
+ }\r
+ \r
+ /**\r
+ * <p>Reads the 8 bits of the special corner condition 1.</p>\r
+ * \r
+ * <p>See ISO 16022:2006, Figure F.3</p>\r
+ * \r
+ * @param Number of rows in the mapping matrix\r
+ * @param Number of columns in the mapping matrix\r
+ * @return byte from the Corner condition 1\r
+ */\r
+ int readCorner1(int numRows, int numColumns) {\r
+ int currentByte = 0;\r
+ if (readModule(numRows - 1, 0, numRows, numColumns)) {\r
+ currentByte |= 1;\r
+ }\r
+ currentByte <<= 1;\r
+ if (readModule(numRows - 1, 1, numRows, numColumns)) {\r
+ currentByte |= 1;\r
+ }\r
+ currentByte <<= 1;\r
+ if (readModule(numRows - 1, 2, numRows, numColumns)) {\r
+ currentByte |= 1;\r
+ }\r
+ currentByte <<= 1;\r
+ if (readModule(0, numColumns - 2, numRows, numColumns)) {\r
+ currentByte |= 1;\r
+ }\r
+ currentByte <<= 1;\r
+ if (readModule(0, numColumns - 1, numRows, numColumns)) {\r
+ currentByte |= 1;\r
+ }\r
+ currentByte <<= 1;\r
+ if (readModule(1, numColumns - 1, numRows, numColumns)) {\r
+ currentByte |= 1;\r
+ }\r
+ currentByte <<= 1;\r
+ if (readModule(2, numColumns - 1, numRows, numColumns)) {\r
+ currentByte |= 1;\r
+ }\r
+ currentByte <<= 1;\r
+ if (readModule(3, numColumns - 1, numRows, numColumns)) {\r
+ currentByte |= 1;\r
+ }\r
+ return currentByte;\r
+ }\r
+ \r
+ /**\r
+ * <p>Reads the 8 bits of the special corner condition 2.</p>\r
+ * \r
+ * <p>See ISO 16022:2006, Figure F.4</p>\r
+ * \r
+ * @param Number of rows in the mapping matrix\r
+ * @param Number of columns in the mapping matrix\r
+ * @return byte from the Corner condition 2\r
+ */\r
+ int readCorner2(int numRows, int numColumns) {\r
+ int currentByte = 0;\r
+ if (readModule(numRows - 3, 0, numRows, numColumns)) {\r
+ currentByte |= 1;\r
+ }\r
+ currentByte <<= 1;\r
+ if (readModule(numRows - 2, 0, numRows, numColumns)) {\r
+ currentByte |= 1;\r
+ }\r
+ currentByte <<= 1;\r
+ if (readModule(numRows - 1, 0, numRows, numColumns)) {\r
+ currentByte |= 1;\r
+ }\r
+ currentByte <<= 1;\r
+ if (readModule(0, numColumns - 4, numRows, numColumns)) {\r
+ currentByte |= 1;\r
+ }\r
+ currentByte <<= 1;\r
+ if (readModule(0, numColumns - 3, numRows, numColumns)) {\r
+ currentByte |= 1;\r
+ }\r
+ currentByte <<= 1;\r
+ if (readModule(0, numColumns - 2, numRows, numColumns)) {\r
+ currentByte |= 1;\r
+ }\r
+ currentByte <<= 1;\r
+ if (readModule(0, numColumns - 1, numRows, numColumns)) {\r
+ currentByte |= 1;\r
+ }\r
+ currentByte <<= 1;\r
+ if (readModule(1, numColumns - 1, numRows, numColumns)) {\r
+ currentByte |= 1;\r
+ }\r
+ return currentByte;\r
+ }\r
+ \r
+ /**\r
+ * <p>Reads the 8 bits of the special corner condition 3.</p>\r
+ * \r
+ * <p>See ISO 16022:2006, Figure F.5</p>\r
+ * \r
+ * @param Number of rows in the mapping matrix\r
+ * @param Number of columns in the mapping matrix\r
+ * @return byte from the Corner condition 3\r
+ */\r
+ int readCorner3(int numRows, int numColumns) {\r
+ int currentByte = 0;\r
+ if (readModule(numRows - 1, 0, numRows, numColumns)) {\r
+ currentByte |= 1;\r
+ }\r
+ currentByte <<= 1;\r
+ if (readModule(numRows - 1, numColumns - 1, numRows, numColumns)) {\r
+ currentByte |= 1;\r
+ }\r
+ currentByte <<= 1;\r
+ if (readModule(0, numColumns - 3, numRows, numColumns)) {\r
+ currentByte |= 1;\r
+ }\r
+ currentByte <<= 1;\r
+ if (readModule(0, numColumns - 2, numRows, numColumns)) {\r
+ currentByte |= 1;\r
+ }\r
+ currentByte <<= 1;\r
+ if (readModule(0, numColumns - 1, numRows, numColumns)) {\r
+ currentByte |= 1;\r
+ }\r
+ currentByte <<= 1;\r
+ if (readModule(1, numColumns - 3, numRows, numColumns)) {\r
+ currentByte |= 1;\r
+ }\r
+ currentByte <<= 1;\r
+ if (readModule(1, numColumns - 2, numRows, numColumns)) {\r
+ currentByte |= 1;\r
+ }\r
+ currentByte <<= 1;\r
+ if (readModule(1, numColumns - 1, numRows, numColumns)) {\r
+ currentByte |= 1;\r
+ }\r
+ return currentByte;\r
+ }\r
+ \r
+ /**\r
+ * <p>Reads the 8 bits of the special corner condition 4.</p>\r
+ * \r
+ * <p>See ISO 16022:2006, Figure F.6</p>\r
+ * \r
+ * @param Number of rows in the mapping matrix\r
+ * @param Number of columns in the mapping matrix\r
+ * @return byte from the Corner condition 4\r
+ */\r
+ int readCorner4(int numRows, int numColumns) {\r
+ int currentByte = 0;\r
+ if (readModule(numRows - 3, 0, numRows, numColumns)) {\r
+ currentByte |= 1;\r
+ }\r
+ currentByte <<= 1;\r
+ if (readModule(numRows - 2, 0, numRows, numColumns)) {\r
+ currentByte |= 1;\r
+ }\r
+ currentByte <<= 1;\r
+ if (readModule(numRows - 1, 0, numRows, numColumns)) {\r
+ currentByte |= 1;\r
+ }\r
+ currentByte <<= 1;\r
+ if (readModule(0, numColumns - 2, numRows, numColumns)) {\r
+ currentByte |= 1;\r
+ }\r
+ currentByte <<= 1;\r
+ if (readModule(0, numColumns - 1, numRows, numColumns)) {\r
+ currentByte |= 1;\r
+ }\r
+ currentByte <<= 1;\r
+ if (readModule(1, numColumns - 1, numRows, numColumns)) {\r
+ currentByte |= 1;\r
+ }\r
+ currentByte <<= 1;\r
+ if (readModule(2, numColumns - 1, numRows, numColumns)) {\r
+ currentByte |= 1;\r
+ }\r
+ currentByte <<= 1;\r
+ if (readModule(3, numColumns - 1, numRows, numColumns)) {\r
+ currentByte |= 1;\r
+ }\r
+ return currentByte;\r
+ }\r
+ \r
+ /**\r
+ * <p>Extracts the data region from a {@link BitMatrix} that contains\r
+ * alignment patterns.</p>\r
+ * \r
+ * @param bitMarix Original {@link BitMatrix} with alignment patterns\r
+ * @param version {@link Version} information corresponding with the bitMatrix\r
+ * @return BitMatrix that has the alignment patterns removed\r
+ */\r
+ BitMatrix ExtractDataRegion(BitMatrix bitMatrix, Version version) {\r
+ int symbolSizeRows = version.getSymbolSizeRows();\r
+ int symbolSizeColumns = version.getSymbolSizeColumns();\r
+ \r
+ // TODO(bbrown): Make this work with rectangular codes\r
+ if (bitMatrix.getDimension() != symbolSizeRows) {\r
+ throw new IllegalArgumentException("Dimension of bitMarix must match the version size");\r
+ }\r
+ \r
+ int dataRegionSizeRows = version.getDataRegionSizeRows();\r
+ int dataRegionSizeColumns = version.getDataRegionSizeColumns();\r
+ \r
+ int numDataRegionsRow = symbolSizeRows / dataRegionSizeRows;\r
+ int numDataRegionsColumn = symbolSizeColumns / dataRegionSizeColumns;\r
+ \r
+ int sizeDataRegionRow = numDataRegionsRow * dataRegionSizeRows;\r
+ int sizeDataRegionColumn = numDataRegionsColumn * dataRegionSizeColumns;\r
+ \r
+ // TODO(bbrown): Make this work with rectangular codes\r
+ BitMatrix mappingBitMatrix = new BitMatrix(sizeDataRegionRow);\r
+ int readRowOffset = 0;\r
+ int readColumnOffset = 0;\r
+ int writeRowOffset = 0;\r
+ int writeColumnOffset = 0;\r
+ for (int dataRegionRow = 0; dataRegionRow < numDataRegionsRow; ++dataRegionRow) {\r
+ for (int dataRegionColumn = 0; dataRegionColumn < numDataRegionsColumn; ++dataRegionColumn) {\r
+ for (int i = 0; i < dataRegionSizeRows; ++i) {\r
+ for (int j = 0; j < dataRegionSizeColumns; ++j) {\r
+ readRowOffset = dataRegionRow * (dataRegionSizeRows + 2) + 1 + i;\r
+ readColumnOffset = dataRegionColumn * (dataRegionSizeColumns + 2) + 1 + j;\r
+ writeRowOffset = dataRegionRow * dataRegionSizeRows + i;\r
+ writeColumnOffset = dataRegionColumn * dataRegionSizeColumns + j;\r
+ \r
+ if (bitMatrix.get(readRowOffset, readColumnOffset)) {\r
+ mappingBitMatrix.set(writeRowOffset, writeColumnOffset);\r
+ }\r
+ }\r
+ }\r
+ }\r
+ }\r
+ \r
+ return mappingBitMatrix;\r
+ }\r
+\r
+}
\ No newline at end of file