Added code for the Data Matrix decoder.
[zxing.git] / core / src / com / google / zxing / datamatrix / decoder / BitMatrixParser.java
diff --git a/core/src/com/google/zxing/datamatrix/decoder/BitMatrixParser.java b/core/src/com/google/zxing/datamatrix/decoder/BitMatrixParser.java
new file mode 100644 (file)
index 0000000..3bc61cd
--- /dev/null
@@ -0,0 +1,446 @@
+/*\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