mirror of
https://github.com/zxing/zxing.git
synced 2024-11-09 20:44:03 -08:00
#ADD: DataMatrix reader.
#CHANGE: MultiFormatReader can read DataMatrix. git-svn-id: https://zxing.googlecode.com/svn/trunk@1217 59b500cc-1b3d-0410-9834-0bbf25fbcc57
This commit is contained in:
parent
8090bb441a
commit
2bef6a98d5
|
@ -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,
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
|
82
cpp/core/src/zxing/datamatrix/DataMatrixReader.cpp
Normal file
82
cpp/core/src/zxing/datamatrix/DataMatrixReader.cpp
Normal file
|
@ -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() {
|
||||
}
|
||||
|
||||
}
|
||||
}
|
44
cpp/core/src/zxing/datamatrix/DataMatrixReader.h
Normal file
44
cpp/core/src/zxing/datamatrix/DataMatrixReader.h
Normal file
|
@ -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__
|
202
cpp/core/src/zxing/datamatrix/Version.cpp
Normal file
202
cpp/core/src/zxing/datamatrix/Version.cpp
Normal file
|
@ -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();
|
||||
|
||||
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) {
|
||||
// Calculate the total number of codewords
|
||||
int total = 0;
|
||||
int ecCodewords = ecBlocks_->getECCodewords();
|
||||
vector<ECB*> &ecbArray = ecBlocks_->getECBlocks();
|
||||
for (unsigned int i = 0; i < ecbArray.size(); i++) {
|
||||
ECB *ecBlock = ecbArray[i];
|
||||
total += ecBlock->getCount() * (ecBlock->getDataCodewords() + ecCodewords);
|
||||
}
|
||||
totalCodewords_ = total;
|
||||
}
|
||||
|
||||
Version::~Version() {
|
||||
delete ecBlocks_;
|
||||
}
|
||||
|
||||
int Version::getVersionNumber() {
|
||||
return versionNumber_;
|
||||
}
|
||||
|
||||
int Version::getSymbolSizeRows() {
|
||||
return symbolSizeRows_;
|
||||
}
|
||||
|
||||
int Version::getSymbolSizeColumns() {
|
||||
return symbolSizeColumns_;
|
||||
}
|
||||
|
||||
int Version::getDataRegionSizeRows() {
|
||||
return dataRegionSizeRows_;
|
||||
}
|
||||
|
||||
int Version::getDataRegionSizeColumns() {
|
||||
return dataRegionSizeColumns_;
|
||||
}
|
||||
|
||||
int Version::getTotalCodewords() {
|
||||
return totalCodewords_;
|
||||
}
|
||||
|
||||
ECBlocks* Version::getECBlocks() {
|
||||
return ecBlocks_;
|
||||
}
|
||||
|
||||
Version* Version::getVersionForDimensions(int numRows, int numColumns) {
|
||||
if ((numRows & 0x01) != 0 || (numColumns & 0x01) != 0) {
|
||||
throw ReaderException("Number of rows and columns must be even");
|
||||
}
|
||||
|
||||
// TODO(bbrown): This is doing a linear search through the array of versions.
|
||||
// If we interleave the rectangular versions with the square versions we could
|
||||
// do a binary search.
|
||||
for (int i = 0; i < N_VERSIONS; ++i){
|
||||
Version* version = VERSIONS[i];
|
||||
if (version->getSymbolSizeRows() == numRows && version->getSymbolSizeColumns() == numColumns) {
|
||||
return version;
|
||||
}
|
||||
}
|
||||
throw ReaderException("Error version not found");
|
||||
}
|
||||
|
||||
/**
|
||||
* See ISO 16022:2006 5.5.1 Table 7
|
||||
*/
|
||||
int Version::buildVersions() {
|
||||
VERSIONS.push_back(Ref<Version>(new Version(1, 10, 10, 8, 8,
|
||||
new ECBlocks(5, new ECB(1, 3)))));
|
||||
VERSIONS.push_back(Ref<Version>(new Version(2, 12, 12, 10, 10,
|
||||
new ECBlocks(7, new ECB(1, 5)))));
|
||||
VERSIONS.push_back(Ref<Version>(new Version(3, 14, 14, 12, 12,
|
||||
new ECBlocks(10, new ECB(1, 8)))));
|
||||
VERSIONS.push_back(Ref<Version>(new Version(4, 16, 16, 14, 14,
|
||||
new ECBlocks(12, new ECB(1, 12)))));
|
||||
VERSIONS.push_back(Ref<Version>(new Version(5, 18, 18, 16, 16,
|
||||
new ECBlocks(14, new ECB(1, 18)))));
|
||||
VERSIONS.push_back(Ref<Version>(new Version(6, 20, 20, 18, 18,
|
||||
new ECBlocks(18, new ECB(1, 22)))));
|
||||
VERSIONS.push_back(Ref<Version>(new Version(7, 22, 22, 20, 20,
|
||||
new ECBlocks(20, new ECB(1, 30)))));
|
||||
VERSIONS.push_back(Ref<Version>(new Version(8, 24, 24, 22, 22,
|
||||
new ECBlocks(24, new ECB(1, 36)))));
|
||||
VERSIONS.push_back(Ref<Version>(new Version(9, 26, 26, 24, 24,
|
||||
new ECBlocks(28, new ECB(1, 44)))));
|
||||
VERSIONS.push_back(Ref<Version>(new Version(10, 32, 32, 14, 14,
|
||||
new ECBlocks(36, new ECB(1, 62)))));
|
||||
VERSIONS.push_back(Ref<Version>(new Version(11, 36, 36, 16, 16,
|
||||
new ECBlocks(42, new ECB(1, 86)))));
|
||||
VERSIONS.push_back(Ref<Version>(new Version(12, 40, 40, 18, 18,
|
||||
new ECBlocks(48, new ECB(1, 114)))));
|
||||
VERSIONS.push_back(Ref<Version>(new Version(13, 44, 44, 20, 20,
|
||||
new ECBlocks(56, new ECB(1, 144)))));
|
||||
VERSIONS.push_back(Ref<Version>(new Version(14, 48, 48, 22, 22,
|
||||
new ECBlocks(68, new ECB(1, 174)))));
|
||||
VERSIONS.push_back(Ref<Version>(new Version(15, 52, 52, 24, 24,
|
||||
new ECBlocks(42, new ECB(2, 102)))));
|
||||
VERSIONS.push_back(Ref<Version>(new Version(16, 64, 64, 14, 14,
|
||||
new ECBlocks(56, new ECB(2, 140)))));
|
||||
VERSIONS.push_back(Ref<Version>(new Version(17, 72, 72, 16, 16,
|
||||
new ECBlocks(36, new ECB(4, 92)))));
|
||||
VERSIONS.push_back(Ref<Version>(new Version(18, 80, 80, 18, 18,
|
||||
new ECBlocks(48, new ECB(4, 114)))));
|
||||
VERSIONS.push_back(Ref<Version>(new Version(19, 88, 88, 20, 20,
|
||||
new ECBlocks(56, new ECB(4, 144)))));
|
||||
VERSIONS.push_back(Ref<Version>(new Version(20, 96, 96, 22, 22,
|
||||
new ECBlocks(68, new ECB(4, 174)))));
|
||||
VERSIONS.push_back(Ref<Version>(new Version(21, 104, 104, 24, 24,
|
||||
new ECBlocks(56, new ECB(6, 136)))));
|
||||
VERSIONS.push_back(Ref<Version>(new Version(22, 120, 120, 18, 18,
|
||||
new ECBlocks(68, new ECB(6, 175)))));
|
||||
VERSIONS.push_back(Ref<Version>(new Version(23, 132, 132, 20, 20,
|
||||
new ECBlocks(62, new ECB(8, 163)))));
|
||||
VERSIONS.push_back(Ref<Version>(new Version(24, 144, 144, 22, 22,
|
||||
new ECBlocks(62, new ECB(8, 156), new ECB(2, 155)))));
|
||||
VERSIONS.push_back(Ref<Version>(new Version(25, 8, 18, 6, 16,
|
||||
new ECBlocks(7, new ECB(1, 5)))));
|
||||
VERSIONS.push_back(Ref<Version>(new Version(26, 8, 32, 6, 14,
|
||||
new ECBlocks(11, new ECB(1, 10)))));
|
||||
VERSIONS.push_back(Ref<Version>(new Version(27, 12, 26, 10, 24,
|
||||
new ECBlocks(14, new ECB(1, 16)))));
|
||||
VERSIONS.push_back(Ref<Version>(new Version(28, 12, 36, 10, 16,
|
||||
new ECBlocks(18, new ECB(1, 22)))));
|
||||
VERSIONS.push_back(Ref<Version>(new Version(29, 16, 36, 10, 16,
|
||||
new ECBlocks(24, new ECB(1, 32)))));
|
||||
VERSIONS.push_back(Ref<Version>(new Version(30, 16, 48, 14, 22,
|
||||
new ECBlocks(28, new ECB(1, 49)))));
|
||||
return VERSIONS.size();
|
||||
}
|
||||
}
|
||||
}
|
85
cpp/core/src/zxing/datamatrix/Version.h
Normal file
85
cpp/core/src/zxing/datamatrix/Version.h
Normal file
|
@ -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:
|
||||
int versionNumber_;
|
||||
int symbolSizeRows_;
|
||||
int symbolSizeColumns_;
|
||||
int dataRegionSizeRows_;
|
||||
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();
|
||||
int getSymbolSizeRows();
|
||||
int getSymbolSizeColumns();
|
||||
int getDataRegionSizeRows();
|
||||
int getDataRegionSizeColumns();
|
||||
int getTotalCodewords();
|
||||
ECBlocks* getECBlocks();
|
||||
static int buildVersions();
|
||||
Version* getVersionForDimensions(int numRows, int numColumns);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif // __VERSION_H__
|
362
cpp/core/src/zxing/datamatrix/decoder/BitMatrixParser.cpp
Normal file
362
cpp/core/src/zxing/datamatrix/decoder/BitMatrixParser.cpp
Normal file
|
@ -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");
|
||||
|
||||
parsedVersion_ = readVersion(bitMatrix);
|
||||
bitMatrix_ = extractDataRegion(bitMatrix);
|
||||
// TODO(bbrown): Make this work for rectangular symbols
|
||||
readBitMatrix_ = new BitMatrix(bitMatrix_->getDimension());
|
||||
}
|
||||
|
||||
Version *BitMatrixParser::readVersion(Ref<BitMatrix> bitMatrix) {
|
||||
if (parsedVersion_ != 0) {
|
||||
return parsedVersion_;
|
||||
}
|
||||
|
||||
// TODO(bbrown): make this work for rectangular dimensions as well.
|
||||
int numRows = bitMatrix->getDimension();
|
||||
int numColumns = numRows;
|
||||
|
||||
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;
|
||||
int row = 4;
|
||||
int column = 0;
|
||||
|
||||
// TODO(bbrown): Data Matrix can be rectangular, assuming square for now
|
||||
int numRows = bitMatrix_->getDimension();
|
||||
int numColumns = numRows;
|
||||
|
||||
bool corner1Read = false;
|
||||
bool corner2Read = false;
|
||||
bool corner3Read = false;
|
||||
bool corner4Read = false;
|
||||
|
||||
// Read all of the codewords
|
||||
do {
|
||||
// Check the four corner cases
|
||||
if ((row == numRows) && (column == 0) && !corner1Read) {
|
||||
result[resultOffset++] = (unsigned char) readCorner1(numRows, numColumns);
|
||||
row -= 2;
|
||||
column +=2;
|
||||
corner1Read = true;
|
||||
} else if ((row == numRows-2) && (column == 0) && ((numColumns & 0x03) != 0) && !corner2Read) {
|
||||
result[resultOffset++] = (unsigned char) readCorner2(numRows, numColumns);
|
||||
row -= 2;
|
||||
column +=2;
|
||||
corner2Read = true;
|
||||
} else if ((row == numRows+4) && (column == 2) && ((numColumns & 0x07) == 0) && !corner3Read) {
|
||||
result[resultOffset++] = (unsigned char) readCorner3(numRows, numColumns);
|
||||
row -= 2;
|
||||
column +=2;
|
||||
corner3Read = true;
|
||||
} else if ((row == numRows-2) && (column == 0) && ((numColumns & 0x07) == 4) && !corner4Read) {
|
||||
result[resultOffset++] = (unsigned char) readCorner4(numRows, numColumns);
|
||||
row -= 2;
|
||||
column +=2;
|
||||
corner4Read = true;
|
||||
} else {
|
||||
// Sweep upward diagonally to the right
|
||||
do {
|
||||
if ((row < numRows) && (column >= 0) && !readBitMatrix_->get(column, row)) {
|
||||
result[resultOffset++] = (unsigned char) readUtah(row, column, numRows, numColumns);
|
||||
}
|
||||
row -= 2;
|
||||
column +=2;
|
||||
} while ((row >= 0) && (column < numColumns));
|
||||
row += 1;
|
||||
column +=3;
|
||||
|
||||
// Sweep downward diagonally to the left
|
||||
do {
|
||||
if ((row >= 0) && (column < numColumns) && !readBitMatrix_->get(column, row)) {
|
||||
result[resultOffset++] = (unsigned char) readUtah(row, column, numRows, numColumns);
|
||||
}
|
||||
row += 2;
|
||||
column -=2;
|
||||
} while ((row < numRows) && (column >= 0));
|
||||
row += 3;
|
||||
column +=1;
|
||||
}
|
||||
} while ((row < numRows) || (column < numColumns));
|
||||
|
||||
if (resultOffset != parsedVersion_->getTotalCodewords()) {
|
||||
throw ReaderException("Did not read all codewords");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool BitMatrixParser::readModule(int row, int column, int numRows, int numColumns) {
|
||||
// Adjust the row and column indices based on boundary wrapping
|
||||
if (row < 0) {
|
||||
row += numRows;
|
||||
column += 4 - ((numRows + 4) & 0x07);
|
||||
}
|
||||
if (column < 0) {
|
||||
column += numColumns;
|
||||
row += 4 - ((numColumns + 4) & 0x07);
|
||||
}
|
||||
readBitMatrix_->set(column, row);
|
||||
return bitMatrix_->get(column, row);
|
||||
}
|
||||
|
||||
int BitMatrixParser::readUtah(int row, int column, int numRows, int numColumns) {
|
||||
int currentByte = 0;
|
||||
if (readModule(row - 2, column - 2, numRows, numColumns)) {
|
||||
currentByte |= 1;
|
||||
}
|
||||
currentByte <<= 1;
|
||||
if (readModule(row - 2, column - 1, numRows, numColumns)) {
|
||||
currentByte |= 1;
|
||||
}
|
||||
currentByte <<= 1;
|
||||
if (readModule(row - 1, column - 2, numRows, numColumns)) {
|
||||
currentByte |= 1;
|
||||
}
|
||||
currentByte <<= 1;
|
||||
if (readModule(row - 1, column - 1, numRows, numColumns)) {
|
||||
currentByte |= 1;
|
||||
}
|
||||
currentByte <<= 1;
|
||||
if (readModule(row - 1, column, numRows, numColumns)) {
|
||||
currentByte |= 1;
|
||||
}
|
||||
currentByte <<= 1;
|
||||
if (readModule(row, column - 2, numRows, numColumns)) {
|
||||
currentByte |= 1;
|
||||
}
|
||||
currentByte <<= 1;
|
||||
if (readModule(row, column - 1, numRows, numColumns)) {
|
||||
currentByte |= 1;
|
||||
}
|
||||
currentByte <<= 1;
|
||||
if (readModule(row, column, numRows, numColumns)) {
|
||||
currentByte |= 1;
|
||||
}
|
||||
return currentByte;
|
||||
}
|
||||
|
||||
int BitMatrixParser::readCorner1(int numRows, int numColumns) {
|
||||
int currentByte = 0;
|
||||
if (readModule(numRows - 1, 0, numRows, numColumns)) {
|
||||
currentByte |= 1;
|
||||
}
|
||||
currentByte <<= 1;
|
||||
if (readModule(numRows - 1, 1, numRows, numColumns)) {
|
||||
currentByte |= 1;
|
||||
}
|
||||
currentByte <<= 1;
|
||||
if (readModule(numRows - 1, 2, numRows, numColumns)) {
|
||||
currentByte |= 1;
|
||||
}
|
||||
currentByte <<= 1;
|
||||
if (readModule(0, numColumns - 2, numRows, numColumns)) {
|
||||
currentByte |= 1;
|
||||
}
|
||||
currentByte <<= 1;
|
||||
if (readModule(0, numColumns - 1, numRows, numColumns)) {
|
||||
currentByte |= 1;
|
||||
}
|
||||
currentByte <<= 1;
|
||||
if (readModule(1, numColumns - 1, numRows, numColumns)) {
|
||||
currentByte |= 1;
|
||||
}
|
||||
currentByte <<= 1;
|
||||
if (readModule(2, numColumns - 1, numRows, numColumns)) {
|
||||
currentByte |= 1;
|
||||
}
|
||||
currentByte <<= 1;
|
||||
if (readModule(3, numColumns - 1, numRows, numColumns)) {
|
||||
currentByte |= 1;
|
||||
}
|
||||
return currentByte;
|
||||
}
|
||||
|
||||
int BitMatrixParser::readCorner2(int numRows, int numColumns) {
|
||||
int currentByte = 0;
|
||||
if (readModule(numRows - 3, 0, numRows, numColumns)) {
|
||||
currentByte |= 1;
|
||||
}
|
||||
currentByte <<= 1;
|
||||
if (readModule(numRows - 2, 0, numRows, numColumns)) {
|
||||
currentByte |= 1;
|
||||
}
|
||||
currentByte <<= 1;
|
||||
if (readModule(numRows - 1, 0, numRows, numColumns)) {
|
||||
currentByte |= 1;
|
||||
}
|
||||
currentByte <<= 1;
|
||||
if (readModule(0, numColumns - 4, numRows, numColumns)) {
|
||||
currentByte |= 1;
|
||||
}
|
||||
currentByte <<= 1;
|
||||
if (readModule(0, numColumns - 3, numRows, numColumns)) {
|
||||
currentByte |= 1;
|
||||
}
|
||||
currentByte <<= 1;
|
||||
if (readModule(0, numColumns - 2, numRows, numColumns)) {
|
||||
currentByte |= 1;
|
||||
}
|
||||
currentByte <<= 1;
|
||||
if (readModule(0, numColumns - 1, numRows, numColumns)) {
|
||||
currentByte |= 1;
|
||||
}
|
||||
currentByte <<= 1;
|
||||
if (readModule(1, numColumns - 1, numRows, numColumns)) {
|
||||
currentByte |= 1;
|
||||
}
|
||||
return currentByte;
|
||||
}
|
||||
|
||||
int BitMatrixParser::readCorner3(int numRows, int numColumns) {
|
||||
int currentByte = 0;
|
||||
if (readModule(numRows - 1, 0, numRows, numColumns)) {
|
||||
currentByte |= 1;
|
||||
}
|
||||
currentByte <<= 1;
|
||||
if (readModule(numRows - 1, numColumns - 1, numRows, numColumns)) {
|
||||
currentByte |= 1;
|
||||
}
|
||||
currentByte <<= 1;
|
||||
if (readModule(0, numColumns - 3, numRows, numColumns)) {
|
||||
currentByte |= 1;
|
||||
}
|
||||
currentByte <<= 1;
|
||||
if (readModule(0, numColumns - 2, numRows, numColumns)) {
|
||||
currentByte |= 1;
|
||||
}
|
||||
currentByte <<= 1;
|
||||
if (readModule(0, numColumns - 1, numRows, numColumns)) {
|
||||
currentByte |= 1;
|
||||
}
|
||||
currentByte <<= 1;
|
||||
if (readModule(1, numColumns - 3, numRows, numColumns)) {
|
||||
currentByte |= 1;
|
||||
}
|
||||
currentByte <<= 1;
|
||||
if (readModule(1, numColumns - 2, numRows, numColumns)) {
|
||||
currentByte |= 1;
|
||||
}
|
||||
currentByte <<= 1;
|
||||
if (readModule(1, numColumns - 1, numRows, numColumns)) {
|
||||
currentByte |= 1;
|
||||
}
|
||||
return currentByte;
|
||||
}
|
||||
|
||||
int BitMatrixParser::readCorner4(int numRows, int numColumns) {
|
||||
int currentByte = 0;
|
||||
if (readModule(numRows - 3, 0, numRows, numColumns)) {
|
||||
currentByte |= 1;
|
||||
}
|
||||
currentByte <<= 1;
|
||||
if (readModule(numRows - 2, 0, numRows, numColumns)) {
|
||||
currentByte |= 1;
|
||||
}
|
||||
currentByte <<= 1;
|
||||
if (readModule(numRows - 1, 0, numRows, numColumns)) {
|
||||
currentByte |= 1;
|
||||
}
|
||||
currentByte <<= 1;
|
||||
if (readModule(0, numColumns - 2, numRows, numColumns)) {
|
||||
currentByte |= 1;
|
||||
}
|
||||
currentByte <<= 1;
|
||||
if (readModule(0, numColumns - 1, numRows, numColumns)) {
|
||||
currentByte |= 1;
|
||||
}
|
||||
currentByte <<= 1;
|
||||
if (readModule(1, numColumns - 1, numRows, numColumns)) {
|
||||
currentByte |= 1;
|
||||
}
|
||||
currentByte <<= 1;
|
||||
if (readModule(2, numColumns - 1, numRows, numColumns)) {
|
||||
currentByte |= 1;
|
||||
}
|
||||
currentByte <<= 1;
|
||||
if (readModule(3, numColumns - 1, numRows, numColumns)) {
|
||||
currentByte |= 1;
|
||||
}
|
||||
return currentByte;
|
||||
}
|
||||
|
||||
Ref<BitMatrix> BitMatrixParser::extractDataRegion(Ref<BitMatrix> bitMatrix) {
|
||||
int symbolSizeRows = parsedVersion_->getSymbolSizeRows();
|
||||
int symbolSizeColumns = parsedVersion_->getSymbolSizeColumns();
|
||||
|
||||
// TODO(bbrown): Make this work with rectangular codes
|
||||
if ((int)bitMatrix->getDimension() != symbolSizeRows) {
|
||||
throw IllegalArgumentException("Dimension of bitMarix must match the version size");
|
||||
}
|
||||
|
||||
int dataRegionSizeRows = parsedVersion_->getDataRegionSizeRows();
|
||||
int dataRegionSizeColumns = parsedVersion_->getDataRegionSizeColumns();
|
||||
|
||||
int numDataRegionsRow = symbolSizeRows / dataRegionSizeRows;
|
||||
int numDataRegionsColumn = symbolSizeColumns / dataRegionSizeColumns;
|
||||
|
||||
int sizeDataRegionRow = numDataRegionsRow * dataRegionSizeRows;
|
||||
//int sizeDataRegionColumn = numDataRegionsColumn * dataRegionSizeColumns;
|
||||
|
||||
// TODO(bbrown): Make this work with rectangular codes
|
||||
Ref<BitMatrix> bitMatrixWithoutAlignment(new BitMatrix(sizeDataRegionRow));
|
||||
for (int dataRegionRow = 0; dataRegionRow < numDataRegionsRow; ++dataRegionRow) {
|
||||
int dataRegionRowOffset = dataRegionRow * dataRegionSizeRows;
|
||||
for (int dataRegionColumn = 0; dataRegionColumn < numDataRegionsColumn; ++dataRegionColumn) {
|
||||
int dataRegionColumnOffset = dataRegionColumn * dataRegionSizeColumns;
|
||||
for (int i = 0; i < dataRegionSizeRows; ++i) {
|
||||
int readRowOffset = dataRegionRow * (dataRegionSizeRows + 2) + 1 + i;
|
||||
int writeRowOffset = dataRegionRowOffset + i;
|
||||
for (int j = 0; j < dataRegionSizeColumns; ++j) {
|
||||
int readColumnOffset = dataRegionColumn * (dataRegionSizeColumns + 2) + 1 + j;
|
||||
if (bitMatrix->get(readColumnOffset, readRowOffset)) {
|
||||
int writeColumnOffset = dataRegionColumnOffset + j;
|
||||
bitMatrixWithoutAlignment->set(writeColumnOffset, writeRowOffset);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return bitMatrixWithoutAlignment;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
59
cpp/core/src/zxing/datamatrix/decoder/BitMatrixParser.h
Normal file
59
cpp/core/src/zxing/datamatrix/decoder/BitMatrixParser.h
Normal file
|
@ -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:
|
||||
int readUtah(int row, int column, int numRows, int numColumns);
|
||||
int readCorner1(int numRows, int numColumns);
|
||||
int readCorner2(int numRows, int numColumns);
|
||||
int readCorner3(int numRows, int numColumns);
|
||||
int readCorner4(int numRows, int numColumns);
|
||||
Ref<BitMatrix> extractDataRegion(Ref<BitMatrix> bitMatrix);
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif // __BIT_MATRIX_PARSER_DM_H__
|
113
cpp/core/src/zxing/datamatrix/decoder/DataBlock.cpp
Normal file
113
cpp/core/src/zxing/datamatrix/decoder/DataBlock.cpp
Normal file
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
50
cpp/core/src/zxing/datamatrix/decoder/DataBlock.h
Normal file
50
cpp/core/src/zxing/datamatrix/decoder/DataBlock.h
Normal file
|
@ -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__
|
404
cpp/core/src/zxing/datamatrix/decoder/DecodedBitStreamParser.cpp
Normal file
404
cpp/core/src/zxing/datamatrix/decoder/DecodedBitStreamParser.cpp
Normal file
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
103
cpp/core/src/zxing/datamatrix/decoder/DecodedBitStreamParser.h
Normal file
103
cpp/core/src/zxing/datamatrix/decoder/DecodedBitStreamParser.h
Normal file
|
@ -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__
|
96
cpp/core/src/zxing/datamatrix/decoder/Decoder.cpp
Normal file
96
cpp/core/src/zxing/datamatrix/decoder/Decoder.cpp
Normal file
|
@ -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) {
|
||||
}
|
||||
|
||||
|
||||
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) {
|
||||
// Construct a parser and read version, error-correction level
|
||||
BitMatrixParser parser(bits);
|
||||
Version *version = parser.readVersion(bits);
|
||||
|
||||
// Read codewords
|
||||
ArrayRef<unsigned char> codewords(parser.readCodewords());
|
||||
// Separate into data blocks
|
||||
std::vector<Ref<DataBlock> > dataBlocks = DataBlock::getDataBlocks(codewords, version);
|
||||
|
||||
// Count total number of data bytes
|
||||
int totalBytes = 0;
|
||||
for (unsigned int i = 0; i < dataBlocks.size(); i++) {
|
||||
totalBytes += dataBlocks[i]->getNumDataCodewords();
|
||||
}
|
||||
ArrayRef<unsigned char> resultBytes(totalBytes);
|
||||
int resultOffset = 0;
|
||||
|
||||
// Error-correct and copy data blocks together into a stream of bytes
|
||||
for (unsigned int j = 0; j < dataBlocks.size(); j++) {
|
||||
Ref<DataBlock> dataBlock(dataBlocks[j]);
|
||||
ArrayRef<unsigned char> codewordBytes = dataBlock->getCodewords();
|
||||
int numDataCodewords = dataBlock->getNumDataCodewords();
|
||||
correctErrors(codewordBytes, numDataCodewords);
|
||||
for (int i = 0; i < numDataCodewords; i++) {
|
||||
resultBytes[resultOffset++] = codewordBytes[i];
|
||||
}
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
}
|
51
cpp/core/src/zxing/datamatrix/decoder/Decoder.h
Normal file
51
cpp/core/src/zxing/datamatrix/decoder/Decoder.h
Normal file
|
@ -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);
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif // __DECODER_DM_H__
|
54
cpp/core/src/zxing/datamatrix/detector/CornerPoint.cpp
Normal file
54
cpp/core/src/zxing/datamatrix/detector/CornerPoint.cpp
Normal file
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
47
cpp/core/src/zxing/datamatrix/detector/CornerPoint.h
Normal file
47
cpp/core/src/zxing/datamatrix/detector/CornerPoint.h
Normal file
|
@ -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__
|
317
cpp/core/src/zxing/datamatrix/detector/Detector.cpp
Normal file
317
cpp/core/src/zxing/datamatrix/detector/Detector.cpp
Normal file
|
@ -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>
|
||||
#include <cmath>
|
||||
#include <sstream>
|
||||
|
||||
namespace zxing {
|
||||
namespace datamatrix {
|
||||
|
||||
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_;
|
||||
}
|
||||
|
||||
Detector::Detector(Ref<BitMatrix> image) : image_(image) { }
|
||||
|
||||
Ref<BitMatrix> Detector::getImage() {
|
||||
return image_;
|
||||
}
|
||||
|
||||
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);
|
||||
transitions[0].reset(transitionsBetween(pointA, pointB));
|
||||
transitions[1].reset(transitionsBetween(pointA, pointC));
|
||||
transitions[2].reset(transitionsBetween(pointB, pointD));
|
||||
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);
|
||||
corners[0].reset(maybeTopLeft);
|
||||
corners[1].reset(bottomLeft);
|
||||
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;
|
||||
|
||||
Ref<PerspectiveTransform> transform = createTransform(topLeft, topR, bottomLeft, bottomRight, dimension);
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
Ref<PerspectiveTransform> Detector::createTransform(Ref<ResultPoint> topLeft, Ref<ResultPoint> topRight, Ref <
|
||||
ResultPoint > bottomLeft, Ref<ResultPoint> bottomRight, int dimension) {
|
||||
|
||||
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()));
|
||||
return transform;
|
||||
}
|
||||
|
||||
Ref<BitMatrix> Detector::sampleGrid(Ref<BitMatrix> image, int dimension, Ref<PerspectiveTransform> transform) {
|
||||
GridSampler &sampler = GridSampler::getInstance();
|
||||
return sampler.sampleGrid(image, dimension, transform);
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
}
|
||||
}
|
79
cpp/core/src/zxing/datamatrix/detector/Detector.h
Normal file
79
cpp/core/src/zxing/datamatrix/detector/Detector.h
Normal file
|
@ -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.
|
||||
*/
|
||||
|
||||
|
||||
#include <zxing/common/Counted.h>
|
||||
#include <zxing/common/DetectorResult.h>
|
||||
#include <zxing/common/BitMatrix.h>
|
||||
#include <zxing/common/PerspectiveTransform.h>
|
||||
#include <zxing/datamatrix/detector/MonochromeRectangleDetector.h>
|
||||
|
||||
|
||||
namespace zxing {
|
||||
namespace datamatrix {
|
||||
|
||||
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();
|
||||
};
|
||||
|
||||
class Detector : public Counted {
|
||||
private:
|
||||
Ref<BitMatrix> image_;
|
||||
|
||||
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; };
|
||||
|
||||
public:
|
||||
Ref<BitMatrix> getImage();
|
||||
Detector(Ref<BitMatrix> image);
|
||||
|
||||
virtual Ref<PerspectiveTransform> createTransform(Ref<ResultPoint> topLeft, Ref<ResultPoint> topRight, Ref <
|
||||
ResultPoint > bottomLeft, Ref<ResultPoint> bottomRight, int dimension);
|
||||
|
||||
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);
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif // __DETECTOR_H__
|
|
@ -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.
|
||||
*/
|
||||
|
||||
#include <zxing/ReaderException.h>
|
||||
#include <zxing/datamatrix/detector/MonochromeRectangleDetector.h>
|
||||
#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);
|
||||
corners[0].reset(pointA);
|
||||
corners[1].reset(pointB);
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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>
|
||||
#include <zxing/ReaderException.h>
|
||||
#include <zxing/ResultPoint.h>
|
||||
#include <zxing/common/BitMatrix.h>
|
||||
#include <zxing/common/Counted.h>
|
||||
#include <zxing/datamatrix/detector/CornerPoint.h>
|
||||
|
||||
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__
|
Loading…
Reference in a new issue