#ADD: DataMatrix reader.
authorluizcroc <luizcroc@59b500cc-1b3d-0410-9834-0bbf25fbcc57>
Tue, 23 Feb 2010 23:50:08 +0000 (23:50 +0000)
committerluizcroc <luizcroc@59b500cc-1b3d-0410-9834-0bbf25fbcc57>
Tue, 23 Feb 2010 23:50:08 +0000 (23:50 +0000)
#CHANGE: MultiFormatReader can read DataMatrix.

git-svn-id: http://zxing.googlecode.com/svn/trunk@1217 59b500cc-1b3d-0410-9834-0bbf25fbcc57

20 files changed:
cpp/core/src/zxing/BarcodeFormat.h
cpp/core/src/zxing/MultiFormatReader.cpp
cpp/core/src/zxing/datamatrix/DataMatrixReader.cpp [new file with mode: 0644]
cpp/core/src/zxing/datamatrix/DataMatrixReader.h [new file with mode: 0644]
cpp/core/src/zxing/datamatrix/Version.cpp [new file with mode: 0644]
cpp/core/src/zxing/datamatrix/Version.h [new file with mode: 0644]
cpp/core/src/zxing/datamatrix/decoder/BitMatrixParser.cpp [new file with mode: 0644]
cpp/core/src/zxing/datamatrix/decoder/BitMatrixParser.h [new file with mode: 0644]
cpp/core/src/zxing/datamatrix/decoder/DataBlock.cpp [new file with mode: 0644]
cpp/core/src/zxing/datamatrix/decoder/DataBlock.h [new file with mode: 0644]
cpp/core/src/zxing/datamatrix/decoder/DecodedBitStreamParser.cpp [new file with mode: 0644]
cpp/core/src/zxing/datamatrix/decoder/DecodedBitStreamParser.h [new file with mode: 0644]
cpp/core/src/zxing/datamatrix/decoder/Decoder.cpp [new file with mode: 0644]
cpp/core/src/zxing/datamatrix/decoder/Decoder.h [new file with mode: 0644]
cpp/core/src/zxing/datamatrix/detector/CornerPoint.cpp [new file with mode: 0644]
cpp/core/src/zxing/datamatrix/detector/CornerPoint.h [new file with mode: 0644]
cpp/core/src/zxing/datamatrix/detector/Detector.cpp [new file with mode: 0644]
cpp/core/src/zxing/datamatrix/detector/Detector.h [new file with mode: 0644]
cpp/core/src/zxing/datamatrix/detector/MonochromeRectangleDetector.cpp [new file with mode: 0644]
cpp/core/src/zxing/datamatrix/detector/MonochromeRectangleDetector.h [new file with mode: 0644]

index c55edad..943831d 100644 (file)
@@ -27,6 +27,7 @@ namespace zxing {
        typedef enum BarcodeFormat {
                BarcodeFormat_None = 0, 
                BarcodeFormat_QR_CODE,
+               BarcodeFormat_DATA_MATRIX,
                BarcodeFormat_UPC_E,
                BarcodeFormat_UPC_A,
                BarcodeFormat_EAN_8,
index 2483ffc..72b950c 100644 (file)
@@ -3,6 +3,7 @@
  *  ZXing
  *
  *  Created by Lukasz Warchol on 10-01-26.
+ *  Modified by Luiz Silva on 09/02/2010.
  *  Copyright 2010 ZXing authors All rights reserved.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -20,6 +21,7 @@
 
 #include "MultiFormatReader.h"
 #include <zxing/qrcode/QRCodeReader.h>
+#include <zxing/datamatrix/DataMatrixReader.h>
 #include <zxing/oned/MultiFormatUPCEANReader.h>
 #include <zxing/oned/MultiFormatOneDReader.h>
 #include <zxing/ReaderException.h>
@@ -29,6 +31,7 @@ namespace zxing {
                readers = new std::vector<Reader*>();
                
                readers->push_back(new zxing::qrcode::QRCodeReader());
+               readers->push_back(new zxing::datamatrix::DataMatrixReader());
                readers->push_back(new zxing::oned::MultiFormatUPCEANReader());
                readers->push_back(new zxing::oned::MultiFormatOneDReader());
        }
diff --git a/cpp/core/src/zxing/datamatrix/DataMatrixReader.cpp b/cpp/core/src/zxing/datamatrix/DataMatrixReader.cpp
new file mode 100644 (file)
index 0000000..92caa72
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ *  DataMatrixReader.cpp
+ *  zxing
+ *
+ *  Created by Luiz Silva on 09/02/2010.
+ *  Copyright 2010 ZXing authors All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <zxing/datamatrix/DataMatrixReader.h>
+#include <zxing/datamatrix/detector/Detector.h>
+#include <iostream>
+
+namespace zxing {
+namespace datamatrix {
+
+using namespace std;
+
+DataMatrixReader::DataMatrixReader() :
+    decoder_() {
+}
+
+Ref<Result> DataMatrixReader::decode(Ref<BinaryBitmap> image) {
+#ifdef DEBUG
+  cout << "decoding image " << image.object_ << ":\n" << flush;
+#endif
+
+  Detector detector(image->getBlackMatrix());
+
+
+#ifdef DEBUG
+  cout << "(1) created detector " << &detector << "\n" << flush;
+#endif
+
+  Ref<DetectorResult> detectorResult(detector.detect());
+#ifdef DEBUG
+  cout << "(2) detected, have detectorResult " << detectorResult.object_ << "\n" << flush;
+#endif
+
+  std::vector<Ref<ResultPoint> > points(detectorResult->getPoints());
+
+
+#ifdef DEBUG
+  cout << "(3) extracted points " << &points << "\n" << flush;
+  cout << "found " << points->size() << " points:\n";
+  for (size_t i = 0; i < points->size(); i++) {
+    cout << "   " << points[i]->getX() << "," << points[i]->getY() << "\n";
+  }
+  cout << "bits:\n";
+  cout << *(detectorResult->getBits()) << "\n";
+#endif
+
+  Ref<DecoderResult> decoderResult(decoder_.decode(detectorResult->getBits()));
+#ifdef DEBUG
+  cout << "(4) decoded, have decoderResult " << decoderResult.object_ << "\n" << flush;
+#endif
+
+  Ref<Result> result(
+    new Result(decoderResult->getText(), decoderResult->getRawBytes(), points, BarcodeFormat_DATA_MATRIX));
+#ifdef DEBUG
+  cout << "(5) created result " << result.object_ << ", returning\n" << flush;
+#endif
+
+  return result;
+}
+
+DataMatrixReader::~DataMatrixReader() {
+}
+
+}
+}
diff --git a/cpp/core/src/zxing/datamatrix/DataMatrixReader.h b/cpp/core/src/zxing/datamatrix/DataMatrixReader.h
new file mode 100644 (file)
index 0000000..4d621c8
--- /dev/null
@@ -0,0 +1,44 @@
+#ifndef __DATA_MATRIX_READER_H__
+#define __DATA_MATRIX_READER_H__
+
+/*
+ *  DataMatrixReader.h
+ *  zxing
+ *
+ *  Created by Luiz Silva on 09/02/2010.
+ *  Copyright 2010 ZXing authors All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <zxing/Reader.h>
+#include <zxing/datamatrix/decoder/Decoder.h>
+
+namespace zxing {
+namespace datamatrix {
+
+class DataMatrixReader : public Reader {
+private:
+  Decoder decoder_;
+
+public:
+  DataMatrixReader();
+  virtual Ref<Result> decode(Ref<BinaryBitmap> image);
+  virtual ~DataMatrixReader();
+
+};
+
+}
+}
+
+#endif // __DATA_MATRIX_READER_H__
diff --git a/cpp/core/src/zxing/datamatrix/Version.cpp b/cpp/core/src/zxing/datamatrix/Version.cpp
new file mode 100644 (file)
index 0000000..f1b25a4
--- /dev/null
@@ -0,0 +1,202 @@
+/*
+ *  Version.cpp
+ *  zxing
+ *
+ *  Created by Luiz Silva on 09/02/2010.
+ *  Copyright 2010 ZXing authors All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <zxing/datamatrix/Version.h>
+#include <cstdarg>
+#include <limits>
+#include <iostream>
+
+namespace zxing {
+namespace datamatrix {
+using namespace std;
+
+ECB::ECB(int count, int dataCodewords) :
+    count_(count), dataCodewords_(dataCodewords) {
+}
+
+int ECB::getCount() {
+  return count_;
+}
+
+int ECB::getDataCodewords() {
+  return dataCodewords_;
+}
+
+ECBlocks::ECBlocks(int ecCodewords, ECB *ecBlocks) :
+    ecCodewords_(ecCodewords) {
+  ecBlocks_.push_back(ecBlocks);
+}
+
+ECBlocks::ECBlocks(int ecCodewords, ECB *ecBlocks1, ECB *ecBlocks2) :
+    ecCodewords_(ecCodewords) {
+  ecBlocks_.push_back(ecBlocks1);
+  ecBlocks_.push_back(ecBlocks2);
+}
+
+int ECBlocks::getECCodewords() {
+  return ecCodewords_;
+}
+
+std::vector<ECB*>& ECBlocks::getECBlocks() {
+  return ecBlocks_;
+}
+
+ECBlocks::~ECBlocks() {
+  for (size_t i = 0; i < ecBlocks_.size(); i++) {
+    delete ecBlocks_[i];
+  }
+}
+
+vector<Ref<Version> > Version::VERSIONS;
+static int N_VERSIONS = Version::buildVersions();
+\r
+Version::Version(int versionNumber, int symbolSizeRows, int symbolSizeColumns, int dataRegionSizeRows,
+               int dataRegionSizeColumns, ECBlocks* ecBlocks) : versionNumber_(versionNumber), 
+               symbolSizeRows_(symbolSizeRows), symbolSizeColumns_(symbolSizeColumns), 
+               dataRegionSizeRows_(dataRegionSizeRows), dataRegionSizeColumns_(dataRegionSizeColumns), 
+               ecBlocks_(ecBlocks) {\r
+    // Calculate the total number of codewords\r
+    int total = 0;\r
+    int ecCodewords = ecBlocks_->getECCodewords();\r
+    vector<ECB*> &ecbArray = ecBlocks_->getECBlocks();\r
+    for (unsigned int i = 0; i < ecbArray.size(); i++) {\r
+      ECB *ecBlock = ecbArray[i];\r
+      total += ecBlock->getCount() * (ecBlock->getDataCodewords() + ecCodewords);\r
+    }\r
+    totalCodewords_ = total;\r
+}\r
+
+Version::~Version() {
+    delete ecBlocks_;
+}
+\r
+int Version::getVersionNumber() {\r
+  return versionNumber_;\r
+}\r
+
+int Version::getSymbolSizeRows() {\r
+  return symbolSizeRows_;\r
+}\r
+  \r
+int Version::getSymbolSizeColumns() {\r
+  return symbolSizeColumns_;\r
+}\r
+\r
+int Version::getDataRegionSizeRows() {\r
+  return dataRegionSizeRows_;\r
+}\r
+  \r
+int Version::getDataRegionSizeColumns() {\r
+  return dataRegionSizeColumns_;\r
+}\r
+  \r
+int Version::getTotalCodewords() {\r
+  return totalCodewords_;\r
+}
+\r
+ECBlocks* Version::getECBlocks() {\r
+  return ecBlocks_;\r
+}\r
+  \r
+Version* Version::getVersionForDimensions(int numRows, int numColumns) {\r
+    if ((numRows & 0x01) != 0 || (numColumns & 0x01) != 0) {\r
+      throw ReaderException("Number of rows and columns must be even");\r
+    }\r
+    \r
+    // TODO(bbrown): This is doing a linear search through the array of versions.\r
+    // If we interleave the rectangular versions with the square versions we could\r
+    // do a binary search.\r
+    for (int i = 0; i < N_VERSIONS; ++i){\r
+      Version* version = VERSIONS[i];\r
+      if (version->getSymbolSizeRows() == numRows && version->getSymbolSizeColumns() == numColumns) {\r
+        return version;\r
+      }\r
+    }
+    throw ReaderException("Error version not found");\r
+  }
+
+/**\r
+ * See ISO 16022:2006 5.5.1 Table 7\r
+ */
+int Version::buildVersions() {
+  VERSIONS.push_back(Ref<Version>(new Version(1, 10, 10, 8, 8,\r
+                                                 new ECBlocks(5, new ECB(1, 3)))));
+  VERSIONS.push_back(Ref<Version>(new Version(2, 12, 12, 10, 10,\r
+                                                 new ECBlocks(7, new ECB(1, 5)))));
+  VERSIONS.push_back(Ref<Version>(new Version(3, 14, 14, 12, 12,\r
+                                                 new ECBlocks(10, new ECB(1, 8)))));
+  VERSIONS.push_back(Ref<Version>(new Version(4, 16, 16, 14, 14,\r
+                                                 new ECBlocks(12, new ECB(1, 12)))));
+  VERSIONS.push_back(Ref<Version>(new Version(5, 18, 18, 16, 16,\r
+                                                 new ECBlocks(14, new ECB(1, 18)))));
+  VERSIONS.push_back(Ref<Version>(new Version(6, 20, 20, 18, 18,\r
+                                                 new ECBlocks(18, new ECB(1, 22)))));
+  VERSIONS.push_back(Ref<Version>(new Version(7, 22, 22, 20, 20,\r
+                                                 new ECBlocks(20, new ECB(1, 30)))));
+  VERSIONS.push_back(Ref<Version>(new Version(8, 24, 24, 22, 22,\r
+                                                 new ECBlocks(24, new ECB(1, 36)))));
+  VERSIONS.push_back(Ref<Version>(new Version(9, 26, 26, 24, 24,\r
+                                                 new ECBlocks(28, new ECB(1, 44)))));
+  VERSIONS.push_back(Ref<Version>(new Version(10, 32, 32, 14, 14,\r
+                                                 new ECBlocks(36, new ECB(1, 62)))));
+  VERSIONS.push_back(Ref<Version>(new Version(11, 36, 36, 16, 16,\r
+                                                 new ECBlocks(42, new ECB(1, 86)))));
+  VERSIONS.push_back(Ref<Version>(new Version(12, 40, 40, 18, 18,\r
+                                                 new ECBlocks(48, new ECB(1, 114)))));
+  VERSIONS.push_back(Ref<Version>(new Version(13, 44, 44, 20, 20,\r
+                                                 new ECBlocks(56, new ECB(1, 144)))));
+  VERSIONS.push_back(Ref<Version>(new Version(14, 48, 48, 22, 22,\r
+                                                 new ECBlocks(68, new ECB(1, 174)))));
+  VERSIONS.push_back(Ref<Version>(new Version(15, 52, 52, 24, 24,\r
+                                                 new ECBlocks(42, new ECB(2, 102)))));
+  VERSIONS.push_back(Ref<Version>(new Version(16, 64, 64, 14, 14,\r
+                                                 new ECBlocks(56, new ECB(2, 140)))));
+  VERSIONS.push_back(Ref<Version>(new Version(17, 72, 72, 16, 16,\r
+                                                 new ECBlocks(36, new ECB(4, 92)))));
+  VERSIONS.push_back(Ref<Version>(new  Version(18, 80, 80, 18, 18,\r
+                                                 new ECBlocks(48, new ECB(4, 114)))));
+  VERSIONS.push_back(Ref<Version>(new Version(19, 88, 88, 20, 20,\r
+                                                 new ECBlocks(56, new ECB(4, 144)))));
+  VERSIONS.push_back(Ref<Version>(new Version(20, 96, 96, 22, 22,\r
+                                                 new ECBlocks(68, new ECB(4, 174)))));
+  VERSIONS.push_back(Ref<Version>(new Version(21, 104, 104, 24, 24,\r
+                                                 new ECBlocks(56, new ECB(6, 136)))));
+  VERSIONS.push_back(Ref<Version>(new Version(22, 120, 120, 18, 18,\r
+                                                 new ECBlocks(68, new ECB(6, 175)))));
+  VERSIONS.push_back(Ref<Version>(new Version(23, 132, 132, 20, 20,\r
+                                                 new ECBlocks(62, new ECB(8, 163)))));
+  VERSIONS.push_back(Ref<Version>(new Version(24, 144, 144, 22, 22,\r
+                                                 new ECBlocks(62, new ECB(8, 156), new ECB(2, 155)))));
+  VERSIONS.push_back(Ref<Version>(new Version(25, 8, 18, 6, 16,\r
+                                                 new ECBlocks(7, new ECB(1, 5)))));
+  VERSIONS.push_back(Ref<Version>(new Version(26, 8, 32, 6, 14,\r
+                                                 new ECBlocks(11, new ECB(1, 10)))));
+  VERSIONS.push_back(Ref<Version>(new Version(27, 12, 26, 10, 24,\r
+                                                     new ECBlocks(14, new ECB(1, 16)))));
+  VERSIONS.push_back(Ref<Version>(new Version(28, 12, 36, 10, 16,\r
+                                                     new ECBlocks(18, new ECB(1, 22)))));
+  VERSIONS.push_back(Ref<Version>(new Version(29, 16, 36, 10, 16,\r
+                                                     new ECBlocks(24, new ECB(1, 32)))));
+  VERSIONS.push_back(Ref<Version>(new Version(30, 16, 48, 14, 22,\r
+                                                     new ECBlocks(28, new ECB(1, 49)))));
+  return VERSIONS.size();
+}
+}
+}
diff --git a/cpp/core/src/zxing/datamatrix/Version.h b/cpp/core/src/zxing/datamatrix/Version.h
new file mode 100644 (file)
index 0000000..cdcec12
--- /dev/null
@@ -0,0 +1,85 @@
+#ifndef __VERSION_H__
+#define __VERSION_H__
+
+/*
+ *  Version.h
+ *  zxing
+ *
+ *  Created by Luiz Silva on 09/02/2010.
+ *  Copyright 2010 ZXing authors All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <zxing/ReaderException.h>
+#include <zxing/common/BitMatrix.h>
+#include <zxing/common/Counted.h>
+#include <vector>
+#include <valarray>
+
+namespace zxing {
+namespace datamatrix {
+using namespace std;
+
+class ECB {
+private:
+  int count_;
+  int dataCodewords_;
+public:
+  ECB(int count, int dataCodewords);
+  int getCount();
+  int getDataCodewords();
+};
+
+class ECBlocks {
+private:
+  int ecCodewords_;
+  std::vector<ECB*> ecBlocks_;
+public:
+  ECBlocks(int ecCodewords, ECB *ecBlocks);
+  ECBlocks(int ecCodewords, ECB *ecBlocks1, ECB *ecBlocks2);
+  int getECCodewords();
+  std::vector<ECB*>& getECBlocks();
+  ~ECBlocks();
+};
+
+class Version : public Counted {
+private:\r
+  int versionNumber_;\r
+  int symbolSizeRows_;\r
+  int symbolSizeColumns_;\r
+  int dataRegionSizeRows_;\r
+  int dataRegionSizeColumns_;
+  ECBlocks* ecBlocks_;
+  int totalCodewords_;
+  Version(int versionNumber, int symbolSizeRows, int symbolSizeColumns, int dataRegionSizeRows,
+                 int dataRegionSizeColumns, ECBlocks *ecBlocks);
+
+public:
+  static std::vector<Ref<Version> > VERSIONS;
+  
+  ~Version();
+  int getVersionNumber();\r
+  int getSymbolSizeRows();\r
+  int getSymbolSizeColumns();  \r
+  int getDataRegionSizeRows();  \r
+  int getDataRegionSizeColumns();
+  int getTotalCodewords();
+  ECBlocks* getECBlocks();
+  static int  buildVersions();  \r
+  Version* getVersionForDimensions(int numRows, int numColumns);
+};
+}
+}
+
+#endif // __VERSION_H__
diff --git a/cpp/core/src/zxing/datamatrix/decoder/BitMatrixParser.cpp b/cpp/core/src/zxing/datamatrix/decoder/BitMatrixParser.cpp
new file mode 100644 (file)
index 0000000..08faa76
--- /dev/null
@@ -0,0 +1,362 @@
+/*
+ *  BitMatrixParser.cpp
+ *  zxing
+ *
+ *  Created by Luiz Silva on 09/02/2010.
+ *  Copyright 2010 ZXing authors All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <zxing/datamatrix/decoder/BitMatrixParser.h>
+#include <zxing/common/IllegalArgumentException.h>
+
+namespace zxing {
+namespace datamatrix {
+
+int BitMatrixParser::copyBit(size_t x, size_t y, int versionBits) {
+  return bitMatrix_->get(x, y) ? (versionBits << 1) | 0x1 : versionBits << 1;
+}
+
+BitMatrixParser::BitMatrixParser(Ref<BitMatrix> bitMatrix) : parsedVersion_(0) {
+  size_t dimension = bitMatrix->getDimension();
+  if (dimension < 10 || dimension > 144 || (dimension & 0x01) != 0)
+    throw ReaderException("Dimension must be even, > 10 < 144");
+  \r
+  parsedVersion_ = readVersion(bitMatrix);
+  bitMatrix_ = extractDataRegion(bitMatrix);\r
+  // TODO(bbrown): Make this work for rectangular symbols\r
+  readBitMatrix_ = new BitMatrix(bitMatrix_->getDimension());
+}
+
+Version *BitMatrixParser::readVersion(Ref<BitMatrix> bitMatrix) {
+  if (parsedVersion_ != 0) {
+    return parsedVersion_;
+  }
+\r
+  // TODO(bbrown): make this work for rectangular dimensions as well.\r
+  int numRows = bitMatrix->getDimension();\r
+  int numColumns = numRows;\r
+   
+  Version* version = parsedVersion_->getVersionForDimensions(numRows, numColumns);
+  if (version != 0) {
+    return version;
+  }
+  throw ReaderException("Couldn't decode version");
+}
+
+ArrayRef<unsigned char> BitMatrixParser::readCodewords() {
+       ArrayRef<unsigned char> result(parsedVersion_->getTotalCodewords());
+       int resultOffset = 0;\r
+    int row = 4;\r
+    int column = 0;
+\r
+    // TODO(bbrown): Data Matrix can be rectangular, assuming square for now\r
+    int numRows = bitMatrix_->getDimension();\r
+    int numColumns = numRows;\r
+    \r
+    bool corner1Read = false;\r
+    bool corner2Read = false;\r
+    bool corner3Read = false;\r
+    bool 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++] = (unsigned char) readCorner1(numRows, numColumns);\r
+        row -= 2;\r
+        column +=2;\r
+        corner1Read = true;\r
+      } else if ((row == numRows-2) && (column == 0) && ((numColumns & 0x03) != 0) && !corner2Read) {\r
+        result[resultOffset++] = (unsigned char) readCorner2(numRows, numColumns);\r
+        row -= 2;\r
+        column +=2;\r
+        corner2Read = true;\r
+      } else if ((row == numRows+4) && (column == 2) && ((numColumns & 0x07) == 0) && !corner3Read) {\r
+        result[resultOffset++] = (unsigned char) readCorner3(numRows, numColumns);\r
+        row -= 2;\r
+        column +=2;\r
+        corner3Read = true;\r
+      } else if ((row == numRows-2) && (column == 0) && ((numColumns & 0x07) == 4) && !corner4Read) {\r
+        result[resultOffset++] = (unsigned char) readCorner4(numRows, numColumns);\r
+        row -= 2;\r
+        column +=2;\r
+        corner4Read = true;\r
+      } else {\r
+        // Sweep upward diagonally to the right\r
+        do {\r
+          if ((row < numRows) && (column >= 0) && !readBitMatrix_->get(column, row)) {\r
+            result[resultOffset++] = (unsigned char) readUtah(row, column, numRows, numColumns);\r
+          }\r
+          row -= 2;\r
+          column +=2;\r
+        } while ((row >= 0) && (column < numColumns));\r
+        row += 1;\r
+        column +=3;\r
+        \r
+        // Sweep downward diagonally to the left\r
+        do {\r
+          if ((row >= 0) && (column < numColumns) && !readBitMatrix_->get(column, row)) {\r
+             result[resultOffset++] = (unsigned char) readUtah(row, column, numRows, numColumns);\r
+          }\r
+          row += 2;\r
+          column -=2;\r
+        } while ((row < numRows) && (column >= 0));\r
+        row += 3;\r
+        column +=1;\r
+      }\r
+    } while ((row < numRows) || (column < numColumns));\r
+\r
+    if (resultOffset != parsedVersion_->getTotalCodewords()) {\r
+      throw ReaderException("Did not read all codewords");\r
+    }\r
+    return result;
+}\r
+  
+bool BitMatrixParser::readModule(int row, int column, int numRows, int numColumns) {\r
+    // Adjust the row and column indices based on boundary 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
+    readBitMatrix_->set(column, row);\r
+    return bitMatrix_->get(column, row);\r
+  }\r
+  \r
+int BitMatrixParser::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
+int BitMatrixParser::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
+int BitMatrixParser::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
+int BitMatrixParser::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
+int BitMatrixParser::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
+Ref<BitMatrix> BitMatrixParser::extractDataRegion(Ref<BitMatrix> bitMatrix) {\r
+    int symbolSizeRows = parsedVersion_->getSymbolSizeRows();\r
+    int symbolSizeColumns = parsedVersion_->getSymbolSizeColumns();\r
+    \r
+    // TODO(bbrown): Make this work with rectangular codes\r
+    if ((int)bitMatrix->getDimension() != symbolSizeRows) {\r
+      throw IllegalArgumentException("Dimension of bitMarix must match the version size");\r
+    }\r
+    \r
+    int dataRegionSizeRows = parsedVersion_->getDataRegionSizeRows();\r
+    int dataRegionSizeColumns = parsedVersion_->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
+    Ref<BitMatrix> bitMatrixWithoutAlignment(new BitMatrix(sizeDataRegionRow));\r
+    for (int dataRegionRow = 0; dataRegionRow < numDataRegionsRow; ++dataRegionRow) {\r
+      int dataRegionRowOffset = dataRegionRow * dataRegionSizeRows;\r
+      for (int dataRegionColumn = 0; dataRegionColumn < numDataRegionsColumn; ++dataRegionColumn) {\r
+        int dataRegionColumnOffset = dataRegionColumn * dataRegionSizeColumns;\r
+        for (int i = 0; i < dataRegionSizeRows; ++i) {\r
+          int readRowOffset = dataRegionRow * (dataRegionSizeRows + 2) + 1 + i;\r
+          int writeRowOffset = dataRegionRowOffset + i;\r
+          for (int j = 0; j < dataRegionSizeColumns; ++j) {\r
+            int readColumnOffset = dataRegionColumn * (dataRegionSizeColumns + 2) + 1 + j;\r
+            if (bitMatrix->get(readColumnOffset, readRowOffset)) {\r
+              int writeColumnOffset = dataRegionColumnOffset + j;\r
+              bitMatrixWithoutAlignment->set(writeColumnOffset, writeRowOffset);\r
+            }\r
+          }\r
+        }\r
+      }\r
+    }\r
+    return bitMatrixWithoutAlignment;\r
+}
+
+}
+}
diff --git a/cpp/core/src/zxing/datamatrix/decoder/BitMatrixParser.h b/cpp/core/src/zxing/datamatrix/decoder/BitMatrixParser.h
new file mode 100644 (file)
index 0000000..92097ae
--- /dev/null
@@ -0,0 +1,59 @@
+#ifndef __BIT_MATRIX_PARSER_DM_H__
+#define __BIT_MATRIX_PARSER_DM_H__
+
+/*
+ *  BitMatrixParser.h
+ *  zxing
+ *
+ *  Created by Luiz Silva on 09/02/2010.
+ *  Copyright 2010 ZXing authors All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <zxing/ReaderException.h>
+#include <zxing/common/BitMatrix.h>
+#include <zxing/common/Counted.h>
+#include <zxing/common/Array.h>
+#include <zxing/datamatrix/Version.h>
+
+namespace zxing {
+namespace datamatrix {
+
+class BitMatrixParser : public Counted {
+private:
+  Ref<BitMatrix> bitMatrix_;
+  Ref<BitMatrix> readBitMatrix_;
+  Version *parsedVersion_;
+
+  int copyBit(size_t x, size_t y, int versionBits);
+
+public:
+  BitMatrixParser(Ref<BitMatrix> bitMatrix);
+  Version *readVersion(Ref<BitMatrix> bitMatrix);
+  ArrayRef<unsigned char> readCodewords();
+  bool readModule(int row, int column, int numRows, int numColumns);
+
+private:\r
+  int readUtah(int row, int column, int numRows, int numColumns);\r
+  int readCorner1(int numRows, int numColumns);\r
+  int readCorner2(int numRows, int numColumns);\r
+  int readCorner3(int numRows, int numColumns);
+  int readCorner4(int numRows, int numColumns);\r
+  Ref<BitMatrix> extractDataRegion(Ref<BitMatrix> bitMatrix);
+};
+
+}
+}
+
+#endif // __BIT_MATRIX_PARSER_DM_H__
diff --git a/cpp/core/src/zxing/datamatrix/decoder/DataBlock.cpp b/cpp/core/src/zxing/datamatrix/decoder/DataBlock.cpp
new file mode 100644 (file)
index 0000000..c87d5f3
--- /dev/null
@@ -0,0 +1,113 @@
+/*
+ *  DataBlock.cpp
+ *  zxing
+ *
+ *  Created by Luiz Silva on 09/02/2010.
+ *  Copyright 2010 ZXing authors All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <zxing/datamatrix/decoder/DataBlock.h>
+#include <zxing/common/IllegalArgumentException.h>
+
+namespace zxing {
+namespace datamatrix {
+
+using namespace std;
+
+DataBlock::DataBlock(int numDataCodewords, ArrayRef<unsigned char> codewords) :
+    numDataCodewords_(numDataCodewords), codewords_(codewords) {
+}
+
+int DataBlock::getNumDataCodewords() {
+  return numDataCodewords_;
+}
+
+ArrayRef<unsigned char> DataBlock::getCodewords() {
+  return codewords_;
+}
+
+std::vector<Ref<DataBlock> > DataBlock::getDataBlocks(ArrayRef<unsigned char> rawCodewords, Version *version) {
+  // Figure out the number and size of data blocks used by this version and
+  // error correction level
+  ECBlocks* ecBlocks = version->getECBlocks();
+
+  // First count the total number of data blocks
+  int totalBlocks = 0;
+  vector<ECB*> ecBlockArray = ecBlocks->getECBlocks();
+  for (size_t i = 0; i < ecBlockArray.size(); i++) {
+    totalBlocks += ecBlockArray[i]->getCount();
+  }
+
+  // Now establish DataBlocks of the appropriate size and number of data codewords
+  std::vector<Ref<DataBlock> > result(totalBlocks);
+  int numResultBlocks = 0;
+  for (size_t j = 0; j < ecBlockArray.size(); j++) {
+    ECB *ecBlock = ecBlockArray[j];
+    for (int i = 0; i < ecBlock->getCount(); i++) {
+      int numDataCodewords = ecBlock->getDataCodewords();
+      int numBlockCodewords = ecBlocks->getECCodewords() + numDataCodewords;
+      ArrayRef<unsigned char> buffer(numBlockCodewords);
+      Ref<DataBlock> blockRef(new DataBlock(numDataCodewords, buffer));
+      result[numResultBlocks++] = blockRef;
+    }
+  }
+
+  // All blocks have the same amount of data, except that the last n
+  // (where n may be 0) have 1 more byte. Figure out where these start.
+  int shorterBlocksTotalCodewords = result[0]->codewords_.size();
+  int longerBlocksStartAt = result.size() - 1;
+  while (longerBlocksStartAt >= 0) {
+    int numCodewords = result[longerBlocksStartAt]->codewords_.size();
+    if (numCodewords == shorterBlocksTotalCodewords) {
+      break;
+    }
+    if (numCodewords != shorterBlocksTotalCodewords + 1) {
+      throw IllegalArgumentException("Data block sizes differ by more than 1");
+    }
+    longerBlocksStartAt--;
+  }
+  longerBlocksStartAt++;
+
+  int shorterBlocksNumDataCodewords = shorterBlocksTotalCodewords - ecBlocks->getECCodewords();
+  // The last elements of result may be 1 element longer;
+  // first fill out as many elements as all of them have
+  int rawCodewordsOffset = 0;
+  for (int i = 0; i < shorterBlocksNumDataCodewords; i++) {
+    for (int j = 0; j < numResultBlocks; j++) {
+      result[j]->codewords_[i] = rawCodewords[rawCodewordsOffset++];
+    }
+  }
+  // Fill out the last data block in the longer ones
+  for (int j = longerBlocksStartAt; j < numResultBlocks; j++) {
+    result[j]->codewords_[shorterBlocksNumDataCodewords] = rawCodewords[rawCodewordsOffset++];
+  }
+  // Now add in error correction blocks
+  int max = result[0]->codewords_.size();
+  for (int i = shorterBlocksNumDataCodewords; i < max; i++) {
+    for (int j = 0; j < numResultBlocks; j++) {
+      int iOffset = j < longerBlocksStartAt ? i : i + 1;
+      result[j]->codewords_[iOffset] = rawCodewords[rawCodewordsOffset++];
+    }
+  }
+
+  if ((size_t)rawCodewordsOffset != rawCodewords.size()) {
+    throw IllegalArgumentException("rawCodewordsOffset != rawCodewords.length");
+  }
+
+  return result;
+}
+
+}
+}
diff --git a/cpp/core/src/zxing/datamatrix/decoder/DataBlock.h b/cpp/core/src/zxing/datamatrix/decoder/DataBlock.h
new file mode 100644 (file)
index 0000000..69c1210
--- /dev/null
@@ -0,0 +1,50 @@
+#ifndef __DATA_BLOCK_DM_H__
+#define __DATA_BLOCK_DM_H__
+
+/*
+ *  DataBlock.h
+ *  zxing
+ *
+ *  Created by Luiz Silva on 09/02/2010.
+ *  Copyright 2010 ZXing authors All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <valarray>
+#include <vector>
+#include <zxing/common/Counted.h>
+#include <zxing/common/Array.h>
+#include <zxing/datamatrix/Version.h>
+
+namespace zxing {
+namespace datamatrix {
+
+class DataBlock : public Counted {
+private:
+  int numDataCodewords_;
+  ArrayRef<unsigned char> codewords_;
+
+  DataBlock(int numDataCodewords, ArrayRef<unsigned char> codewords);
+
+public:  
+  static std::vector<Ref<DataBlock> > getDataBlocks(ArrayRef<unsigned char> rawCodewords, Version *version);
+
+  int getNumDataCodewords();
+  ArrayRef<unsigned char> getCodewords();
+};
+
+}
+}
+
+#endif // __DATA_BLOCK_DM_H__
diff --git a/cpp/core/src/zxing/datamatrix/decoder/DecodedBitStreamParser.cpp b/cpp/core/src/zxing/datamatrix/decoder/DecodedBitStreamParser.cpp
new file mode 100644 (file)
index 0000000..9aa2f68
--- /dev/null
@@ -0,0 +1,404 @@
+/*
+ *  DecodedBitStreamParser.cpp
+ *  zxing
+ *
+ *  Created by Luiz Silva on 09/02/2010.
+ *  Copyright 2010 ZXing authors All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <zxing/ReaderException.h>
+#include <zxing/datamatrix/decoder/DecodedBitStreamParser.h>
+#include <iostream>
+
+namespace zxing {
+namespace datamatrix {
+
+using namespace std;
+
+const char DecodedBitStreamParser::C40_BASIC_SET_CHARS[] = {
+      '*', '*', '*', ' ', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
+      'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
+      'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'
+  };
+  
+const char DecodedBitStreamParser::C40_SHIFT2_SET_CHARS[] = {
+    '!', '"', '#', '$', '%', '&', '\'', '(', ')', '*', '+', ',', '-', '.',
+    '/', ':', ';', '<', '=', '>', '?', '@', '[', '\\', ']', '^', '_'
+};
+  
+const char DecodedBitStreamParser::TEXT_BASIC_SET_CHARS[] = {
+    '*', '*', '*', ' ', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
+    'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
+    'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'
+  };
+  
+const char DecodedBitStreamParser::TEXT_SHIFT3_SET_CHARS[] = {
+    '\'', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
+    'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '{', '|', '}', '~', (char) 127
+};
+
+std::string DecodedBitStreamParser::decode(ArrayRef<unsigned char> bytes) {
+    Ref<BitSource> bits(new BitSource(bytes));
+    ostringstream result;
+    ostringstream resultTrailer;
+//     bool trailer = false;
+    int mode = ASCII_ENCODE;
+    do {
+      if (mode == ASCII_ENCODE) {
+        mode = decodeAsciiSegment(bits, result, resultTrailer);
+      } else {
+        switch (mode) {
+          case C40_ENCODE:
+            decodeC40Segment(bits, result);
+            break;
+          case TEXT_ENCODE:
+            decodeTextSegment(bits, result);
+            break;
+          case ANSIX12_ENCODE:
+            decodeAnsiX12Segment(bits, result);
+            break;
+          case EDIFACT_ENCODE:
+            decodeEdifactSegment(bits, result);
+            break;
+          case BASE256_ENCODE:
+            decodeBase256Segment(bits, result);
+            break;
+          default:
+            throw ReaderException("Unsupported mode indicator");
+        }
+        mode = ASCII_ENCODE;
+      }
+    } while (mode != PAD_ENCODE && bits->available() > 0);
+/*    if (trailer) {
+      result << resultTrailer;
+    }
+*/     
+    return result.str();
+}
+  
+int DecodedBitStreamParser::decodeAsciiSegment(Ref<BitSource> bits, ostringstream & result,
+               ostringstream & resultTrailer) {
+    bool upperShift = false;
+    do {
+      int oneByte = bits->readBits(8);
+      if (oneByte == 0) {
+               throw ReaderException("Not enough bits to decode");
+           } else if (oneByte <= 128) {  // ASCII data (ASCII value + 1)
+               oneByte = upperShift ? (oneByte + 128) : oneByte;
+               upperShift = false;
+                       result << (char) (oneByte - 1);
+               return ASCII_ENCODE;
+           } else if (oneByte == 129) {  // Pad
+               return PAD_ENCODE;
+           } else if (oneByte <= 229) {  // 2-digit data 00-99 (Numeric Value + 130)
+             int value = oneByte - 130;
+             if (value < 10) { // padd with '0' for single digit values
+                       result << '0';
+                 }
+                 result << value;
+           } else if (oneByte == 230) {  // Latch to C40 encodation
+               return C40_ENCODE;
+           } else if (oneByte == 231) {  // Latch to Base 256 encodation
+               return BASE256_ENCODE;
+           } else if (oneByte == 232) {  // FNC1
+               //throw ReaderException.getInstance();
+        // Ignore this symbol for now
+           } else if (oneByte == 233) {  // Structured Append
+               //throw ReaderException.getInstance();
+        // Ignore this symbol for now
+           } else if (oneByte == 234) {  // Reader Programming
+               //throw ReaderException.getInstance();
+        // Ignore this symbol for now
+           } else if (oneByte == 235) {  // Upper Shift (shift to Extended ASCII)
+               upperShift = true;
+           } else if (oneByte == 236) {  // 05 Macro
+       /*              trailer = false;
+               result << "[)>\u001E05\u001D";
+               resultTrailer << "\u001E\u0004";
+        // Ignore this symbol for now
+      */       } else if (oneByte == 237) {  // 06 Macro
+       /*              trailer = false;
+               result << "[)>\u001E06\u001D";
+               resultTrailer <<  "\u001E\u0004";
+        // Ignore this symbol for now
+        */   } else if (oneByte == 238) {  // Latch to ANSI X12 encodation
+               return ANSIX12_ENCODE;
+           } else if (oneByte == 239) {  // Latch to Text encodation
+               return TEXT_ENCODE;
+           } else if (oneByte == 240) {  // Latch to EDIFACT encodation
+               return EDIFACT_ENCODE;
+           } else if (oneByte == 241) {  // ECI Character
+               // TODO(bbrown): I think we need to support ECI
+               //throw ReaderException.getInstance();
+        // Ignore this symbol for now
+           } else if (oneByte >= 242) {  // Not to be used in ASCII encodation
+               throw ReaderException("Not to be used in ASCII encodation");
+           }
+    } while (bits->available() > 0);
+    return ASCII_ENCODE;
+}
+
+void DecodedBitStreamParser::decodeC40Segment(Ref<BitSource> bits, ostringstream & result) {
+    // Three C40 values are encoded in a 16-bit value as
+    // (1600 * C1) + (40 * C2) + C3 + 1
+    // TODO(bbrown): The Upper Shift with C40 doesn't work in the 4 value scenario all the time
+    bool upperShift = false;
+
+    int* cValues = new int[3];
+    do {
+      // If there is only one byte left then it will be encoded as ASCII
+      if (bits->available() == 8) {
+        return;
+      }
+      int firstByte = bits->readBits(8);
+      if (firstByte == 254) {  // Unlatch codeword
+        return;
+      }
+
+      parseTwoBytes(firstByte, bits->readBits(8), cValues);
+
+      int shift = 0;
+      for (int i = 0; i < 3; i++) {
+        int cValue = cValues[i];
+        switch (shift) {
+          case 0:
+            if (cValue < 3) {
+              shift = cValue + 1;
+            } else {
+              if (upperShift) {
+                result << (char) (C40_BASIC_SET_CHARS[cValue] + 128);
+                upperShift = false;
+              } else {
+                result << C40_BASIC_SET_CHARS[cValue];
+              }
+            }
+            break;
+          case 1:
+            if (upperShift) {
+              result << cValue + 128;
+              upperShift = false;
+            } else {
+              result << cValue;
+            }
+            shift = 0;
+            break;
+          case 2:
+            if (cValue < 27) {
+              if (upperShift) {
+                result << (char) (C40_SHIFT2_SET_CHARS[cValue] + 128);
+                upperShift = false;
+              } else {
+                result << C40_SHIFT2_SET_CHARS[cValue];
+              }
+            } else if (cValue == 27) {  // FNC1
+              throw ReaderException("FNC1");
+            } else if (cValue == 30) {  // Upper Shift
+              upperShift = true;
+            } else {
+              throw ReaderException("Upper Shift");
+            }
+            shift = 0;
+            break;
+          case 3:
+            if (upperShift) {
+              result << (char) (cValue + 224);
+              upperShift = false;
+            } else {
+              result << (char) (cValue + 96);
+            }
+            shift = 0;
+            break;
+          default:
+            throw ReaderException("");
+        }
+      }
+    } while (bits->available() > 0);
+}
+  
+void DecodedBitStreamParser::decodeTextSegment(Ref<BitSource> bits, ostringstream & result) {
+    // Three Text values are encoded in a 16-bit value as
+    // (1600 * C1) + (40 * C2) + C3 + 1
+    // TODO(bbrown): The Upper Shift with Text doesn't work in the 4 value scenario all the time
+    bool upperShift = false;
+
+    int* cValues = new int[3];
+    do {
+      // If there is only one byte left then it will be encoded as ASCII
+      if (bits->available() == 8) {
+        return;
+      }
+      int firstByte = bits->readBits(8);
+      if (firstByte == 254) {  // Unlatch codeword
+        return;
+      }
+
+      parseTwoBytes(firstByte, bits->readBits(8), cValues);
+
+      int shift = 0;
+      for (int i = 0; i < 3; i++) {
+        int cValue = cValues[i];
+        switch (shift) {
+          case 0:
+            if (cValue < 3) {
+              shift = cValue + 1;
+            } else {
+              if (upperShift) {
+                result << (char) (TEXT_BASIC_SET_CHARS[cValue] + 128);
+                upperShift = false;
+              } else {
+                result << (TEXT_BASIC_SET_CHARS[cValue]);
+              }
+            }
+            break;
+          case 1:
+            if (upperShift) {
+              result << (char) (cValue + 128);
+              upperShift = false;
+            } else {
+              result << (cValue);
+            }
+            shift = 0;
+            break;
+          case 2:
+            // Shift 2 for Text is the same encoding as C40
+            if (cValue < 27) {
+              if (upperShift) {
+                result << (char) (C40_SHIFT2_SET_CHARS[cValue] + 128);
+                upperShift = false;
+              } else {
+                result << (C40_SHIFT2_SET_CHARS[cValue]);
+              }
+            } else if (cValue == 27) {  // FNC1
+              throw ReaderException("FNC1");
+            } else if (cValue == 30) {  // Upper Shift
+              upperShift = true;
+            } else {
+              throw ReaderException("Upper Shift");
+            }
+            shift = 0;
+            break;
+          case 3:
+            if (upperShift) {
+              result << (char) (TEXT_SHIFT3_SET_CHARS[cValue] + 128);
+              upperShift = false;
+            } else {
+              result << (TEXT_SHIFT3_SET_CHARS[cValue]);
+            }
+            shift = 0;
+            break;
+          default:
+            throw ReaderException("");
+        }
+      }
+    } while (bits->available() > 0);
+}
+  
+void DecodedBitStreamParser::decodeAnsiX12Segment(Ref<BitSource> bits, ostringstream & result) {
+    // Three ANSI X12 values are encoded in a 16-bit value as
+    // (1600 * C1) + (40 * C2) + C3 + 1
+
+    int* cValues = new int[3];
+    do {
+      // If there is only one byte left then it will be encoded as ASCII
+      if (bits->available() == 8) {
+        return;
+      }
+      int firstByte = bits->readBits(8);
+      if (firstByte == 254) {  // Unlatch codeword
+        return;
+      }
+
+      parseTwoBytes(firstByte, bits->readBits(8), cValues);
+
+      for (int i = 0; i < 3; i++) {
+        int cValue = cValues[i];
+        if (cValue == 0) {  // X12 segment terminator <CR>
+          result << '\r';
+        } else if (cValue == 1) {  // X12 segment separator *
+          result << '*';
+        } else if (cValue == 2) {  // X12 sub-element separator >
+          result << '>';
+        } else if (cValue == 3) {  // space
+          result << ' ';
+        } else if (cValue < 14) {  // 0 - 9
+          result << (char) (cValue + 44);
+        } else if (cValue < 40) {  // A - Z
+          result << (char) (cValue + 51);
+        } else {
+          throw ReaderException("");
+        }
+      }
+    } while (bits->available() > 0);
+}
+
+void DecodedBitStreamParser::parseTwoBytes(int firstByte, int secondByte, int*& result) {
+    int fullBitValue = (firstByte << 8) + secondByte - 1;
+    int temp = fullBitValue / 1600;
+    result[0] = temp;
+    fullBitValue -= temp * 1600;
+    temp = fullBitValue / 40;
+    result[1] = temp;
+    result[2] = fullBitValue - temp * 40;
+}
+  
+void DecodedBitStreamParser::decodeEdifactSegment(Ref<BitSource> bits, ostringstream & result) {
+    bool unlatch = false;
+    do {
+      // If there is only two or less bytes left then it will be encoded as ASCII
+      if (bits->available() <= 16) {
+        return;
+      }
+
+      for (int i = 0; i < 4; i++) {
+        int edifactValue = bits->readBits(6);
+
+        // Check for the unlatch character
+        if (edifactValue == 0x2B67) {  // 011111
+          unlatch = true;
+          // If we encounter the unlatch code then continue reading because the Codeword triple
+          // is padded with 0's
+        }
+        
+        if (!unlatch) {
+          if ((edifactValue & 32) == 0) {  // no 1 in the leading (6th) bit
+            edifactValue |= 64;  // Add a leading 01 to the 6 bit binary value
+          }
+          result << (edifactValue);
+        }
+      }
+    } while (!unlatch && bits->available() > 0);
+}
+  
+void DecodedBitStreamParser::decodeBase256Segment(Ref<BitSource> bits, ostringstream & result){//, vector<unsigned char> byteSegments) 
+    // Figure out how long the Base 256 Segment is.
+    int d1 = bits->readBits(8);
+    int count;
+    if (d1 == 0) {  // Read the remainder of the symbol
+      count = bits->available() / 8;
+    } else if (d1 < 250) {
+      count = d1;
+    } else {
+      count = 250 * (d1 - 249) + bits->readBits(8);
+    }
+    unsigned char* bytes = new unsigned char[count];
+    for (int i = 0; i < count; i++) {
+      bytes[i] = unrandomize255State(bits->readBits(8), i);
+    }
+    //byteSegments.push_back(bytes);
+       result << bytes;
+}
+}
+}
+
diff --git a/cpp/core/src/zxing/datamatrix/decoder/DecodedBitStreamParser.h b/cpp/core/src/zxing/datamatrix/decoder/DecodedBitStreamParser.h
new file mode 100644 (file)
index 0000000..6a0b260
--- /dev/null
@@ -0,0 +1,103 @@
+#ifndef __DECODED_BIT_STREAM_PARSER_DM_H__
+#define __DECODED_BIT_STREAM_PARSER_DM_H__
+
+/*
+ *  DecodedBitStreamParser.h
+ *  zxing
+ *
+ *  Created by Luiz Silva on 09/02/2010.
+ *  Copyright 2010 ZXing authors All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <string>
+#include <sstream>
+#include <zxing/common/BitSource.h>
+#include <zxing/common/Counted.h>
+#include <zxing/common/Array.h>
+
+
+namespace zxing {
+namespace datamatrix {
+
+class DecodedBitStreamParser {
+private:
+  static const int PAD_ENCODE = 0;  // Not really an encoding
+  static const int ASCII_ENCODE = 1;
+  static const int C40_ENCODE = 2;
+  static const int TEXT_ENCODE = 3;
+  static const int ANSIX12_ENCODE = 4;
+  static const int EDIFACT_ENCODE = 5;
+  static const int BASE256_ENCODE = 6;
+    
+  /**
+   * See ISO 16022:2006, Annex C Table C.1
+   * The C40 Basic Character Set (*'s used for placeholders for the shift values)
+   */
+  static const char C40_BASIC_SET_CHARS[];
+  
+  static const char C40_SHIFT2_SET_CHARS[];  
+  /**
+   * See ISO 16022:2006, Annex C Table C.2
+   * The Text Basic Character Set (*'s used for placeholders for the shift values)
+   */
+  static const char TEXT_BASIC_SET_CHARS[];
+  
+  static const char TEXT_SHIFT3_SET_CHARS[];  
+  /**
+   * See ISO 16022:2006, 5.2.3 and Annex C, Table C.2
+   */
+  int decodeAsciiSegment(Ref<BitSource> bits, std::ostringstream &result, std::ostringstream &resultTrailer);
+  /**
+   * See ISO 16022:2006, 5.2.5 and Annex C, Table C.1
+   */
+  void decodeC40Segment(Ref<BitSource> bits, std::ostringstream &result);
+  /**
+   * See ISO 16022:2006, 5.2.6 and Annex C, Table C.2
+   */
+  void decodeTextSegment(Ref<BitSource> bits, std::ostringstream &result);
+  /**
+   * See ISO 16022:2006, 5.2.7
+   */
+  void decodeAnsiX12Segment(Ref<BitSource> bits, std::ostringstream &result);
+  /**
+   * See ISO 16022:2006, 5.2.8 and Annex C Table C.3
+   */
+  void decodeEdifactSegment(Ref<BitSource> bits, std::ostringstream &result);
+  /**
+   * See ISO 16022:2006, 5.2.9 and Annex B, B.2
+   */
+  void decodeBase256Segment(Ref<BitSource> bits, std::ostringstream &result);//,std::vector<unsigned char> byteSegments);
+
+  void parseTwoBytes(int firstByte, int secondByte, int*& result);
+  /**
+   * See ISO 16022:2006, Annex B, B.2
+   */
+  unsigned char unrandomize255State(int randomizedBase256Codeword,
+                                          int base256CodewordPosition) {
+    int pseudoRandomNumber = ((149 * base256CodewordPosition) % 255) + 1;
+    int tempVariable = randomizedBase256Codeword - pseudoRandomNumber;
+    return (unsigned char) (tempVariable >= 0 ? tempVariable : (tempVariable + 256));
+  };
+  void append(std::ostream &ost, const unsigned char *bufIn, size_t nIn, const char *src);
+
+public:
+  DecodedBitStreamParser() { };
+  std::string decode(ArrayRef<unsigned char> bytes);
+};
+
+}
+}
+
+#endif // __DECODED_BIT_STREAM_PARSER_DM_H__
diff --git a/cpp/core/src/zxing/datamatrix/decoder/Decoder.cpp b/cpp/core/src/zxing/datamatrix/decoder/Decoder.cpp
new file mode 100644 (file)
index 0000000..72172dc
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ *  Decoder.cpp
+ *  zxing
+ *
+ *  Created by Luiz Silva on 09/02/2010.
+ *  Copyright 2010 ZXing authors All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <zxing/datamatrix/decoder/Decoder.h>
+#include <zxing/datamatrix/decoder/BitMatrixParser.h>
+#include <zxing/datamatrix/decoder/DataBlock.h>
+#include <zxing/datamatrix/decoder/DecodedBitStreamParser.h>
+#include <zxing/datamatrix/Version.h>
+#include <zxing/ReaderException.h>
+#include <zxing/common/reedsolomon/ReedSolomonException.h>
+
+namespace zxing {
+namespace datamatrix {
+
+using namespace std;
+
+Decoder::Decoder() :
+    rsDecoder_(GF256::DATA_MATRIX_FIELD) {
+}
+\r
+
+void Decoder::correctErrors(ArrayRef<unsigned char> codewordBytes, int numDataCodewords) {
+  int numCodewords = codewordBytes->size();
+  ArrayRef<int> codewordInts(numCodewords);
+  for (int i = 0; i < numCodewords; i++) {
+    codewordInts[i] = codewordBytes[i] & 0xff;
+  }
+  int numECCodewords = numCodewords - numDataCodewords;
+
+  try {
+    rsDecoder_.decode(codewordInts, numECCodewords);
+  } catch (ReedSolomonException ex) {
+    ReaderException rex(ex.what());
+    throw rex;
+  }
+
+  for (int i = 0; i < numDataCodewords; i++) {
+    codewordBytes[i] = (unsigned char)codewordInts[i];
+  }
+}
+
+Ref<DecoderResult> Decoder::decode(Ref<BitMatrix> bits) {\r
+    // Construct a parser and read version, error-correction level\r
+    BitMatrixParser parser(bits);\r
+    Version *version = parser.readVersion(bits);\r
+\r
+    // Read codewords\r
+    ArrayRef<unsigned char> codewords(parser.readCodewords());\r
+    // Separate into data blocks\r
+    std::vector<Ref<DataBlock> > dataBlocks = DataBlock::getDataBlocks(codewords, version);\r
+\r
+    // Count total number of data bytes\r
+    int totalBytes = 0;\r
+    for (unsigned int i = 0; i < dataBlocks.size(); i++) {\r
+      totalBytes += dataBlocks[i]->getNumDataCodewords();\r
+    }\r
+    ArrayRef<unsigned char> resultBytes(totalBytes);\r
+    int resultOffset = 0;\r
+\r
+    // Error-correct and copy data blocks together into a stream of bytes\r
+    for (unsigned int j = 0; j < dataBlocks.size(); j++) {\r
+      Ref<DataBlock> dataBlock(dataBlocks[j]);\r
+      ArrayRef<unsigned char> codewordBytes = dataBlock->getCodewords();\r
+      int numDataCodewords = dataBlock->getNumDataCodewords();\r
+      correctErrors(codewordBytes, numDataCodewords);\r
+      for (int i = 0; i < numDataCodewords; i++) {\r
+        resultBytes[resultOffset++] = codewordBytes[i];\r
+      }\r
+    }\r
+
+  // Decode the contents of that stream of bytes
+  DecodedBitStreamParser decodedBSParser;
+  Ref<String> text(new String(decodedBSParser.decode(resultBytes)));
+
+  Ref<DecoderResult> result(new DecoderResult(resultBytes, text));
+  return result;
+}
+}
+}
diff --git a/cpp/core/src/zxing/datamatrix/decoder/Decoder.h b/cpp/core/src/zxing/datamatrix/decoder/Decoder.h
new file mode 100644 (file)
index 0000000..b305dac
--- /dev/null
@@ -0,0 +1,51 @@
+#ifndef __DECODER_DM_H__
+#define __DECODER_DM_H__
+
+/*
+ *  Decoder.h
+ *  zxing
+ *
+ *  Created by Luiz Silva on 09/02/2010.
+ *  Copyright 2010 ZXing authors All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <zxing/common/reedsolomon/ReedSolomonDecoder.h>
+#include <zxing/common/reedsolomon/GF256.h>
+#include <zxing/common/Counted.h>
+#include <zxing/common/Array.h>
+#include <zxing/common/DecoderResult.h>
+#include <zxing/common/BitMatrix.h>
+#include <valarray>
+
+
+namespace zxing {
+namespace datamatrix {
+
+class Decoder {
+private:
+  ReedSolomonDecoder rsDecoder_;
+
+  void correctErrors(ArrayRef<unsigned char> bytes, int numDataCodewords);
+
+public:
+  Decoder();
+
+  Ref<DecoderResult> decode(Ref<BitMatrix> bits);
+};
+
+}
+}
+\r
+#endif // __DECODER_DM_H__
diff --git a/cpp/core/src/zxing/datamatrix/detector/CornerPoint.cpp b/cpp/core/src/zxing/datamatrix/detector/CornerPoint.cpp
new file mode 100644 (file)
index 0000000..00ad26d
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ *  CornerPoint.cpp
+ *  zxing
+ *
+ *  Created by Luiz Silva on 09/02/2010.
+ *  Copyright 2010 ZXing authors All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <zxing/datamatrix/detector/CornerPoint.h>
+
+
+namespace zxing {
+       namespace datamatrix {
+               
+               using namespace std;
+               
+               CornerPoint::CornerPoint(float posX, float posY) :
+               posX_(posX), posY_(posY) {
+               }
+               
+               float CornerPoint::getX() {
+                       return posX_;
+               }
+               
+               float CornerPoint::getY() {
+                       return posY_;
+               }
+               
+               int CornerPoint::getCount() {
+                       return counter_;
+               }
+                               
+               void CornerPoint::incrementCount() {
+                       counter_++;
+               }
+               
+               bool CornerPoint::equals(Ref<CornerPoint> other) {
+                       return posX_ == other->getX() && posY_ == other->getY();
+               }
+               
+       }
+}
diff --git a/cpp/core/src/zxing/datamatrix/detector/CornerPoint.h b/cpp/core/src/zxing/datamatrix/detector/CornerPoint.h
new file mode 100644 (file)
index 0000000..06ef879
--- /dev/null
@@ -0,0 +1,47 @@
+#ifndef __CORNER_FINDER_H__
+#define __CORNER_FINDER_H__
+
+/*
+ *  CornerPoint.h
+ *  zxing
+ *
+ *  Created by Luiz Silva on 09/02/2010.
+ *  Copyright 2010 ZXing authors All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <zxing/ResultPoint.h>
+#include <cmath>
+
+namespace zxing {
+       namespace datamatrix {
+                       
+               class CornerPoint : public ResultPoint {
+               private:
+                       float posX_;
+                       float posY_;
+                       int counter_;
+                       
+               public:
+                       CornerPoint(float posX, float posY);
+                       float getX();
+                       float getY();
+                       int getCount();
+                       void incrementCount();
+                       bool equals(Ref<CornerPoint> other);
+               };
+       }
+}
+
+#endif // __CORNER_FINDER_H__
diff --git a/cpp/core/src/zxing/datamatrix/detector/Detector.cpp b/cpp/core/src/zxing/datamatrix/detector/Detector.cpp
new file mode 100644 (file)
index 0000000..bb18f0a
--- /dev/null
@@ -0,0 +1,317 @@
+/*
+ *  Detector.cpp
+ *  zxing
+ *
+ *  Created by Luiz Silva on 09/02/2010.
+ *  Copyright 2010 ZXing authors All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <zxing/common/GridSampler.h>
+#include <zxing/datamatrix/detector/Detector.h>\r
+#include <cmath>\r
+#include <sstream>
+\r
+namespace zxing {\r
+namespace datamatrix {\r
+\r
+using namespace std;
+
+ResultPointsAndTransitions::ResultPointsAndTransitions() { 
+       Ref<CornerPoint> ref(new CornerPoint(0,0)); 
+       from_ = ref; 
+       to_ = ref; 
+       transitions_ = 0;
+}
+
+ResultPointsAndTransitions::ResultPointsAndTransitions(Ref<CornerPoint> from, Ref<CornerPoint> to, int transitions) {
+       from_ = from; 
+       to_ = to; 
+       transitions_ = transitions;
+}
+
+Ref<CornerPoint> ResultPointsAndTransitions::getFrom() {
+      return from_;
+}
+
+Ref<CornerPoint> ResultPointsAndTransitions::getTo() {
+      return to_;
+}
+
+int ResultPointsAndTransitions::getTransitions() {
+      return transitions_;
+}
+\r
+Detector::Detector(Ref<BitMatrix> image) : image_(image) { }\r
+\r
+Ref<BitMatrix> Detector::getImage() {\r
+   return image_;\r
+}\r
+\r
+Ref<DetectorResult> Detector::detect() {
+    Ref<MonochromeRectangleDetector> rectangleDetector_(new MonochromeRectangleDetector(image_));
+    std::vector<Ref<CornerPoint> > cornerPoints = rectangleDetector_->detect();
+    Ref<CornerPoint> pointA = cornerPoints[0];
+    Ref<CornerPoint> pointB = cornerPoints[1];
+    Ref<CornerPoint> pointC = cornerPoints[2];
+    Ref<CornerPoint> pointD = cornerPoints[3];
+
+    // Point A and D are across the diagonal from one another,
+    // as are B and C. Figure out which are the solid black lines
+    // by counting transitions    
+       std::vector<Ref<ResultPointsAndTransitions> > transitions(4);\r
+       transitions[0].reset(transitionsBetween(pointA, pointB));\r
+       transitions[1].reset(transitionsBetween(pointA, pointC));\r
+       transitions[2].reset(transitionsBetween(pointB, pointD));\r
+       transitions[3].reset(transitionsBetween(pointC, pointD));
+    insertionSort(transitions);
+
+    // Sort by number of transitions. First two will be the two solid sides; last two
+    // will be the two alternating black/white sides
+    Ref<ResultPointsAndTransitions> lSideOne(transitions[0]);
+    Ref<ResultPointsAndTransitions> lSideTwo(transitions[1]);
+
+    // Figure out which point is their intersection by tallying up the number of times we see the
+    // endpoints in the four endpoints. One will show up twice.
+    Ref<CornerPoint> maybeTopLeft;
+    Ref<CornerPoint> bottomLeft;
+    Ref<CornerPoint> maybeBottomRight;
+       if (lSideOne->getFrom()->equals(lSideOne->getTo())) {
+               bottomLeft = lSideOne->getFrom(); 
+               maybeTopLeft = lSideTwo->getFrom();
+               maybeBottomRight = lSideTwo->getTo();
+       }
+       else if (lSideOne->getFrom()->equals(lSideTwo->getFrom())) {
+               bottomLeft = lSideOne->getFrom(); 
+               maybeTopLeft = lSideOne->getTo();
+               maybeBottomRight = lSideTwo->getTo();
+       } 
+       else if (lSideOne->getFrom()->equals(lSideTwo->getTo())) {
+               bottomLeft = lSideOne->getFrom(); 
+               maybeTopLeft = lSideOne->getTo();
+               maybeBottomRight = lSideTwo->getFrom();
+       } 
+       else if (lSideOne->getTo()->equals(lSideTwo->getFrom())) {
+               bottomLeft = lSideOne->getTo(); 
+               maybeTopLeft = lSideOne->getFrom();
+               maybeBottomRight = lSideTwo->getTo();
+       } 
+       else if (lSideOne->getTo()->equals(lSideTwo->getTo())) {
+               bottomLeft = lSideOne->getTo(); 
+               maybeTopLeft = lSideOne->getFrom();
+               maybeBottomRight = lSideTwo->getFrom();
+       } 
+       else {
+               bottomLeft = lSideTwo->getFrom(); 
+               maybeTopLeft = lSideOne->getTo();
+               maybeBottomRight = lSideOne->getFrom();
+       } 
+
+    // Bottom left is correct but top left and bottom right might be switched
+    std::vector<Ref<CornerPoint> > corners(3);\r
+       corners[0].reset(maybeTopLeft);\r
+       corners[1].reset(bottomLeft);\r
+       corners[2].reset(maybeBottomRight);
+    // Use the dot product trick to sort them out
+    orderBestPatterns(corners);
+
+    // Now we know which is which:
+    Ref<CornerPoint> bottomRight(corners[0]);
+    bottomLeft = corners[1];
+    Ref<CornerPoint> topLeft(corners[2]);
+
+    // Which point didn't we find in relation to the "L" sides? that's the top right corner
+    Ref<CornerPoint> topRight;
+    if (!(pointA->equals(bottomRight) || pointA->equals(bottomLeft) || pointA->equals(topLeft))) {
+      topRight = pointA;
+    } else if (!(pointB->equals(bottomRight) || pointB->equals(bottomLeft) || pointB->equals(topLeft))) {
+      topRight = pointB;
+    } else if (!(pointC->equals(bottomRight) || pointC->equals(bottomLeft) || pointC->equals(topLeft))) {
+      topRight = pointC;
+    } else {
+      topRight = pointD;
+    }
+
+       float topRightX = (bottomRight->getX() - bottomLeft->getX()) + topLeft->getX();
+  float topRightY = (bottomRight->getY() - bottomLeft->getY()) + topLeft->getY();
+       Ref<CornerPoint> topR(new CornerPoint(topRightX,topRightY));
+
+    // Next determine the dimension by tracing along the top or right side and counting black/white
+    // transitions. Since we start inside a black module, we should see a number of transitions
+    // equal to 1 less than the code dimension. Well, actually 2 less, because we are going to
+    // end on a black module:
+    // The top right point is actually the corner of a module, which is one of the two black modules
+    // adjacent to the white module at the top right. Tracing to that corner from either the top left
+    // or bottom right should work here. The number of transitions could be higher than it should be
+    // due to noise. So we try both and take the min.
+       int dimension = min(transitionsBetween(topLeft, topRight)->getTransitions(), 
+                             transitionsBetween(bottomRight, topRight)->getTransitions());
+    if ((dimension & 0x01) == 1) {
+      // it can't be odd, so, round... up?
+      dimension++;
+    }
+    dimension += 2;
+\r
+       Ref<PerspectiveTransform> transform = createTransform(topLeft, topR, bottomLeft, bottomRight, dimension);\r
+       Ref<BitMatrix> bits(sampleGrid(image_, dimension, transform));
+       std::vector<Ref<ResultPoint> > points(4);
+         points[0].reset(pointA);
+         points[1].reset(pointB);
+         points[2].reset(pointC);
+         points[3].reset(pointD);
+         Ref<DetectorResult> detectorResult(new DetectorResult(bits, points, transform));
+    return detectorResult;\r
+}\r
+
+Ref<ResultPointsAndTransitions> Detector::transitionsBetween(Ref<CornerPoint> from, Ref<CornerPoint> to) {
+    // See QR Code Detector, sizeOfBlackWhiteBlackRun()
+    int fromX = (int) from->getX();
+    int fromY = (int) from->getY();
+    int toX = (int) to->getX();
+    int toY = (int) to->getY();
+    bool steep = abs(toY - fromY) > abs(toX - fromX);
+    if (steep) {
+      int temp = fromX;
+      fromX = fromY;
+      fromY = temp;
+      temp = toX;
+      toX = toY;
+      toY = temp;
+    }
+
+    int dx = abs(toX - fromX);
+    int dy = abs(toY - fromY);
+    int error = -dx >> 1;
+    int ystep = fromY < toY ? 1 : -1;
+    int xstep = fromX < toX ? 1 : -1;
+    int transitions = 0;
+    bool inBlack = image_->get(steep ? fromY : fromX, steep ? fromX : fromY);
+    for (int x = fromX, y = fromY; x != toX; x += xstep) {
+      bool isBlack = image_->get(steep ? y : x, steep ? x : y);
+      if (isBlack != inBlack) {
+        transitions++;
+        inBlack = isBlack;
+      }
+      error += dy;
+      if (error > 0) {
+        if (y == toY) {
+          break;
+        }
+        y += ystep;
+        error -= dx;
+      }
+    }
+       Ref<ResultPointsAndTransitions> result(new ResultPointsAndTransitions(from, to, transitions));
+    return result;
+  }
+\r
+Ref<PerspectiveTransform> Detector::createTransform(Ref<ResultPoint> topLeft, Ref<ResultPoint> topRight, Ref <\r
+    ResultPoint > bottomLeft, Ref<ResultPoint> bottomRight, int dimension) {\r
+\r
+  Ref<PerspectiveTransform> transform(PerspectiveTransform::quadrilateralToQuadrilateral(
+        0.0f,
+        0.0f,
+        dimension,
+        0.0f,
+        dimension,
+        dimension,
+        0.0f,
+        dimension,
+        topLeft->getX(),
+        topLeft->getY(),
+        topRight->getX(),
+        topRight->getY(),
+        bottomRight->getX(),
+        bottomRight->getY(),
+        bottomLeft->getX(),
+        bottomLeft->getY()));\r
+  return transform;\r
+}\r
+\r
+Ref<BitMatrix> Detector::sampleGrid(Ref<BitMatrix> image, int dimension, Ref<PerspectiveTransform> transform) {\r
+  GridSampler &sampler = GridSampler::getInstance();\r
+  return sampler.sampleGrid(image, dimension, transform);\r
+}
+
+void Detector::insertionSort(std::vector<Ref<ResultPointsAndTransitions> > &vector) {
+    int max = vector.size();
+       bool swapped = true;
+       Ref<ResultPointsAndTransitions> value;
+    Ref<ResultPointsAndTransitions> valueB;
+       do {
+               swapped = false;
+           for (int i = 1; i < max; i++) {
+         value = vector[i-1];
+                 if (compare(value, (valueB = vector[i])) > 0) {
+                       swapped = true;
+                       vector[i-1].reset(valueB);
+                       vector[i].reset(value);
+                 }
+               }
+       } while (swapped);
+}
+void Detector::orderBestPatterns(std::vector<Ref<CornerPoint> > &patterns) {
+    // Find distances between pattern centers
+    float zeroOneDistance = distance(patterns[0]->getX(), patterns[1]->getX(),patterns[0]->getY(), patterns[1]->getY());
+    float oneTwoDistance = distance(patterns[1]->getX(), patterns[2]->getX(),patterns[1]->getY(), patterns[2]->getY());
+    float zeroTwoDistance = distance(patterns[0]->getX(), patterns[2]->getX(),patterns[0]->getY(), patterns[2]->getY());
+
+    Ref<CornerPoint> pointA, pointB, pointC;
+    // Assume one closest to other two is B; A and C will just be guesses at first
+    if (oneTwoDistance >= zeroOneDistance && oneTwoDistance >= zeroTwoDistance) {
+      pointB = patterns[0];
+      pointA = patterns[1];
+      pointC = patterns[2];
+    } else if (zeroTwoDistance >= oneTwoDistance && zeroTwoDistance >= zeroOneDistance) {
+      pointB = patterns[1];
+      pointA = patterns[0];
+      pointC = patterns[2];
+    } else {
+      pointB = patterns[2];
+      pointA = patterns[0];
+      pointC = patterns[1];
+    }
+
+    // Use cross product to figure out whether A and C are correct or flipped.
+    // This asks whether BC x BA has a positive z component, which is the arrangement
+    // we want for A, B, C. If it's negative, then we've got it flipped around and
+    // should swap A and C.
+    if (crossProductZ(pointA, pointB, pointC) < 0.0f) {
+      Ref<CornerPoint> temp = pointA;
+      pointA = pointC;
+      pointC = temp;
+    }
+
+    patterns[0] = pointA;
+    patterns[1] = pointB;
+    patterns[2] = pointC; 
+}
+
+float Detector::distance(float x1, float x2, float y1, float y2) {
+    float xDiff = x1 - x2;
+    float yDiff = y1 - y2;
+    return (float) sqrt((double) (xDiff * xDiff + yDiff * yDiff));
+  }
+
+int Detector::compare(Ref<ResultPointsAndTransitions> a, Ref<ResultPointsAndTransitions> b) {
+      return a->getTransitions() - b->getTransitions();
+    }
+
+float Detector::crossProductZ(Ref<ResultPoint> pointA, Ref<ResultPoint> pointB, Ref<ResultPoint> pointC) {
+    float bX = pointB->getX();
+    float bY = pointB->getY();
+    return ((pointC->getX() - bX) * (pointA->getY() - bY)) - ((pointC->getY() - bY) * (pointA->getX() - bX));
+  }
+}
+}
diff --git a/cpp/core/src/zxing/datamatrix/detector/Detector.h b/cpp/core/src/zxing/datamatrix/detector/Detector.h
new file mode 100644 (file)
index 0000000..96f58f5
--- /dev/null
@@ -0,0 +1,79 @@
+#ifndef __DETECTOR_H__
+#define __DETECTOR_H__
+
+/*
+ *  Detector.h
+ *  zxing
+ *
+ *  Created by Luiz Silva on 09/02/2010.
+ *  Copyright 2010 ZXing authors All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+\r
+#include <zxing/common/Counted.h>\r
+#include <zxing/common/DetectorResult.h>\r
+#include <zxing/common/BitMatrix.h>\r
+#include <zxing/common/PerspectiveTransform.h>\r
+#include <zxing/datamatrix/detector/MonochromeRectangleDetector.h>
+\r
+\r
+namespace zxing {\r
+namespace datamatrix {
+\r
+class ResultPointsAndTransitions : public Counted {
+private:
+  Ref<CornerPoint> to_;
+  Ref<CornerPoint> from_;
+  int transitions_;
+
+public:
+  ResultPointsAndTransitions();
+  ResultPointsAndTransitions(Ref<CornerPoint> from, Ref<CornerPoint> to, int transitions);
+  Ref<CornerPoint> getFrom();
+  Ref<CornerPoint> getTo();
+  int getTransitions();
+};
+\r
+class Detector : public Counted {\r
+private:\r
+  Ref<BitMatrix> image_;\r
+\r
+protected:
+  Ref<BitMatrix> sampleGrid(Ref<BitMatrix> image, int dimension, Ref<PerspectiveTransform> transform);
+
+  void insertionSort(std::vector<Ref<ResultPointsAndTransitions> >& vector);
+
+  Ref<ResultPointsAndTransitions> transitionsBetween(Ref<CornerPoint> from, Ref<CornerPoint> to);
+  int min(int a, int b) { return a > b ? b : a; };
+\r
+public:\r
+  Ref<BitMatrix> getImage();\r
+  Detector(Ref<BitMatrix> image);
+\r
+  virtual Ref<PerspectiveTransform> createTransform(Ref<ResultPoint> topLeft, Ref<ResultPoint> topRight, Ref <\r
+      ResultPoint > bottomLeft, Ref<ResultPoint> bottomRight, int dimension);
+\r
+  Ref<DetectorResult> detect();
+  void orderBestPatterns(std::vector<Ref<CornerPoint> > &patterns);
+  float distance(float x1, float x2, float y1, float y2);
+private:
+  int compare(Ref<ResultPointsAndTransitions> a, Ref<ResultPointsAndTransitions> b);
+  float crossProductZ(Ref<ResultPoint> pointA, Ref<ResultPoint> pointB, Ref<ResultPoint> pointC);
+};
+\r
+}\r
+}\r
+\r
+#endif // __DETECTOR_H__
diff --git a/cpp/core/src/zxing/datamatrix/detector/MonochromeRectangleDetector.cpp b/cpp/core/src/zxing/datamatrix/detector/MonochromeRectangleDetector.cpp
new file mode 100644 (file)
index 0000000..1a39c3e
--- /dev/null
@@ -0,0 +1,173 @@
+/*
+ *  MonochromeRectangleDetector.cpp
+ *  zxing
+ *
+ *  Created by Luiz Silva on 09/02/2010.
+ *  Copyright 2010 ZXing authors All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+\r
+#include <zxing/ReaderException.h>\r
+#include <zxing/datamatrix/detector/MonochromeRectangleDetector.h>\r
+#include <sstream>
+
+namespace zxing {
+namespace datamatrix {
+
+std::vector<Ref<CornerPoint> > MonochromeRectangleDetector::detect() {
+    int height = image_->getHeight();
+    int width = image_->getWidth();
+    int halfHeight = height >> 1;
+    int halfWidth = width >> 1;
+    int deltaY = max(1, height / (MAX_MODULES << 3));
+    int deltaX = max(1, width / (MAX_MODULES << 3));
+
+    int top = 0;
+    int bottom = height;
+    int left = 0;
+    int right = width;
+    Ref<CornerPoint> pointA(findCornerFromCenter(halfWidth, 0, left, right,
+        halfHeight, -deltaY, top, bottom, halfWidth >> 1));
+    top = (int) pointA->getY() - 1;
+    Ref<CornerPoint> pointB(findCornerFromCenter(halfWidth, -deltaX, left, right,
+        halfHeight, 0, top, bottom, halfHeight >> 1));
+    left = (int) pointB->getX() - 1;
+    Ref<CornerPoint> pointC(findCornerFromCenter(halfWidth, deltaX, left, right,
+        halfHeight, 0, top, bottom, halfHeight >> 1));
+    right = (int) pointC->getX() + 1;
+    Ref<CornerPoint> pointD(findCornerFromCenter(halfWidth, 0, left, right,
+        halfHeight, deltaY, top, bottom, halfWidth >> 1));
+    bottom = (int) pointD->getY() + 1;
+
+    // Go try to find point A again with better information -- might have been off at first.
+    pointA.reset(findCornerFromCenter(halfWidth, 0, left, right,
+        halfHeight, -deltaY, top, bottom, halfWidth >> 2));
+       std::vector<Ref<CornerPoint> > corners(4);\r
+       corners[0].reset(pointA);\r
+       corners[1].reset(pointB);\r
+       corners[2].reset(pointC);
+       corners[3].reset(pointD);
+    return corners;
+  }
+
+Ref<CornerPoint> MonochromeRectangleDetector::findCornerFromCenter(int centerX, int deltaX, int left, int right,
+      int centerY, int deltaY, int top, int bottom, int maxWhiteRun) {    
+         int* lastRange = NULL;
+    for (int y = centerY, x = centerX;
+         y < bottom && y >= top && x < right && x >= left;
+         y += deltaY, x += deltaX) {
+      int* range;
+      if (deltaX == 0) {
+        // horizontal slices, up and down
+        range = blackWhiteRange(y, maxWhiteRun, left, right, true);
+      } else {
+        // vertical slices, left and right
+        range = blackWhiteRange(x, maxWhiteRun, top, bottom, false);
+      }
+      if (range == NULL) {
+        if (lastRange == NULL) {
+                           throw ReaderException("Couldn't find corners (lastRange = NULL) ");
+        } else {
+        // lastRange was found
+        if (deltaX == 0) {
+          int lastY = y - deltaY;
+          if (lastRange[0] < centerX) {
+            if (lastRange[1] > centerX) {
+              // straddle, choose one or the other based on direction
+                               Ref<CornerPoint> result(new CornerPoint(deltaY > 0 ? lastRange[0] : lastRange[1], lastY));
+                               return result;
+            }
+                             Ref<CornerPoint> result(new CornerPoint(lastRange[0], lastY));
+                             return result;
+          } else {
+                             Ref<CornerPoint> result(new CornerPoint(lastRange[1], lastY));
+                             return result;
+            }
+        } else {
+          int lastX = x - deltaX;
+          if (lastRange[0] < centerY) {
+            if (lastRange[1] > centerY) {
+                               Ref<CornerPoint> result(new CornerPoint(lastX, deltaX < 0 ? lastRange[0] : lastRange[1]));
+                               return result;
+            }
+                             Ref<CornerPoint> result(new CornerPoint(lastX, lastRange[0]));
+                             return result;
+          } else {
+                             Ref<CornerPoint> result(new CornerPoint(lastX, lastRange[1]));
+                             return result;
+            }
+          }
+        }
+      }
+      lastRange = range;
+    }
+    throw ReaderException("Couldn't find corners");
+  }
+
+int* MonochromeRectangleDetector::blackWhiteRange(int fixedDimension, int maxWhiteRun, int minDim, int maxDim,
+      bool horizontal) {
+    
+         int center = (minDim + maxDim) >> 1;
+
+    // Scan left/up first
+    int start = center;
+    while (start >= minDim) {
+      if (horizontal ? image_->get(start, fixedDimension) : image_->get(fixedDimension, start)) {
+        start--;
+      } else {
+        int whiteRunStart = start;
+        do {
+          start--;
+        } while (start >= minDim && !(horizontal ? image_->get(start, fixedDimension) :
+            image_->get(fixedDimension, start)));
+        int whiteRunSize = whiteRunStart - start;
+        if (start < minDim || whiteRunSize > maxWhiteRun) {
+          start = whiteRunStart;
+          break;
+        }
+      }
+    }
+    start++;
+
+    // Then try right/down
+    int end = center;
+    while (end < maxDim) {
+      if (horizontal ? image_->get(end, fixedDimension) : image_->get(fixedDimension, end)) {
+        end++;
+      } else {
+        int whiteRunStart = end;
+        do {
+          end++;
+        } while (end < maxDim && !(horizontal ? image_->get(end, fixedDimension) :
+            image_->get(fixedDimension, end)));
+        int whiteRunSize = end - whiteRunStart;
+        if (end >= maxDim || whiteRunSize > maxWhiteRun) {
+          end = whiteRunStart;
+          break;
+        }
+      }
+    }
+    end--;
+    int* result;
+    if (end > start) {
+      result = new int [2];
+      result[0] = start;
+      result[1] = end;
+    }
+    else
+       result = NULL;
+         return result;
+  }
+}
+}
diff --git a/cpp/core/src/zxing/datamatrix/detector/MonochromeRectangleDetector.h b/cpp/core/src/zxing/datamatrix/detector/MonochromeRectangleDetector.h
new file mode 100644 (file)
index 0000000..a2729fe
--- /dev/null
@@ -0,0 +1,56 @@
+#ifndef __MONOCHROMERECTANGLEDETECTOR_H__
+#define __MONOCHROMERECTANGLEDETECTOR_H__
+
+/*
+ *  MonochromeRectangleDetector.h
+ *  zxing
+ *
+ *  Created by Luiz Silva on 09/02/2010.
+ *  Copyright 2010 ZXing authors All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <vector>\r
+#include <zxing/ReaderException.h>\r
+#include <zxing/ResultPoint.h>\r
+#include <zxing/common/BitMatrix.h>\r
+#include <zxing/common/Counted.h>\r
+#include <zxing/datamatrix/detector/CornerPoint.h>
+\r
+namespace zxing {
+namespace datamatrix {
+
+class MonochromeRectangleDetector : public Counted {
+private:
+  static const int MAX_MODULES = 32;
+  Ref<BitMatrix> image_;
+
+public:
+  MonochromeRectangleDetector(Ref<BitMatrix> image) : image_(image) {  };
+
+  std::vector<Ref<CornerPoint> > detect();
+
+private:
+  Ref<CornerPoint> findCornerFromCenter(int centerX, int deltaX, int left, int right,
+      int centerY, int deltaY, int top, int bottom, int maxWhiteRun);
+
+  int* blackWhiteRange(int fixedDimension, int maxWhiteRun, int minDim, int maxDim,
+      bool horizontal);
+
+  int max(int a, float b) { return (float) a > b ? a : (int) b;};
+};
+}
+}
+
+#endif // __MONOCHROMERECTANGLEDETECTOR_H__