typedef enum BarcodeFormat {
BarcodeFormat_None = 0,
BarcodeFormat_QR_CODE,
+ BarcodeFormat_DATA_MATRIX,
BarcodeFormat_UPC_E,
BarcodeFormat_UPC_A,
BarcodeFormat_EAN_8,
* 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");
#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>
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());
}
--- /dev/null
+/*
+ * 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() {
+}
+
+}
+}
--- /dev/null
+#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__
--- /dev/null
+/*
+ * 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();
+}
+}
+}
--- /dev/null
+#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__
--- /dev/null
+/*
+ * 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
+}
+
+}
+}
--- /dev/null
+#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__
--- /dev/null
+/*
+ * 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;
+}
+
+}
+}
--- /dev/null
+#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__
--- /dev/null
+/*
+ * 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;
+}
+}
+}
+
--- /dev/null
+#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__
--- /dev/null
+/*
+ * 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;
+}
+}
+}
--- /dev/null
+#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__
--- /dev/null
+/*
+ * 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();
+ }
+
+ }
+}
--- /dev/null
+#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__
--- /dev/null
+/*
+ * 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));
+ }
+}
+}
--- /dev/null
+#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__
--- /dev/null
+/*
+ * 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;
+ }
+}
+}
--- /dev/null
+#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__