From a57f8b24d35abc15b241876b02ab2b73ae930e56 Mon Sep 17 00:00:00 2001 From: favoritas37 Date: Mon, 1 Jun 2015 22:29:56 +0300 Subject: [PATCH] Progressing the support of QR encoder. Ported MartixUtil, MaskUtil, applied fixes to ByteMatrix and extended BitArray to support array building. --- source/QZXing.pri | 3 +- source/zxing/zxing/WriterException.h | 17 + source/zxing/zxing/common/BitArray.cpp | 202 ++++--- source/zxing/zxing/common/BitArray.h | 74 ++- source/zxing/zxing/qrcode/QRVersion.cpp | 2 +- source/zxing/zxing/qrcode/Version.h | 2 +- .../zxing/zxing/qrcode/encoder/ByteMatrix.cpp | 10 +- .../zxing/zxing/qrcode/encoder/ByteMatrix.h | 10 +- source/zxing/zxing/qrcode/encoder/Encoder.cpp | 545 +++++++++++++++++ source/zxing/zxing/qrcode/encoder/Encoder.h | 566 ++---------------- .../zxing/zxing/qrcode/encoder/MaskUtil.cpp | 204 +++++++ source/zxing/zxing/qrcode/encoder/MaskUtil.h | 261 ++------ .../zxing/zxing/qrcode/encoder/MatrixUtil.cpp | 409 +++++++++++++ .../zxing/zxing/qrcode/encoder/MatrixUtil.h | 558 ++++------------- 14 files changed, 1590 insertions(+), 1273 deletions(-) create mode 100644 source/zxing/zxing/WriterException.h diff --git a/source/QZXing.pri b/source/QZXing.pri index 061dda5..06d3959 100644 --- a/source/QZXing.pri +++ b/source/QZXing.pri @@ -128,7 +128,8 @@ HEADERS += $$PWD/QZXing_global.h \ $$PWD/zxing/zxing/qrcode/encoder/Encoder.h \ $$PWD/zxing/zxing/qrcode/encoder/MaskUtil.h \ $$PWD/zxing/zxing/qrcode/encoder/MatrixUtil.h \ - $$PWD/zxing/zxing/qrcode/encoder/QRCode.h + $$PWD/zxing/zxing/qrcode/encoder/QRCode.h \ + $$PWD/zxing/zxing/WriterException.h SOURCES += $$PWD/CameraImageWrapper.cpp \ $$PWD/qzxing.cpp \ diff --git a/source/zxing/zxing/WriterException.h b/source/zxing/zxing/WriterException.h new file mode 100644 index 0000000..c511c8e --- /dev/null +++ b/source/zxing/zxing/WriterException.h @@ -0,0 +1,17 @@ +#ifndef WRITEREXCEPTION_H +#define WRITEREXCEPTION_H + +#include + +namespace zxing { + +class WriterException : public Exception { + public: + WriterException() throw() {} + WriterException(char const* msg) throw() : Exception(msg) {} + ~WriterException() throw() {} +}; + +} + +#endif // WRITEREXCEPTION_H diff --git a/source/zxing/zxing/common/BitArray.cpp b/source/zxing/zxing/common/BitArray.cpp index 3495e14..4f716f1 100644 --- a/source/zxing/zxing/common/BitArray.cpp +++ b/source/zxing/zxing/common/BitArray.cpp @@ -16,96 +16,101 @@ */ #include +#include +#include using std::vector; using zxing::BitArray; + // VC++ using zxing::Ref; int BitArray::makeArraySize(int size) { - return (size + bitsPerWord-1) >> logBits; + return (size + bitsPerWord-1) >> logBits; } +BitArray::BitArray(): size(0), bits(1) {} + BitArray::BitArray(int size_) - : size(size_), bits(makeArraySize(size)) {} + : size(size_), bits(makeArraySize(size)) {} BitArray::~BitArray() { } int BitArray::getSize() const { - return size; + return size; } void BitArray::setBulk(int i, int newBits) { - bits[i >> logBits] = newBits; + bits[i >> logBits] = newBits; } void BitArray::clear() { - int max = bits->size(); - for (int i = 0; i < max; i++) { - bits[i] = 0; - } + int max = bits->size(); + for (int i = 0; i < max; i++) { + bits[i] = 0; + } } bool BitArray::isRange(int start, int end, bool value) { - if (end < start) { - throw IllegalArgumentException(); - } - if (end == start) { - return true; // empty range matches - } - end--; // will be easier to treat this as the last actually set bit -- inclusive - int firstInt = start >> logBits; - int lastInt = end >> logBits; - for (int i = firstInt; i <= lastInt; i++) { - int firstBit = i > firstInt ? 0 : start & bitsMask; - int lastBit = i < lastInt ? (bitsPerWord-1) : end & bitsMask; - int mask; - if (firstBit == 0 && lastBit == (bitsPerWord-1)) { - mask = -1; - } else { - mask = 0; - for (int j = firstBit; j <= lastBit; j++) { - mask |= 1 << j; - } + if (end < start) { + throw IllegalArgumentException(); } - - // Return false if we're looking for 1s and the masked bits[i] isn't all 1s (that is, - // equals the mask, or we're looking for 0s and the masked portion is not all 0s - if ((bits[i] & mask) != (value ? mask : 0)) { - return false; + if (end == start) { + return true; // empty range matches } - } - return true; + end--; // will be easier to treat this as the last actually set bit -- inclusive + int firstInt = start >> logBits; + int lastInt = end >> logBits; + for (int i = firstInt; i <= lastInt; i++) { + int firstBit = i > firstInt ? 0 : start & bitsMask; + int lastBit = i < lastInt ? (bitsPerWord-1) : end & bitsMask; + int mask; + if (firstBit == 0 && lastBit == (bitsPerWord-1)) { + mask = -1; + } else { + mask = 0; + for (int j = firstBit; j <= lastBit; j++) { + mask |= 1 << j; + } + } + + // Return false if we're looking for 1s and the masked bits[i] isn't all 1s (that is, + // equals the mask, or we're looking for 0s and the masked portion is not all 0s + if ((bits[i] & mask) != (value ? mask : 0)) { + return false; + } + } + return true; } vector& BitArray::getBitArray() { - return bits->values(); + return bits->values(); } void BitArray::reverse() { - ArrayRef newBits(bits->size()); - int size = this->size; - for (int i = 0; i < size; i++) { - if (get(size - i - 1)) { - newBits[i >> logBits] |= 1 << (i & bitsMask); + ArrayRef newBits(bits->size()); + int size = this->size; + for (int i = 0; i < size; i++) { + if (get(size - i - 1)) { + newBits[i >> logBits] |= 1 << (i & bitsMask); + } } - } - bits = newBits; + bits = newBits; } BitArray::Reverse::Reverse(Ref array_) : array(array_) { - array->reverse(); + array->reverse(); } BitArray::Reverse::~Reverse() { - array->reverse(); + array->reverse(); } namespace { - // N.B.: This only works for 32 bit ints ... - int numberOfTrailingZeros(int i) { +// N.B.: This only works for 32 bit ints ... +int numberOfTrailingZeros(int i) { // HD, Figure 5-14 int y; if (i == 0) return 32; @@ -115,41 +120,86 @@ namespace { y = i << 4; if (y != 0) { n = n - 4; i = y; } y = i << 2; if (y != 0) { n = n - 2; i = y; } return n - (((unsigned int)(i << 1)) >> 31); - } +} } int BitArray::getNextSet(int from) { - if (from >= size) { - return size; - } - int bitsOffset = from >> logBits; - int currentBits = bits[bitsOffset]; - // mask off lesser bits first - currentBits &= ~((1 << (from & bitsMask)) - 1); - while (currentBits == 0) { - if (++bitsOffset == (int)bits->size()) { - return size; + if (from >= size) { + return size; } - currentBits = bits[bitsOffset]; - } - int result = (bitsOffset << logBits) + numberOfTrailingZeros(currentBits); - return result > size ? size : result; + int bitsOffset = from >> logBits; + int currentBits = bits[bitsOffset]; + // mask off lesser bits first + currentBits &= ~((1 << (from & bitsMask)) - 1); + while (currentBits == 0) { + if (++bitsOffset == (int)bits->size()) { + return size; + } + currentBits = bits[bitsOffset]; + } + int result = (bitsOffset << logBits) + numberOfTrailingZeros(currentBits); + return result > size ? size : result; } int BitArray::getNextUnset(int from) { - if (from >= size) { - return size; - } - int bitsOffset = from >> logBits; - int currentBits = ~bits[bitsOffset]; - // mask off lesser bits first - currentBits &= ~((1 << (from & bitsMask)) - 1); - while (currentBits == 0) { - if (++bitsOffset == (int)bits->size()) { - return size; + if (from >= size) { + return size; } - currentBits = ~bits[bitsOffset]; - } - int result = (bitsOffset << logBits) + numberOfTrailingZeros(currentBits); - return result > size ? size : result; + int bitsOffset = from >> logBits; + int currentBits = ~bits[bitsOffset]; + // mask off lesser bits first + currentBits &= ~((1 << (from & bitsMask)) - 1); + while (currentBits == 0) { + if (++bitsOffset == (int)bits->size()) { + return size; + } + currentBits = ~bits[bitsOffset]; + } + int result = (bitsOffset << logBits) + numberOfTrailingZeros(currentBits); + return result > size ? size : result; +} + +void BitArray::appendBit(bool bit) +{ + ensureCapacity(size + 1); + if (bit) { + bits[size / 32] |= 1 << (size & 0x1F); + } + size++; +} + +void BitArray::appendBits(int value, int numBits) +{ + if (numBits < 0 || numBits > 32) { + throw IllegalArgumentException("Num bits must be between 0 and 32"); + } + ensureCapacity(size + numBits); + for (int numBitsLeft = numBits; numBitsLeft > 0; numBitsLeft--) { + appendBit(((value >> (numBitsLeft - 1)) & 0x01) == 1); + } +} + +void BitArray::ensureCapacity(int size) +{ + if (size > bits->size() * 32) + { + ArrayRef newBits = makeArray(size); + //memcpy(bits, newBits->, bits->size()); + for (size_t i=0; isize(); ++i) { + newBits[i] = bits[i]; + } + bits = newBits; + } +} + +void BitArray::xor_(const BitArray& other) +{ + if (bits->size() != other.bits->size()) { + throw IllegalArgumentException("Sizes don't match"); + } + for (int i = 0; i < bits->size(); i++) { + // The last byte could be incomplete (i.e. not have 8 bits in + // it) but there is no problem since 0 XOR 0 == 0. + bits[i] ^= other.bits[i]; + } } diff --git a/source/zxing/zxing/common/BitArray.h b/source/zxing/zxing/common/BitArray.h index e4a95a7..0a063df 100644 --- a/source/zxing/zxing/common/BitArray.h +++ b/source/zxing/zxing/common/BitArray.h @@ -25,53 +25,65 @@ #include #include #include +#include namespace zxing { class BitArray : public Counted { public: - static const int bitsPerWord = std::numeric_limits::digits; + static const int bitsPerWord = std::numeric_limits::digits; private: - int size; - ArrayRef bits; - static const int logBits = ZX_LOG_DIGITS(bitsPerWord); - static const int bitsMask = (1 << logBits) - 1; + int size; + ArrayRef bits; + static const int logBits = ZX_LOG_DIGITS(bitsPerWord); + static const int bitsMask = (1 << logBits) - 1; public: - BitArray(int size); - ~BitArray(); - int getSize() const; + BitArray(); + BitArray(int size); + ~BitArray(); + int getSize() const; - bool get(int i) const { - return (bits[i >> logBits] & (1 << (i & bitsMask))) != 0; - } + bool get(int i) const { + return (bits[i >> logBits] & (1 << (i & bitsMask))) != 0; + } - void set(int i) { - bits[i >> logBits] |= 1 << (i & bitsMask); - } + void set(int i) { + bits[i >> logBits] |= 1 << (i & bitsMask); + } - int getNextSet(int from); - int getNextUnset(int from); + int getNextSet(int from); + int getNextUnset(int from); - void setBulk(int i, int newBits); - void setRange(int start, int end); - void clear(); - bool isRange(int start, int end, bool value); - std::vector& getBitArray(); - - void reverse(); + void setBulk(int i, int newBits); + void setRange(int start, int end); + void clear(); + bool isRange(int start, int end, bool value); + std::vector& getBitArray(); - class Reverse { - private: - Ref array; - public: - Reverse(Ref array); - ~Reverse(); - }; + void appendBit(bool bit); + void appendBits(int value, int numBits); + void ensureCapacity(int size); + + void xor_(const BitArray& other); + + static ArrayRef makeArray(int size) { + return ArrayRef((size + 31) / 32); + } + + void reverse(); + + class Reverse { + private: + Ref array; + public: + Reverse(Ref array); + ~Reverse(); + }; private: - static int makeArraySize(int size); + static int makeArraySize(int size); }; std::ostream& operator << (std::ostream&, BitArray const&); diff --git a/source/zxing/zxing/qrcode/QRVersion.cpp b/source/zxing/zxing/qrcode/QRVersion.cpp index 39d6e8f..6f8f5f0 100644 --- a/source/zxing/zxing/qrcode/QRVersion.cpp +++ b/source/zxing/zxing/qrcode/QRVersion.cpp @@ -75,7 +75,7 @@ int Version::N_VERSION_DECODE_INFOS = 34; vector > Version::VERSIONS; static int N_VERSIONS = Version::buildVersions(); -int Version::getVersionNumber() { +int Version::getVersionNumber() const { return versionNumber_; } diff --git a/source/zxing/zxing/qrcode/Version.h b/source/zxing/zxing/qrcode/Version.h index c111cdd..5923e48 100644 --- a/source/zxing/zxing/qrcode/Version.h +++ b/source/zxing/zxing/qrcode/Version.h @@ -68,7 +68,7 @@ public: static std::vector > VERSIONS; ~Version(); - int getVersionNumber(); + int getVersionNumber() const; std::vector &getAlignmentPatternCenters(); int getTotalCodewords(); int getDimensionForVersion(); diff --git a/source/zxing/zxing/qrcode/encoder/ByteMatrix.cpp b/source/zxing/zxing/qrcode/encoder/ByteMatrix.cpp index 3e3f055..34f0058 100644 --- a/source/zxing/zxing/qrcode/encoder/ByteMatrix.cpp +++ b/source/zxing/zxing/qrcode/encoder/ByteMatrix.cpp @@ -11,22 +11,22 @@ ByteMatrix::ByteMatrix(size_t width, size_t height) : bytes_[i].resize(width); } -size_t ByteMatrix::getHeight() +size_t ByteMatrix::getHeight() const { return height_; } -size_t ByteMatrix::getWidth() +size_t ByteMatrix::getWidth() const { return width_; } -char ByteMatrix::get(size_t x, size_t y) +char ByteMatrix::get(size_t x, size_t y) const { return bytes_[y][x]; } -std::vector< std::vector > ByteMatrix::getArray() +std::vector< std::vector > ByteMatrix::getArray() const { return bytes_; } @@ -55,7 +55,7 @@ void ByteMatrix::clear(const char value) } } -const std::string ByteMatrix::toString() +const std::string ByteMatrix::toString() const { std::stringstream result;// = new StringBuilder(2 * width * height + 2); for (size_t y = 0; y < height_; ++y) { diff --git a/source/zxing/zxing/qrcode/encoder/ByteMatrix.h b/source/zxing/zxing/qrcode/encoder/ByteMatrix.h index 4e91791..b9e1319 100644 --- a/source/zxing/zxing/qrcode/encoder/ByteMatrix.h +++ b/source/zxing/zxing/qrcode/encoder/ByteMatrix.h @@ -18,16 +18,16 @@ public: ByteMatrix(size_t width, size_t height); - size_t getHeight(); - size_t getWidth(); - char get(size_t x, size_t y); + size_t getHeight() const; + size_t getWidth() const; + char get(size_t x, size_t y) const; - std::vector< std::vector > getArray(); + std::vector< std::vector > getArray() const; void set(size_t x, size_t y, const char value); void set(size_t x, size_t y, size_t value); void set(size_t x, size_t y, bool value); void clear(const char value); - const std::string toString(); + const std::string toString() const; }; diff --git a/source/zxing/zxing/qrcode/encoder/Encoder.cpp b/source/zxing/zxing/qrcode/encoder/Encoder.cpp index e69de29..4b58280 100644 --- a/source/zxing/zxing/qrcode/encoder/Encoder.cpp +++ b/source/zxing/zxing/qrcode/encoder/Encoder.cpp @@ -0,0 +1,545 @@ +//#include "Encoder.h" +//#include + +//namespace zxing { +//namespace qrcode { + +//// The original table is defined in the table 5 of JISX0510:2004 (p.19). +//const int Encoder::ALPHANUMERIC_TABLE[] = { +// -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 0x00-0x0f +// -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 0x10-0x1f +// 36, -1, -1, -1, 37, 38, -1, -1, -1, -1, 39, 40, -1, 41, 42, 43, // 0x20-0x2f +// 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 44, -1, -1, -1, -1, -1, // 0x30-0x3f +// -1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, // 0x40-0x4f +// 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1, // 0x50-0x5f +//}; + +//const std::string DEFAULT_BYTE_MODE_ENCODING = "ISO-8859-1"; + +////static int Encoder::calculateMaskPenalty(ByteMatrix matrix) { +//// return MaskUtil.applyMaskPenaltyRule1(matrix) +//// + MaskUtil.applyMaskPenaltyRule2(matrix) +//// + MaskUtil.applyMaskPenaltyRule3(matrix) +//// + MaskUtil.applyMaskPenaltyRule4(matrix); +////} + +//// /** +//// * Encode "bytes" with the error correction level "ecLevel". The encoding mode will be chosen +//// * internally by chooseMode(). On success, store the result in "qrCode". +//// * +//// * We recommend you to use QRCode.EC_LEVEL_L (the lowest level) for +//// * "getECLevel" since our primary use is to show QR code on desktop screens. We don't need very +//// * strong error correction for this purpose. +//// * +//// * Note that there is no way to encode bytes in MODE_KANJI. We might want to add EncodeWithMode() +//// * with which clients can specify the encoding mode. For now, we don't need the functionality. +//// */ +//// public static QRCode encode(String content, ErrorCorrectionLevel ecLevel) throws WriterException { +//// return encode(content, ecLevel, null); +//// } + +//// public static QRCode encode(String content, +//// ErrorCorrectionLevel ecLevel, +//// Map hints) throws WriterException { + +//// // Determine what character encoding has been specified by the caller, if any +//// String encoding = hints == null ? null : (String) hints.get(EncodeHintType.CHARACTER_SET); +//// if (encoding == null) { +//// encoding = DEFAULT_BYTE_MODE_ENCODING; +//// } + +//// // Pick an encoding mode appropriate for the content. Note that this will not attempt to use +//// // multiple modes / segments even if that were more efficient. Twould be nice. +//// Mode mode = chooseMode(content, encoding); + +//// // This will store the header information, like mode and +//// // length, as well as "header" segments like an ECI segment. +//// BitArray headerBits = new BitArray(); + +//// // Append ECI segment if applicable +//// if (mode == Mode.BYTE && !DEFAULT_BYTE_MODE_ENCODING.equals(encoding)) { +//// CharacterSetECI eci = CharacterSetECI.getCharacterSetECIByName(encoding); +//// if (eci != null) { +//// appendECI(eci, headerBits); +//// } +//// } + +//// // (With ECI in place,) Write the mode marker +//// appendModeInfo(mode, headerBits); + +//// // Collect data within the main segment, separately, to count its size if needed. Don't add it to +//// // main payload yet. +//// BitArray dataBits = new BitArray(); +//// appendBytes(content, mode, dataBits, encoding); + +//// // Hard part: need to know version to know how many bits length takes. But need to know how many +//// // bits it takes to know version. First we take a guess at version by assuming version will be +//// // the minimum, 1: + +//// int provisionalBitsNeeded = headerBits.getSize() +//// + mode.getCharacterCountBits(Version.getVersionForNumber(1)) +//// + dataBits.getSize(); +//// Version provisionalVersion = chooseVersion(provisionalBitsNeeded, ecLevel); + +//// // Use that guess to calculate the right version. I am still not sure this works in 100% of cases. + +//// int bitsNeeded = headerBits.getSize() +//// + mode.getCharacterCountBits(provisionalVersion) +//// + dataBits.getSize(); +//// Version version = chooseVersion(bitsNeeded, ecLevel); + +//// BitArray headerAndDataBits = new BitArray(); +//// headerAndDataBits.appendBitArray(headerBits); +//// // Find "length" of main segment and write it +//// int numLetters = mode == Mode.BYTE ? dataBits.getSizeInBytes() : content.length(); +//// appendLengthInfo(numLetters, version, mode, headerAndDataBits); +//// // Put data together into the overall payload +//// headerAndDataBits.appendBitArray(dataBits); + +//// Version.ECBlocks ecBlocks = version.getECBlocksForLevel(ecLevel); +//// int numDataBytes = version.getTotalCodewords() - ecBlocks.getTotalECCodewords(); + +//// // Terminate the bits properly. +//// terminateBits(numDataBytes, headerAndDataBits); + +//// // Interleave data bits with error correction code. +//// BitArray finalBits = interleaveWithECBytes(headerAndDataBits, +//// version.getTotalCodewords(), +//// numDataBytes, +//// ecBlocks.getNumBlocks()); + +//// QRCode qrCode = new QRCode(); + +//// qrCode.setECLevel(ecLevel); +//// qrCode.setMode(mode); +//// qrCode.setVersion(version); + +//// // Choose the mask pattern and set to "qrCode". +//// int dimension = version.getDimensionForVersion(); +//// ByteMatrix matrix = new ByteMatrix(dimension, dimension); +//// int maskPattern = chooseMaskPattern(finalBits, ecLevel, version, matrix); +//// qrCode.setMaskPattern(maskPattern); + +//// // Build the matrix and set it to "qrCode". +//// MatrixUtil.buildMatrix(finalBits, ecLevel, version, maskPattern, matrix); +//// qrCode.setMatrix(matrix); + +//// return qrCode; +//// } + +//// /** +//// * @return the code point of the table used in alphanumeric mode or +//// * -1 if there is no corresponding code in the table. +//// */ +//// static int getAlphanumericCode(int code) { +//// if (code < ALPHANUMERIC_TABLE.length) { +//// return ALPHANUMERIC_TABLE[code]; +//// } +//// return -1; +//// } + +//// public static Mode chooseMode(String content) { +//// return chooseMode(content, null); +//// } + +//// /** +//// * Choose the best mode by examining the content. Note that 'encoding' is used as a hint; +//// * if it is Shift_JIS, and the input is only double-byte Kanji, then we return {@link Mode#KANJI}. +//// */ +//// private static Mode chooseMode(String content, String encoding) { +//// if ("Shift_JIS".equals(encoding)) { +//// // Choose Kanji mode if all input are double-byte characters +//// return isOnlyDoubleByteKanji(content) ? Mode.KANJI : Mode.BYTE; +//// } +//// boolean hasNumeric = false; +//// boolean hasAlphanumeric = false; +//// for (int i = 0; i < content.length(); ++i) { +//// char c = content.charAt(i); +//// if (c >= '0' && c <= '9') { +//// hasNumeric = true; +//// } else if (getAlphanumericCode(c) != -1) { +//// hasAlphanumeric = true; +//// } else { +//// return Mode.BYTE; +//// } +//// } +//// if (hasAlphanumeric) { +//// return Mode.ALPHANUMERIC; +//// } +//// if (hasNumeric) { +//// return Mode.NUMERIC; +//// } +//// return Mode.BYTE; +//// } + +//// private static boolean isOnlyDoubleByteKanji(String content) { +//// byte[] bytes; +//// try { +//// bytes = content.getBytes("Shift_JIS"); +//// } catch (UnsupportedEncodingException ignored) { +//// return false; +//// } +//// int length = bytes.length; +//// if (length % 2 != 0) { +//// return false; +//// } +//// for (int i = 0; i < length; i += 2) { +//// int byte1 = bytes[i] & 0xFF; +//// if ((byte1 < 0x81 || byte1 > 0x9F) && (byte1 < 0xE0 || byte1 > 0xEB)) { +//// return false; +//// } +//// } +//// return true; +//// } + +//// private static int chooseMaskPattern(BitArray bits, +//// ErrorCorrectionLevel ecLevel, +//// Version version, +//// ByteMatrix matrix) throws WriterException { + +//// int minPenalty = Integer.MAX_VALUE; // Lower penalty is better. +//// int bestMaskPattern = -1; +//// // We try all mask patterns to choose the best one. +//// for (int maskPattern = 0; maskPattern < QRCode.NUM_MASK_PATTERNS; maskPattern++) { +//// MatrixUtil.buildMatrix(bits, ecLevel, version, maskPattern, matrix); +//// int penalty = calculateMaskPenalty(matrix); +//// if (penalty < minPenalty) { +//// minPenalty = penalty; +//// bestMaskPattern = maskPattern; +//// } +//// } +//// return bestMaskPattern; +//// } + +//// private static Version chooseVersion(int numInputBits, ErrorCorrectionLevel ecLevel) throws WriterException { +//// // In the following comments, we use numbers of Version 7-H. +//// for (int versionNum = 1; versionNum <= 40; versionNum++) { +//// Version version = Version.getVersionForNumber(versionNum); +//// // numBytes = 196 +//// int numBytes = version.getTotalCodewords(); +//// // getNumECBytes = 130 +//// Version.ECBlocks ecBlocks = version.getECBlocksForLevel(ecLevel); +//// int numEcBytes = ecBlocks.getTotalECCodewords(); +//// // getNumDataBytes = 196 - 130 = 66 +//// int numDataBytes = numBytes - numEcBytes; +//// int totalInputBytes = (numInputBits + 7) / 8; +//// if (numDataBytes >= totalInputBytes) { +//// return version; +//// } +//// } +//// throw new WriterException("Data too big"); +//// } + +//// /** +//// * Terminate bits as described in 8.4.8 and 8.4.9 of JISX0510:2004 (p.24). +//// */ +//// static void terminateBits(int numDataBytes, BitArray bits) throws WriterException { +//// int capacity = numDataBytes << 3; +//// if (bits.getSize() > capacity) { +//// throw new WriterException("data bits cannot fit in the QR Code" + bits.getSize() + " > " + +//// capacity); +//// } +//// for (int i = 0; i < 4 && bits.getSize() < capacity; ++i) { +//// bits.appendBit(false); +//// } +//// // Append termination bits. See 8.4.8 of JISX0510:2004 (p.24) for details. +//// // If the last byte isn't 8-bit aligned, we'll add padding bits. +//// int numBitsInLastByte = bits.getSize() & 0x07; +//// if (numBitsInLastByte > 0) { +//// for (int i = numBitsInLastByte; i < 8; i++) { +//// bits.appendBit(false); +//// } +//// } +//// // If we have more space, we'll fill the space with padding patterns defined in 8.4.9 (p.24). +//// int numPaddingBytes = numDataBytes - bits.getSizeInBytes(); +//// for (int i = 0; i < numPaddingBytes; ++i) { +//// bits.appendBits((i & 0x01) == 0 ? 0xEC : 0x11, 8); +//// } +//// if (bits.getSize() != capacity) { +//// throw new WriterException("Bits size does not equal capacity"); +//// } +//// } + +//// /** +//// * Get number of data bytes and number of error correction bytes for block id "blockID". Store +//// * the result in "numDataBytesInBlock", and "numECBytesInBlock". See table 12 in 8.5.1 of +//// * JISX0510:2004 (p.30) +//// */ +//// static void getNumDataBytesAndNumECBytesForBlockID(int numTotalBytes, +//// int numDataBytes, +//// int numRSBlocks, +//// int blockID, +//// int[] numDataBytesInBlock, +//// int[] numECBytesInBlock) throws WriterException { +//// if (blockID >= numRSBlocks) { +//// throw new WriterException("Block ID too large"); +//// } +//// // numRsBlocksInGroup2 = 196 % 5 = 1 +//// int numRsBlocksInGroup2 = numTotalBytes % numRSBlocks; +//// // numRsBlocksInGroup1 = 5 - 1 = 4 +//// int numRsBlocksInGroup1 = numRSBlocks - numRsBlocksInGroup2; +//// // numTotalBytesInGroup1 = 196 / 5 = 39 +//// int numTotalBytesInGroup1 = numTotalBytes / numRSBlocks; +//// // numTotalBytesInGroup2 = 39 + 1 = 40 +//// int numTotalBytesInGroup2 = numTotalBytesInGroup1 + 1; +//// // numDataBytesInGroup1 = 66 / 5 = 13 +//// int numDataBytesInGroup1 = numDataBytes / numRSBlocks; +//// // numDataBytesInGroup2 = 13 + 1 = 14 +//// int numDataBytesInGroup2 = numDataBytesInGroup1 + 1; +//// // numEcBytesInGroup1 = 39 - 13 = 26 +//// int numEcBytesInGroup1 = numTotalBytesInGroup1 - numDataBytesInGroup1; +//// // numEcBytesInGroup2 = 40 - 14 = 26 +//// int numEcBytesInGroup2 = numTotalBytesInGroup2 - numDataBytesInGroup2; +//// // Sanity checks. +//// // 26 = 26 +//// if (numEcBytesInGroup1 != numEcBytesInGroup2) { +//// throw new WriterException("EC bytes mismatch"); +//// } +//// // 5 = 4 + 1. +//// if (numRSBlocks != numRsBlocksInGroup1 + numRsBlocksInGroup2) { +//// throw new WriterException("RS blocks mismatch"); +//// } +//// // 196 = (13 + 26) * 4 + (14 + 26) * 1 +//// if (numTotalBytes != +//// ((numDataBytesInGroup1 + numEcBytesInGroup1) * +//// numRsBlocksInGroup1) + +//// ((numDataBytesInGroup2 + numEcBytesInGroup2) * +//// numRsBlocksInGroup2)) { +//// throw new WriterException("Total bytes mismatch"); +//// } + +//// if (blockID < numRsBlocksInGroup1) { +//// numDataBytesInBlock[0] = numDataBytesInGroup1; +//// numECBytesInBlock[0] = numEcBytesInGroup1; +//// } else { +//// numDataBytesInBlock[0] = numDataBytesInGroup2; +//// numECBytesInBlock[0] = numEcBytesInGroup2; +//// } +//// } + +//// /** +//// * Interleave "bits" with corresponding error correction bytes. On success, store the result in +//// * "result". The interleave rule is complicated. See 8.6 of JISX0510:2004 (p.37) for details. +//// */ +//// static BitArray interleaveWithECBytes(BitArray bits, +//// int numTotalBytes, +//// int numDataBytes, +//// int numRSBlocks) throws WriterException { + +//// // "bits" must have "getNumDataBytes" bytes of data. +//// if (bits.getSizeInBytes() != numDataBytes) { +//// throw new WriterException("Number of bits and data bytes does not match"); +//// } + +//// // Step 1. Divide data bytes into blocks and generate error correction bytes for them. We'll +//// // store the divided data bytes blocks and error correction bytes blocks into "blocks". +//// int dataBytesOffset = 0; +//// int maxNumDataBytes = 0; +//// int maxNumEcBytes = 0; + +//// // Since, we know the number of reedsolmon blocks, we can initialize the vector with the number. +//// Collection blocks = new ArrayList<>(numRSBlocks); + +//// for (int i = 0; i < numRSBlocks; ++i) { +//// int[] numDataBytesInBlock = new int[1]; +//// int[] numEcBytesInBlock = new int[1]; +//// getNumDataBytesAndNumECBytesForBlockID( +//// numTotalBytes, numDataBytes, numRSBlocks, i, +//// numDataBytesInBlock, numEcBytesInBlock); + +//// int size = numDataBytesInBlock[0]; +//// byte[] dataBytes = new byte[size]; +//// bits.toBytes(8*dataBytesOffset, dataBytes, 0, size); +//// byte[] ecBytes = generateECBytes(dataBytes, numEcBytesInBlock[0]); +//// blocks.add(new BlockPair(dataBytes, ecBytes)); + +//// maxNumDataBytes = Math.max(maxNumDataBytes, size); +//// maxNumEcBytes = Math.max(maxNumEcBytes, ecBytes.length); +//// dataBytesOffset += numDataBytesInBlock[0]; +//// } +//// if (numDataBytes != dataBytesOffset) { +//// throw new WriterException("Data bytes does not match offset"); +//// } + +//// BitArray result = new BitArray(); + +//// // First, place data blocks. +//// for (int i = 0; i < maxNumDataBytes; ++i) { +//// for (BlockPair block : blocks) { +//// byte[] dataBytes = block.getDataBytes(); +//// if (i < dataBytes.length) { +//// result.appendBits(dataBytes[i], 8); +//// } +//// } +//// } +//// // Then, place error correction blocks. +//// for (int i = 0; i < maxNumEcBytes; ++i) { +//// for (BlockPair block : blocks) { +//// byte[] ecBytes = block.getErrorCorrectionBytes(); +//// if (i < ecBytes.length) { +//// result.appendBits(ecBytes[i], 8); +//// } +//// } +//// } +//// if (numTotalBytes != result.getSizeInBytes()) { // Should be same. +//// throw new WriterException("Interleaving error: " + numTotalBytes + " and " + +//// result.getSizeInBytes() + " differ."); +//// } + +//// return result; +//// } + +//// static byte[] generateECBytes(byte[] dataBytes, int numEcBytesInBlock) { +//// int numDataBytes = dataBytes.length; +//// int[] toEncode = new int[numDataBytes + numEcBytesInBlock]; +//// for (int i = 0; i < numDataBytes; i++) { +//// toEncode[i] = dataBytes[i] & 0xFF; +//// } +//// new ReedSolomonEncoder(GenericGF.QR_CODE_FIELD_256).encode(toEncode, numEcBytesInBlock); + +//// byte[] ecBytes = new byte[numEcBytesInBlock]; +//// for (int i = 0; i < numEcBytesInBlock; i++) { +//// ecBytes[i] = (byte) toEncode[numDataBytes + i]; +//// } +//// return ecBytes; +//// } + +//// /** +//// * Append mode info. On success, store the result in "bits". +//// */ +//// static void appendModeInfo(Mode mode, BitArray bits) { +//// bits.appendBits(mode.getBits(), 4); +//// } + + +//// /** +//// * Append length info. On success, store the result in "bits". +//// */ +//// static void appendLengthInfo(int numLetters, Version version, Mode mode, BitArray bits) throws WriterException { +//// int numBits = mode.getCharacterCountBits(version); +//// if (numLetters >= (1 << numBits)) { +//// throw new WriterException(numLetters + " is bigger than " + ((1 << numBits) - 1)); +//// } +//// bits.appendBits(numLetters, numBits); +//// } + +//// /** +//// * Append "bytes" in "mode" mode (encoding) into "bits". On success, store the result in "bits". +//// */ +//// static void appendBytes(String content, +//// Mode mode, +//// BitArray bits, +//// String encoding) throws WriterException { +//// switch (mode) { +//// case NUMERIC: +//// appendNumericBytes(content, bits); +//// break; +//// case ALPHANUMERIC: +//// appendAlphanumericBytes(content, bits); +//// break; +//// case BYTE: +//// append8BitBytes(content, bits, encoding); +//// break; +//// case KANJI: +//// appendKanjiBytes(content, bits); +//// break; +//// default: +//// throw new WriterException("Invalid mode: " + mode); +//// } +//// } + +//// static void appendNumericBytes(CharSequence content, BitArray bits) { +//// int length = content.length(); +//// int i = 0; +//// while (i < length) { +//// int num1 = content.charAt(i) - '0'; +//// if (i + 2 < length) { +//// // Encode three numeric letters in ten bits. +//// int num2 = content.charAt(i + 1) - '0'; +//// int num3 = content.charAt(i + 2) - '0'; +//// bits.appendBits(num1 * 100 + num2 * 10 + num3, 10); +//// i += 3; +//// } else if (i + 1 < length) { +//// // Encode two numeric letters in seven bits. +//// int num2 = content.charAt(i + 1) - '0'; +//// bits.appendBits(num1 * 10 + num2, 7); +//// i += 2; +//// } else { +//// // Encode one numeric letter in four bits. +//// bits.appendBits(num1, 4); +//// i++; +//// } +//// } +//// } + +//// static void appendAlphanumericBytes(CharSequence content, BitArray bits) throws WriterException { +//// int length = content.length(); +//// int i = 0; +//// while (i < length) { +//// int code1 = getAlphanumericCode(content.charAt(i)); +//// if (code1 == -1) { +//// throw new WriterException(); +//// } +//// if (i + 1 < length) { +//// int code2 = getAlphanumericCode(content.charAt(i + 1)); +//// if (code2 == -1) { +//// throw new WriterException(); +//// } +//// // Encode two alphanumeric letters in 11 bits. +//// bits.appendBits(code1 * 45 + code2, 11); +//// i += 2; +//// } else { +//// // Encode one alphanumeric letter in six bits. +//// bits.appendBits(code1, 6); +//// i++; +//// } +//// } +//// } + +//// static void append8BitBytes(String content, BitArray bits, String encoding) +//// throws WriterException { +//// byte[] bytes; +//// try { +//// bytes = content.getBytes(encoding); +//// } catch (UnsupportedEncodingException uee) { +//// throw new WriterException(uee); +//// } +//// for (byte b : bytes) { +//// bits.appendBits(b, 8); +//// } +//// } + +//// static void appendKanjiBytes(String content, BitArray bits) throws WriterException { +//// byte[] bytes; +//// try { +//// bytes = content.getBytes("Shift_JIS"); +//// } catch (UnsupportedEncodingException uee) { +//// throw new WriterException(uee); +//// } +//// int length = bytes.length; +//// for (int i = 0; i < length; i += 2) { +//// int byte1 = bytes[i] & 0xFF; +//// int byte2 = bytes[i + 1] & 0xFF; +//// int code = (byte1 << 8) | byte2; +//// int subtracted = -1; +//// if (code >= 0x8140 && code <= 0x9ffc) { +//// subtracted = code - 0x8140; +//// } else if (code >= 0xe040 && code <= 0xebbf) { +//// subtracted = code - 0xc140; +//// } +//// if (subtracted == -1) { +//// throw new WriterException("Invalid byte sequence"); +//// } +//// int encoded = ((subtracted >> 8) * 0xc0) + (subtracted & 0xff); +//// bits.appendBits(encoded, 13); +//// } +//// } + +//// private static void appendECI(CharacterSetECI eci, BitArray bits) { +//// bits.appendBits(Mode.ECI.getBits(), 4); +//// // This is correct for values up to 127, which is all we need now. +//// bits.appendBits(eci.getValue(), 8); +//// } + +//} +//} diff --git a/source/zxing/zxing/qrcode/encoder/Encoder.h b/source/zxing/zxing/qrcode/encoder/Encoder.h index 8f52451..4dab2cd 100644 --- a/source/zxing/zxing/qrcode/encoder/Encoder.h +++ b/source/zxing/zxing/qrcode/encoder/Encoder.h @@ -1,65 +1,44 @@ -///* -// * Copyright 2008 ZXing authors -// * -// * 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. -// */ +//#ifndef ENCODER_H +//#define ENCODER_H +////package com.google.zxing.qrcode.encoder; -//package com.google.zxing.qrcode.encoder; +////import com.google.zxing.EncodeHintType; +////import com.google.zxing.WriterException; +////import com.google.zxing.common.BitArray; +////import com.google.zxing.common.CharacterSetECI; +////import com.google.zxing.common.reedsolomon.GenericGF; +////import com.google.zxing.common.reedsolomon.ReedSolomonEncoder; +////import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel; +////import com.google.zxing.qrcode.decoder.Mode; +////import com.google.zxing.qrcode.decoder.Version; -//import com.google.zxing.EncodeHintType; -//import com.google.zxing.WriterException; -//import com.google.zxing.common.BitArray; -//import com.google.zxing.common.CharacterSetECI; -//import com.google.zxing.common.reedsolomon.GenericGF; -//import com.google.zxing.common.reedsolomon.ReedSolomonEncoder; -//import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel; -//import com.google.zxing.qrcode.decoder.Mode; -//import com.google.zxing.qrcode.decoder.Version; +////import java.io.UnsupportedEncodingException; +////import java.util.ArrayList; +////import java.util.Collection; +////import java.util.Map; -//import java.io.UnsupportedEncodingException; -//import java.util.ArrayList; -//import java.util.Collection; -//import java.util.Map; +//#include +//#include +//#include +//#include +//#include -///** -// * @author satorux@google.com (Satoru Takabayashi) - creator -// * @author dswitkin@google.com (Daniel Switkin) - ported from C++ -// */ -//public final class Encoder { +//namespace zxing { +//namespace qrcode { -// // The original table is defined in the table 5 of JISX0510:2004 (p.19). -// private static final int[] ALPHANUMERIC_TABLE = { -// -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 0x00-0x0f -// -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 0x10-0x1f -// 36, -1, -1, -1, 37, 38, -1, -1, -1, -1, 39, 40, -1, 41, 42, 43, // 0x20-0x2f -// 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 44, -1, -1, -1, -1, -1, // 0x30-0x3f -// -1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, // 0x40-0x4f -// 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1, // 0x50-0x5f -// }; +//class Encoder { -// static final String DEFAULT_BYTE_MODE_ENCODING = "ISO-8859-1"; +//private: +// static const int ALPHANUMERIC_TABLE[]; +// static const std::string DEFAULT_BYTE_MODE_ENCODING; -// private Encoder() { -// } +// Encoder() {} -// // The mask penalty calculation is complicated. See Table 21 of JISX0510:2004 (p.45) for details. -// // Basically it applies four rules and summate all penalties. -// private static int calculateMaskPenalty(ByteMatrix matrix) { -// return MaskUtil.applyMaskPenaltyRule1(matrix) -// + MaskUtil.applyMaskPenaltyRule2(matrix) -// + MaskUtil.applyMaskPenaltyRule3(matrix) -// + MaskUtil.applyMaskPenaltyRule4(matrix); -// } +// /** +// * The mask penalty calculation is complicated. See Table 21 of JISX0510:2004 (p.45) for details. +// * Basically it applies four rules and summate all penalties. +// */ +// static int calculateMaskPenalty(ByteMatrix matrix); // /** // * Encode "bytes" with the error correction level "ecLevel". The encoding mode will be chosen @@ -72,231 +51,41 @@ // * Note that there is no way to encode bytes in MODE_KANJI. We might want to add EncodeWithMode() // * with which clients can specify the encoding mode. For now, we don't need the functionality. // */ -// public static QRCode encode(String content, ErrorCorrectionLevel ecLevel) throws WriterException { -// return encode(content, ecLevel, null); -// } +//public: +// static QRCode encode(std::string content, ErrorCorrectionLevel ecLevel); -// public static QRCode encode(String content, -// ErrorCorrectionLevel ecLevel, -// Map hints) throws WriterException { - -// // Determine what character encoding has been specified by the caller, if any -// String encoding = hints == null ? null : (String) hints.get(EncodeHintType.CHARACTER_SET); -// if (encoding == null) { -// encoding = DEFAULT_BYTE_MODE_ENCODING; -// } - -// // Pick an encoding mode appropriate for the content. Note that this will not attempt to use -// // multiple modes / segments even if that were more efficient. Twould be nice. -// Mode mode = chooseMode(content, encoding); - -// // This will store the header information, like mode and -// // length, as well as "header" segments like an ECI segment. -// BitArray headerBits = new BitArray(); - -// // Append ECI segment if applicable -// if (mode == Mode.BYTE && !DEFAULT_BYTE_MODE_ENCODING.equals(encoding)) { -// CharacterSetECI eci = CharacterSetECI.getCharacterSetECIByName(encoding); -// if (eci != null) { -// appendECI(eci, headerBits); -// } -// } - -// // (With ECI in place,) Write the mode marker -// appendModeInfo(mode, headerBits); - -// // Collect data within the main segment, separately, to count its size if needed. Don't add it to -// // main payload yet. -// BitArray dataBits = new BitArray(); -// appendBytes(content, mode, dataBits, encoding); - -// // Hard part: need to know version to know how many bits length takes. But need to know how many -// // bits it takes to know version. First we take a guess at version by assuming version will be -// // the minimum, 1: - -// int provisionalBitsNeeded = headerBits.getSize() -// + mode.getCharacterCountBits(Version.getVersionForNumber(1)) -// + dataBits.getSize(); -// Version provisionalVersion = chooseVersion(provisionalBitsNeeded, ecLevel); - -// // Use that guess to calculate the right version. I am still not sure this works in 100% of cases. - -// int bitsNeeded = headerBits.getSize() -// + mode.getCharacterCountBits(provisionalVersion) -// + dataBits.getSize(); -// Version version = chooseVersion(bitsNeeded, ecLevel); - -// BitArray headerAndDataBits = new BitArray(); -// headerAndDataBits.appendBitArray(headerBits); -// // Find "length" of main segment and write it -// int numLetters = mode == Mode.BYTE ? dataBits.getSizeInBytes() : content.length(); -// appendLengthInfo(numLetters, version, mode, headerAndDataBits); -// // Put data together into the overall payload -// headerAndDataBits.appendBitArray(dataBits); - -// Version.ECBlocks ecBlocks = version.getECBlocksForLevel(ecLevel); -// int numDataBytes = version.getTotalCodewords() - ecBlocks.getTotalECCodewords(); - -// // Terminate the bits properly. -// terminateBits(numDataBytes, headerAndDataBits); - -// // Interleave data bits with error correction code. -// BitArray finalBits = interleaveWithECBytes(headerAndDataBits, -// version.getTotalCodewords(), -// numDataBytes, -// ecBlocks.getNumBlocks()); - -// QRCode qrCode = new QRCode(); - -// qrCode.setECLevel(ecLevel); -// qrCode.setMode(mode); -// qrCode.setVersion(version); - -// // Choose the mask pattern and set to "qrCode". -// int dimension = version.getDimensionForVersion(); -// ByteMatrix matrix = new ByteMatrix(dimension, dimension); -// int maskPattern = chooseMaskPattern(finalBits, ecLevel, version, matrix); -// qrCode.setMaskPattern(maskPattern); - -// // Build the matrix and set it to "qrCode". -// MatrixUtil.buildMatrix(finalBits, ecLevel, version, maskPattern, matrix); -// qrCode.setMatrix(matrix); - -// return qrCode; -// } +// static QRCode encode(String content, ErrorCorrectionLevel ecLevel/*, +// Map hints*/); // /** // * @return the code point of the table used in alphanumeric mode or // * -1 if there is no corresponding code in the table. // */ -// static int getAlphanumericCode(int code) { -// if (code < ALPHANUMERIC_TABLE.length) { -// return ALPHANUMERIC_TABLE[code]; -// } -// return -1; -// } +// static int getAlphanumericCode(int code); -// public static Mode chooseMode(String content) { -// return chooseMode(content, null); -// } +// static Mode chooseMode(String content); // /** // * Choose the best mode by examining the content. Note that 'encoding' is used as a hint; // * if it is Shift_JIS, and the input is only double-byte Kanji, then we return {@link Mode#KANJI}. // */ -// private static Mode chooseMode(String content, String encoding) { -// if ("Shift_JIS".equals(encoding)) { -// // Choose Kanji mode if all input are double-byte characters -// return isOnlyDoubleByteKanji(content) ? Mode.KANJI : Mode.BYTE; -// } -// boolean hasNumeric = false; -// boolean hasAlphanumeric = false; -// for (int i = 0; i < content.length(); ++i) { -// char c = content.charAt(i); -// if (c >= '0' && c <= '9') { -// hasNumeric = true; -// } else if (getAlphanumericCode(c) != -1) { -// hasAlphanumeric = true; -// } else { -// return Mode.BYTE; -// } -// } -// if (hasAlphanumeric) { -// return Mode.ALPHANUMERIC; -// } -// if (hasNumeric) { -// return Mode.NUMERIC; -// } -// return Mode.BYTE; -// } +//private: +// static Mode chooseMode(std::string content, std::string encoding); -// private static boolean isOnlyDoubleByteKanji(String content) { -// byte[] bytes; -// try { -// bytes = content.getBytes("Shift_JIS"); -// } catch (UnsupportedEncodingException ignored) { -// return false; -// } -// int length = bytes.length; -// if (length % 2 != 0) { -// return false; -// } -// for (int i = 0; i < length; i += 2) { -// int byte1 = bytes[i] & 0xFF; -// if ((byte1 < 0x81 || byte1 > 0x9F) && (byte1 < 0xE0 || byte1 > 0xEB)) { -// return false; -// } -// } -// return true; -// } +// static boolean isOnlyDoubleByteKanji(std::string content); -// private static int chooseMaskPattern(BitArray bits, +// static int chooseMaskPattern(BitArray bits, // ErrorCorrectionLevel ecLevel, // Version version, -// ByteMatrix matrix) throws WriterException { +// ByteMatrix matrix); -// int minPenalty = Integer.MAX_VALUE; // Lower penalty is better. -// int bestMaskPattern = -1; -// // We try all mask patterns to choose the best one. -// for (int maskPattern = 0; maskPattern < QRCode.NUM_MASK_PATTERNS; maskPattern++) { -// MatrixUtil.buildMatrix(bits, ecLevel, version, maskPattern, matrix); -// int penalty = calculateMaskPenalty(matrix); -// if (penalty < minPenalty) { -// minPenalty = penalty; -// bestMaskPattern = maskPattern; -// } -// } -// return bestMaskPattern; -// } - -// private static Version chooseVersion(int numInputBits, ErrorCorrectionLevel ecLevel) throws WriterException { -// // In the following comments, we use numbers of Version 7-H. -// for (int versionNum = 1; versionNum <= 40; versionNum++) { -// Version version = Version.getVersionForNumber(versionNum); -// // numBytes = 196 -// int numBytes = version.getTotalCodewords(); -// // getNumECBytes = 130 -// Version.ECBlocks ecBlocks = version.getECBlocksForLevel(ecLevel); -// int numEcBytes = ecBlocks.getTotalECCodewords(); -// // getNumDataBytes = 196 - 130 = 66 -// int numDataBytes = numBytes - numEcBytes; -// int totalInputBytes = (numInputBits + 7) / 8; -// if (numDataBytes >= totalInputBytes) { -// return version; -// } -// } -// throw new WriterException("Data too big"); -// } +// static Version chooseVersion(int numInputBits, ErrorCorrectionLevel ecLevel) ; // /** // * Terminate bits as described in 8.4.8 and 8.4.9 of JISX0510:2004 (p.24). // */ -// static void terminateBits(int numDataBytes, BitArray bits) throws WriterException { -// int capacity = numDataBytes << 3; -// if (bits.getSize() > capacity) { -// throw new WriterException("data bits cannot fit in the QR Code" + bits.getSize() + " > " + -// capacity); -// } -// for (int i = 0; i < 4 && bits.getSize() < capacity; ++i) { -// bits.appendBit(false); -// } -// // Append termination bits. See 8.4.8 of JISX0510:2004 (p.24) for details. -// // If the last byte isn't 8-bit aligned, we'll add padding bits. -// int numBitsInLastByte = bits.getSize() & 0x07; -// if (numBitsInLastByte > 0) { -// for (int i = numBitsInLastByte; i < 8; i++) { -// bits.appendBit(false); -// } -// } -// // If we have more space, we'll fill the space with padding patterns defined in 8.4.9 (p.24). -// int numPaddingBytes = numDataBytes - bits.getSizeInBytes(); -// for (int i = 0; i < numPaddingBytes; ++i) { -// bits.appendBits((i & 0x01) == 0 ? 0xEC : 0x11, 8); -// } -// if (bits.getSize() != capacity) { -// throw new WriterException("Bits size does not equal capacity"); -// } -// } +//protected: +// static void terminateBits(int numDataBytes, BitArray bits); // /** // * Get number of data bytes and number of error correction bytes for block id "blockID". Store @@ -307,53 +96,8 @@ // int numDataBytes, // int numRSBlocks, // int blockID, -// int[] numDataBytesInBlock, -// int[] numECBytesInBlock) throws WriterException { -// if (blockID >= numRSBlocks) { -// throw new WriterException("Block ID too large"); -// } -// // numRsBlocksInGroup2 = 196 % 5 = 1 -// int numRsBlocksInGroup2 = numTotalBytes % numRSBlocks; -// // numRsBlocksInGroup1 = 5 - 1 = 4 -// int numRsBlocksInGroup1 = numRSBlocks - numRsBlocksInGroup2; -// // numTotalBytesInGroup1 = 196 / 5 = 39 -// int numTotalBytesInGroup1 = numTotalBytes / numRSBlocks; -// // numTotalBytesInGroup2 = 39 + 1 = 40 -// int numTotalBytesInGroup2 = numTotalBytesInGroup1 + 1; -// // numDataBytesInGroup1 = 66 / 5 = 13 -// int numDataBytesInGroup1 = numDataBytes / numRSBlocks; -// // numDataBytesInGroup2 = 13 + 1 = 14 -// int numDataBytesInGroup2 = numDataBytesInGroup1 + 1; -// // numEcBytesInGroup1 = 39 - 13 = 26 -// int numEcBytesInGroup1 = numTotalBytesInGroup1 - numDataBytesInGroup1; -// // numEcBytesInGroup2 = 40 - 14 = 26 -// int numEcBytesInGroup2 = numTotalBytesInGroup2 - numDataBytesInGroup2; -// // Sanity checks. -// // 26 = 26 -// if (numEcBytesInGroup1 != numEcBytesInGroup2) { -// throw new WriterException("EC bytes mismatch"); -// } -// // 5 = 4 + 1. -// if (numRSBlocks != numRsBlocksInGroup1 + numRsBlocksInGroup2) { -// throw new WriterException("RS blocks mismatch"); -// } -// // 196 = (13 + 26) * 4 + (14 + 26) * 1 -// if (numTotalBytes != -// ((numDataBytesInGroup1 + numEcBytesInGroup1) * -// numRsBlocksInGroup1) + -// ((numDataBytesInGroup2 + numEcBytesInGroup2) * -// numRsBlocksInGroup2)) { -// throw new WriterException("Total bytes mismatch"); -// } - -// if (blockID < numRsBlocksInGroup1) { -// numDataBytesInBlock[0] = numDataBytesInGroup1; -// numECBytesInBlock[0] = numEcBytesInGroup1; -// } else { -// numDataBytesInBlock[0] = numDataBytesInGroup2; -// numECBytesInBlock[0] = numEcBytesInGroup2; -// } -// } +// int numDataBytesInBlock[], +// int numECBytesInBlock[]); // /** // * Interleave "bits" with corresponding error correction bytes. On success, store the result in @@ -362,221 +106,43 @@ // static BitArray interleaveWithECBytes(BitArray bits, // int numTotalBytes, // int numDataBytes, -// int numRSBlocks) throws WriterException { +// int numRSBlocks); -// // "bits" must have "getNumDataBytes" bytes of data. -// if (bits.getSizeInBytes() != numDataBytes) { -// throw new WriterException("Number of bits and data bytes does not match"); -// } - -// // Step 1. Divide data bytes into blocks and generate error correction bytes for them. We'll -// // store the divided data bytes blocks and error correction bytes blocks into "blocks". -// int dataBytesOffset = 0; -// int maxNumDataBytes = 0; -// int maxNumEcBytes = 0; - -// // Since, we know the number of reedsolmon blocks, we can initialize the vector with the number. -// Collection blocks = new ArrayList<>(numRSBlocks); - -// for (int i = 0; i < numRSBlocks; ++i) { -// int[] numDataBytesInBlock = new int[1]; -// int[] numEcBytesInBlock = new int[1]; -// getNumDataBytesAndNumECBytesForBlockID( -// numTotalBytes, numDataBytes, numRSBlocks, i, -// numDataBytesInBlock, numEcBytesInBlock); - -// int size = numDataBytesInBlock[0]; -// byte[] dataBytes = new byte[size]; -// bits.toBytes(8*dataBytesOffset, dataBytes, 0, size); -// byte[] ecBytes = generateECBytes(dataBytes, numEcBytesInBlock[0]); -// blocks.add(new BlockPair(dataBytes, ecBytes)); - -// maxNumDataBytes = Math.max(maxNumDataBytes, size); -// maxNumEcBytes = Math.max(maxNumEcBytes, ecBytes.length); -// dataBytesOffset += numDataBytesInBlock[0]; -// } -// if (numDataBytes != dataBytesOffset) { -// throw new WriterException("Data bytes does not match offset"); -// } - -// BitArray result = new BitArray(); - -// // First, place data blocks. -// for (int i = 0; i < maxNumDataBytes; ++i) { -// for (BlockPair block : blocks) { -// byte[] dataBytes = block.getDataBytes(); -// if (i < dataBytes.length) { -// result.appendBits(dataBytes[i], 8); -// } -// } -// } -// // Then, place error correction blocks. -// for (int i = 0; i < maxNumEcBytes; ++i) { -// for (BlockPair block : blocks) { -// byte[] ecBytes = block.getErrorCorrectionBytes(); -// if (i < ecBytes.length) { -// result.appendBits(ecBytes[i], 8); -// } -// } -// } -// if (numTotalBytes != result.getSizeInBytes()) { // Should be same. -// throw new WriterException("Interleaving error: " + numTotalBytes + " and " + -// result.getSizeInBytes() + " differ."); -// } - -// return result; -// } - -// static byte[] generateECBytes(byte[] dataBytes, int numEcBytesInBlock) { -// int numDataBytes = dataBytes.length; -// int[] toEncode = new int[numDataBytes + numEcBytesInBlock]; -// for (int i = 0; i < numDataBytes; i++) { -// toEncode[i] = dataBytes[i] & 0xFF; -// } -// new ReedSolomonEncoder(GenericGF.QR_CODE_FIELD_256).encode(toEncode, numEcBytesInBlock); - -// byte[] ecBytes = new byte[numEcBytesInBlock]; -// for (int i = 0; i < numEcBytesInBlock; i++) { -// ecBytes[i] = (byte) toEncode[numDataBytes + i]; -// } -// return ecBytes; -// } +// static std::vector generateECBytes(const std::vector& dataBytes[], int numEcBytesInBlock); // /** // * Append mode info. On success, store the result in "bits". // */ -// static void appendModeInfo(Mode mode, BitArray bits) { -// bits.appendBits(mode.getBits(), 4); -// } +// static void appendModeInfo(Mode mode, BitArray bits); // /** // * Append length info. On success, store the result in "bits". // */ -// static void appendLengthInfo(int numLetters, Version version, Mode mode, BitArray bits) throws WriterException { -// int numBits = mode.getCharacterCountBits(version); -// if (numLetters >= (1 << numBits)) { -// throw new WriterException(numLetters + " is bigger than " + ((1 << numBits) - 1)); -// } -// bits.appendBits(numLetters, numBits); -// } +// static void appendLengthInfo(int numLetters, Version version, Mode mode, BitArray bits); // /** // * Append "bytes" in "mode" mode (encoding) into "bits". On success, store the result in "bits". // */ -// static void appendBytes(String content, +// static void appendBytes(std::string content, // Mode mode, // BitArray bits, -// String encoding) throws WriterException { -// switch (mode) { -// case NUMERIC: -// appendNumericBytes(content, bits); -// break; -// case ALPHANUMERIC: -// appendAlphanumericBytes(content, bits); -// break; -// case BYTE: -// append8BitBytes(content, bits, encoding); -// break; -// case KANJI: -// appendKanjiBytes(content, bits); -// break; -// default: -// throw new WriterException("Invalid mode: " + mode); -// } -// } +// std::string encoding); -// static void appendNumericBytes(CharSequence content, BitArray bits) { -// int length = content.length(); -// int i = 0; -// while (i < length) { -// int num1 = content.charAt(i) - '0'; -// if (i + 2 < length) { -// // Encode three numeric letters in ten bits. -// int num2 = content.charAt(i + 1) - '0'; -// int num3 = content.charAt(i + 2) - '0'; -// bits.appendBits(num1 * 100 + num2 * 10 + num3, 10); -// i += 3; -// } else if (i + 1 < length) { -// // Encode two numeric letters in seven bits. -// int num2 = content.charAt(i + 1) - '0'; -// bits.appendBits(num1 * 10 + num2, 7); -// i += 2; -// } else { -// // Encode one numeric letter in four bits. -// bits.appendBits(num1, 4); -// i++; -// } -// } -// } +// static void appendNumericBytes( const std::vector& content, BitArray bits); -// static void appendAlphanumericBytes(CharSequence content, BitArray bits) throws WriterException { -// int length = content.length(); -// int i = 0; -// while (i < length) { -// int code1 = getAlphanumericCode(content.charAt(i)); -// if (code1 == -1) { -// throw new WriterException(); -// } -// if (i + 1 < length) { -// int code2 = getAlphanumericCode(content.charAt(i + 1)); -// if (code2 == -1) { -// throw new WriterException(); -// } -// // Encode two alphanumeric letters in 11 bits. -// bits.appendBits(code1 * 45 + code2, 11); -// i += 2; -// } else { -// // Encode one alphanumeric letter in six bits. -// bits.appendBits(code1, 6); -// i++; -// } -// } -// } +// static void appendAlphanumericBytes(const std::vector& content, BitArray bits); -// static void append8BitBytes(String content, BitArray bits, String encoding) -// throws WriterException { -// byte[] bytes; -// try { -// bytes = content.getBytes(encoding); -// } catch (UnsupportedEncodingException uee) { -// throw new WriterException(uee); -// } -// for (byte b : bytes) { -// bits.appendBits(b, 8); -// } -// } +// static void append8BitBytes(std::string content, BitArray bits, std::string encoding); -// static void appendKanjiBytes(String content, BitArray bits) throws WriterException { -// byte[] bytes; -// try { -// bytes = content.getBytes("Shift_JIS"); -// } catch (UnsupportedEncodingException uee) { -// throw new WriterException(uee); -// } -// int length = bytes.length; -// for (int i = 0; i < length; i += 2) { -// int byte1 = bytes[i] & 0xFF; -// int byte2 = bytes[i + 1] & 0xFF; -// int code = (byte1 << 8) | byte2; -// int subtracted = -1; -// if (code >= 0x8140 && code <= 0x9ffc) { -// subtracted = code - 0x8140; -// } else if (code >= 0xe040 && code <= 0xebbf) { -// subtracted = code - 0xc140; -// } -// if (subtracted == -1) { -// throw new WriterException("Invalid byte sequence"); -// } -// int encoded = ((subtracted >> 8) * 0xc0) + (subtracted & 0xff); -// bits.appendBits(encoded, 13); -// } -// } +// static void appendKanjiBytes(std::string content, BitArray bits); -// private static void appendECI(CharacterSetECI eci, BitArray bits) { -// bits.appendBits(Mode.ECI.getBits(), 4); -// // This is correct for values up to 127, which is all we need now. -// bits.appendBits(eci.getValue(), 8); -// } +//private: +// static void appendECI(zxing::common::CharacterSetECI eci, BitArray bits); //} + +//} +//} + +//#endif // ENCODER_H diff --git a/source/zxing/zxing/qrcode/encoder/MaskUtil.cpp b/source/zxing/zxing/qrcode/encoder/MaskUtil.cpp index e69de29..470f3df 100644 --- a/source/zxing/zxing/qrcode/encoder/MaskUtil.cpp +++ b/source/zxing/zxing/qrcode/encoder/MaskUtil.cpp @@ -0,0 +1,204 @@ +#include "MaskUtil.h" +#include +#include + +namespace zxing { +namespace qrcode { + +// Penalty weights from section 6.8.2.1 +const int MaskUtil::N1 = 3; +const int MaskUtil::N2 = 3; +const int MaskUtil::N3 = 40; +const int MaskUtil::N4 = 10; + +/** + * Apply mask penalty rule 1 and return the penalty. Find repetitive cells with the same color and + * give penalty to them. Example: 00000 or 11111. + */ +int MaskUtil::applyMaskPenaltyRule1(const ByteMatrix& matrix) +{ + return applyMaskPenaltyRule1Internal(matrix, true) + applyMaskPenaltyRule1Internal(matrix, false); +} + +/** + * Apply mask penalty rule 2 and return the penalty. Find 2x2 blocks with the same color and give + * penalty to them. This is actually equivalent to the spec's rule, which is to find MxN blocks and give a + * penalty proportional to (M-1)x(N-1), because this is the number of 2x2 blocks inside such a block. + */ +int MaskUtil::applyMaskPenaltyRule2(const ByteMatrix& matrix) +{ + int penalty = 0; + const std::vector >& array = matrix.getArray(); + int width = matrix.getWidth(); + int height = matrix.getHeight(); + for (int y = 0; y < height - 1; y++) { + for (int x = 0; x < width - 1; x++) { + int value = array[y][x]; + if (value == array[y][x + 1] && value == array[y + 1][x] && value == array[y + 1][x + 1]) { + penalty++; + } + } + } + return N2 * penalty; +} + +/** + * Apply mask penalty rule 3 and return the penalty. Find consecutive runs of 1:1:3:1:1:4 + * starting with black, or 4:1:1:3:1:1 starting with white, and give penalty to them. If we + * find patterns like 000010111010000, we give penalty once. + */ +int MaskUtil::applyMaskPenaltyRule3(const ByteMatrix& matrix) +{ + int numPenalties = 0; + const std::vector >& array = matrix.getArray(); + int width = matrix.getWidth(); + int height = matrix.getHeight(); + for (int y = 0; y < height; y++) { + for (int x = 0; x < width; x++) { + const std::vector& arrayY = array[y]; // We can at least optimize this access + if (x + 6 < width && + arrayY[x] == 1 && + arrayY[x + 1] == 0 && + arrayY[x + 2] == 1 && + arrayY[x + 3] == 1 && + arrayY[x + 4] == 1 && + arrayY[x + 5] == 0 && + arrayY[x + 6] == 1 && + (isWhiteHorizontal(arrayY, x - 4, x) || isWhiteHorizontal(arrayY, x + 7, x + 11))) { + numPenalties++; + } + if (y + 6 < height && + array[y][x] == 1 && + array[y + 1][x] == 0 && + array[y + 2][x] == 1 && + array[y + 3][x] == 1 && + array[y + 4][x] == 1 && + array[y + 5][x] == 0 && + array[y + 6][x] == 1 && + (isWhiteVertical(array, x, y - 4, y) || isWhiteVertical(array, x, y + 7, y + 11))) { + numPenalties++; + } + } + } + return numPenalties * N3; +} + +bool MaskUtil::isWhiteHorizontal(const std::vector& rowArray, int from, int to) +{ + for (int i = from; i < to; i++) { + if (i >= 0 && i < rowArray.size() && rowArray[i] == 1) { + return false; + } + } + return true; +} + +bool MaskUtil::isWhiteVertical(const std::vector >& array, int col, int from, int to) +{ + for (int i = from; i < to; i++) { + if (i >= 0 && i < array.size() && array[i][col] == 1) { + return false; + } + } + return true; +} + +/** + * Apply mask penalty rule 4 and return the penalty. Calculate the ratio of dark cells and give + * penalty if the ratio is far from 50%. It gives 10 penalty for 5% distance. + */ +int MaskUtil::applyMaskPenaltyRule4(const ByteMatrix& matrix) +{ + int numDarkCells = 0; + const std::vector >& array = matrix.getArray(); + int width = matrix.getWidth(); + int height = matrix.getHeight(); + for (int y = 0; y < height; y++) { + const std::vector& arrayY = array[y]; + for (size_t x = 0; x < width; x++) { + if (arrayY[x] == 1) { + numDarkCells++; + } + } + } + int numTotalCells = matrix.getHeight() * matrix.getWidth(); + int fivePercentVariances = abs(numDarkCells * 2 - numTotalCells) * 10 / numTotalCells; + return fivePercentVariances * N4; +} + +/** + * Return the mask bit for "getMaskPattern" at "x" and "y". See 8.8 of JISX0510:2004 for mask + * pattern conditions. + */ +bool MaskUtil::getDataMaskBit(int maskPattern, int x, int y) +{ + int intermediate; + int temp; + switch (maskPattern) { + case 0: + intermediate = (y + x) & 0x1; + break; + case 1: + intermediate = y & 0x1; + break; + case 2: + intermediate = x % 3; + break; + case 3: + intermediate = (y + x) % 3; + break; + case 4: + intermediate = (((unsigned int)y >> (unsigned int)1) + (x / 3)) & 0x1; + break; + case 5: + temp = y * x; + intermediate = (temp & 0x1) + (temp % 3); + break; + case 6: + temp = y * x; + intermediate = ((temp & 0x1) + (temp % 3)) & 0x1; + break; + case 7: + temp = y * x; + intermediate = ((temp % 3) + ((y + x) & 0x1)) & 0x1; + break; + default: + throw new IllegalArgumentException("Invalid mask pattern: " + maskPattern); + } + return intermediate == 0; +} + +/** + * Helper function for applyMaskPenaltyRule1. We need this for doing this calculation in both + * vertical and horizontal orders respectively. + */ +int MaskUtil::applyMaskPenaltyRule1Internal(const ByteMatrix& matrix, bool isHorizontal) +{ + int penalty = 0; + int iLimit = isHorizontal ? matrix.getHeight() : matrix.getWidth(); + int jLimit = isHorizontal ? matrix.getWidth() : matrix.getHeight(); + const std::vector >& array = matrix.getArray(); + for (size_t i = 0; i < iLimit; i++) { + int numSameBitCells = 0; + int prevBit = -1; + for (int j = 0; j < jLimit; j++) { + int bit = isHorizontal ? array[i][j] : array[j][i]; + if (bit == prevBit) { + numSameBitCells++; + } else { + if (numSameBitCells >= 5) { + penalty += N1 + (numSameBitCells - 5); + } + numSameBitCells = 1; // Include the cell itself. + prevBit = bit; + } + } + if (numSameBitCells >= 5) { + penalty += N1 + (numSameBitCells - 5); + } + } + return penalty; +} + +} +} diff --git a/source/zxing/zxing/qrcode/encoder/MaskUtil.h b/source/zxing/zxing/qrcode/encoder/MaskUtil.h index e7d0b5a..c0ca286 100644 --- a/source/zxing/zxing/qrcode/encoder/MaskUtil.h +++ b/source/zxing/zxing/qrcode/encoder/MaskUtil.h @@ -1,217 +1,70 @@ -///* -// * Copyright 2008 ZXing authors -// * -// * 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. -// */ +#ifndef MASKUTIL_H +#define MASKUTIL_H -//package com.google.zxing.qrcode.encoder; +#include "ByteMatrix.h" +#include -///** -// * @author Satoru Takabayashi -// * @author Daniel Switkin -// * @author Sean Owen -// */ -//final class MaskUtil { +namespace zxing { +namespace qrcode { -// // Penalty weights from section 6.8.2.1 -// private static final int N1 = 3; -// private static final int N2 = 3; -// private static final int N3 = 40; -// private static final int N4 = 10; +class MaskUtil { -// private MaskUtil() { -// // do nothing -// } +private: + static const int N1; + static const int N2; + static const int N3; + static const int N4; -// /** -// * Apply mask penalty rule 1 and return the penalty. Find repetitive cells with the same color and -// * give penalty to them. Example: 00000 or 11111. -// */ -// static int applyMaskPenaltyRule1(ByteMatrix matrix) { -// return applyMaskPenaltyRule1Internal(matrix, true) + applyMaskPenaltyRule1Internal(matrix, false); -// } + MaskUtil() {} -// /** -// * Apply mask penalty rule 2 and return the penalty. Find 2x2 blocks with the same color and give -// * penalty to them. This is actually equivalent to the spec's rule, which is to find MxN blocks and give a -// * penalty proportional to (M-1)x(N-1), because this is the number of 2x2 blocks inside such a block. -// */ -// static int applyMaskPenaltyRule2(ByteMatrix matrix) { -// int penalty = 0; -// byte[][] array = matrix.getArray(); -// int width = matrix.getWidth(); -// int height = matrix.getHeight(); -// for (int y = 0; y < height - 1; y++) { -// for (int x = 0; x < width - 1; x++) { -// int value = array[y][x]; -// if (value == array[y][x + 1] && value == array[y + 1][x] && value == array[y + 1][x + 1]) { -// penalty++; -// } -// } -// } -// return N2 * penalty; -// } + /** + * Apply mask penalty rule 1 and return the penalty. Find repetitive cells with the same color and + * give penalty to them. Example: 00000 or 11111. + */ + static int applyMaskPenaltyRule1(const ByteMatrix& matrix); -// /** -// * Apply mask penalty rule 3 and return the penalty. Find consecutive runs of 1:1:3:1:1:4 -// * starting with black, or 4:1:1:3:1:1 starting with white, and give penalty to them. If we -// * find patterns like 000010111010000, we give penalty once. -// */ -// static int applyMaskPenaltyRule3(ByteMatrix matrix) { -// int numPenalties = 0; -// byte[][] array = matrix.getArray(); -// int width = matrix.getWidth(); -// int height = matrix.getHeight(); -// for (int y = 0; y < height; y++) { -// for (int x = 0; x < width; x++) { -// byte[] arrayY = array[y]; // We can at least optimize this access -// if (x + 6 < width && -// arrayY[x] == 1 && -// arrayY[x + 1] == 0 && -// arrayY[x + 2] == 1 && -// arrayY[x + 3] == 1 && -// arrayY[x + 4] == 1 && -// arrayY[x + 5] == 0 && -// arrayY[x + 6] == 1 && -// (isWhiteHorizontal(arrayY, x - 4, x) || isWhiteHorizontal(arrayY, x + 7, x + 11))) { -// numPenalties++; -// } -// if (y + 6 < height && -// array[y][x] == 1 && -// array[y + 1][x] == 0 && -// array[y + 2][x] == 1 && -// array[y + 3][x] == 1 && -// array[y + 4][x] == 1 && -// array[y + 5][x] == 0 && -// array[y + 6][x] == 1 && -// (isWhiteVertical(array, x, y - 4, y) || isWhiteVertical(array, x, y + 7, y + 11))) { -// numPenalties++; -// } -// } -// } -// return numPenalties * N3; -// } + /** + * Apply mask penalty rule 2 and return the penalty. Find 2x2 blocks with the same color and give + * penalty to them. This is actually equivalent to the spec's rule, which is to find MxN blocks and give a + * penalty proportional to (M-1)x(N-1), because this is the number of 2x2 blocks inside such a block. + */ + static int applyMaskPenaltyRule2(const ByteMatrix& matrix); -// private static boolean isWhiteHorizontal(byte[] rowArray, int from, int to) { -// for (int i = from; i < to; i++) { -// if (i >= 0 && i < rowArray.length && rowArray[i] == 1) { -// return false; -// } -// } -// return true; -// } + /** + * Apply mask penalty rule 3 and return the penalty. Find consecutive runs of 1:1:3:1:1:4 + * starting with black, or 4:1:1:3:1:1 starting with white, and give penalty to them. If we + * find patterns like 000010111010000, we give penalty once. + */ + static int applyMaskPenaltyRule3(const ByteMatrix& matrix); -// private static boolean isWhiteVertical(byte[][] array, int col, int from, int to) { -// for (int i = from; i < to; i++) { -// if (i >= 0 && i < array.length && array[i][col] == 1) { -// return false; -// } -// } -// return true; -// } +private: + static bool isWhiteHorizontal(const std::vector& rowArray, int from, int to); -// /** -// * Apply mask penalty rule 4 and return the penalty. Calculate the ratio of dark cells and give -// * penalty if the ratio is far from 50%. It gives 10 penalty for 5% distance. -// */ -// static int applyMaskPenaltyRule4(ByteMatrix matrix) { -// int numDarkCells = 0; -// byte[][] array = matrix.getArray(); -// int width = matrix.getWidth(); -// int height = matrix.getHeight(); -// for (int y = 0; y < height; y++) { -// byte[] arrayY = array[y]; -// for (int x = 0; x < width; x++) { -// if (arrayY[x] == 1) { -// numDarkCells++; -// } -// } -// } -// int numTotalCells = matrix.getHeight() * matrix.getWidth(); -// int fivePercentVariances = Math.abs(numDarkCells * 2 - numTotalCells) * 10 / numTotalCells; -// return fivePercentVariances * N4; -// } + static bool isWhiteVertical(const std::vector >& array, int col, int from, int to); -// /** -// * Return the mask bit for "getMaskPattern" at "x" and "y". See 8.8 of JISX0510:2004 for mask -// * pattern conditions. -// */ -// static boolean getDataMaskBit(int maskPattern, int x, int y) { -// int intermediate; -// int temp; -// switch (maskPattern) { -// case 0: -// intermediate = (y + x) & 0x1; -// break; -// case 1: -// intermediate = y & 0x1; -// break; -// case 2: -// intermediate = x % 3; -// break; -// case 3: -// intermediate = (y + x) % 3; -// break; -// case 4: -// intermediate = ((y >>> 1) + (x / 3)) & 0x1; -// break; -// case 5: -// temp = y * x; -// intermediate = (temp & 0x1) + (temp % 3); -// break; -// case 6: -// temp = y * x; -// intermediate = ((temp & 0x1) + (temp % 3)) & 0x1; -// break; -// case 7: -// temp = y * x; -// intermediate = ((temp % 3) + ((y + x) & 0x1)) & 0x1; -// break; -// default: -// throw new IllegalArgumentException("Invalid mask pattern: " + maskPattern); -// } -// return intermediate == 0; -// } +public: + /** + * Apply mask penalty rule 4 and return the penalty. Calculate the ratio of dark cells and give + * penalty if the ratio is far from 50%. It gives 10 penalty for 5% distance. + */ + static int applyMaskPenaltyRule4(const ByteMatrix& matrix); -// /** -// * Helper function for applyMaskPenaltyRule1. We need this for doing this calculation in both -// * vertical and horizontal orders respectively. -// */ -// private static int applyMaskPenaltyRule1Internal(ByteMatrix matrix, boolean isHorizontal) { -// int penalty = 0; -// int iLimit = isHorizontal ? matrix.getHeight() : matrix.getWidth(); -// int jLimit = isHorizontal ? matrix.getWidth() : matrix.getHeight(); -// byte[][] array = matrix.getArray(); -// for (int i = 0; i < iLimit; i++) { -// int numSameBitCells = 0; -// int prevBit = -1; -// for (int j = 0; j < jLimit; j++) { -// int bit = isHorizontal ? array[i][j] : array[j][i]; -// if (bit == prevBit) { -// numSameBitCells++; -// } else { -// if (numSameBitCells >= 5) { -// penalty += N1 + (numSameBitCells - 5); -// } -// numSameBitCells = 1; // Include the cell itself. -// prevBit = bit; -// } -// } -// if (numSameBitCells >= 5) { -// penalty += N1 + (numSameBitCells - 5); -// } -// } -// return penalty; -// } + /** + * Return the mask bit for "getMaskPattern" at "x" and "y". See 8.8 of JISX0510:2004 for mask + * pattern conditions. + */ + static bool getDataMaskBit(int maskPattern, int x, int y); -//} + /** + * Helper function for applyMaskPenaltyRule1. We need this for doing this calculation in both + * vertical and horizontal orders respectively. + */ +private: + static int applyMaskPenaltyRule1Internal(const ByteMatrix& matrix, bool isHorizontal); + +}; + +} +} + +#endif // MASKUTIL_H diff --git a/source/zxing/zxing/qrcode/encoder/MatrixUtil.cpp b/source/zxing/zxing/qrcode/encoder/MatrixUtil.cpp index e69de29..8497354 100644 --- a/source/zxing/zxing/qrcode/encoder/MatrixUtil.cpp +++ b/source/zxing/zxing/qrcode/encoder/MatrixUtil.cpp @@ -0,0 +1,409 @@ +#include "MatrixUtil.h" +#include "MaskUtil.h" +#include +#include "QRCode.h" + +namespace zxing { +namespace qrcode { + +const int MatrixUtil::POSITION_DETECTION_PATTERN[7][7] = { + {1, 1, 1, 1, 1, 1, 1}, + {1, 0, 0, 0, 0, 0, 1}, + {1, 0, 1, 1, 1, 0, 1}, + {1, 0, 1, 1, 1, 0, 1}, + {1, 0, 1, 1, 1, 0, 1}, + {1, 0, 0, 0, 0, 0, 1}, + {1, 1, 1, 1, 1, 1, 1}, +}; + +const int MatrixUtil::POSITION_ADJUSTMENT_PATTERN[5][5] = { + {1, 1, 1, 1, 1}, + {1, 0, 0, 0, 1}, + {1, 0, 1, 0, 1}, + {1, 0, 0, 0, 1}, + {1, 1, 1, 1, 1}, +}; + +// From Appendix E. Table 1, JIS0510X:2004 (p 71). The table was double-checked by komatsu. +const int MatrixUtil::POSITION_ADJUSTMENT_PATTERN_COORDINATE_TABLE[40][7] = { + {-1, -1, -1, -1, -1, -1, -1}, // Version 1 + { 6, 18, -1, -1, -1, -1, -1}, // Version 2 + { 6, 22, -1, -1, -1, -1, -1}, // Version 3 + { 6, 26, -1, -1, -1, -1, -1}, // Version 4 + { 6, 30, -1, -1, -1, -1, -1}, // Version 5 + { 6, 34, -1, -1, -1, -1, -1}, // Version 6 + { 6, 22, 38, -1, -1, -1, -1}, // Version 7 + { 6, 24, 42, -1, -1, -1, -1}, // Version 8 + { 6, 26, 46, -1, -1, -1, -1}, // Version 9 + { 6, 28, 50, -1, -1, -1, -1}, // Version 10 + { 6, 30, 54, -1, -1, -1, -1}, // Version 11 + { 6, 32, 58, -1, -1, -1, -1}, // Version 12 + { 6, 34, 62, -1, -1, -1, -1}, // Version 13 + { 6, 26, 46, 66, -1, -1, -1}, // Version 14 + { 6, 26, 48, 70, -1, -1, -1}, // Version 15 + { 6, 26, 50, 74, -1, -1, -1}, // Version 16 + { 6, 30, 54, 78, -1, -1, -1}, // Version 17 + { 6, 30, 56, 82, -1, -1, -1}, // Version 18 + { 6, 30, 58, 86, -1, -1, -1}, // Version 19 + { 6, 34, 62, 90, -1, -1, -1}, // Version 20 + { 6, 28, 50, 72, 94, -1, -1}, // Version 21 + { 6, 26, 50, 74, 98, -1, -1}, // Version 22 + { 6, 30, 54, 78, 102, -1, -1}, // Version 23 + { 6, 28, 54, 80, 106, -1, -1}, // Version 24 + { 6, 32, 58, 84, 110, -1, -1}, // Version 25 + { 6, 30, 58, 86, 114, -1, -1}, // Version 26 + { 6, 34, 62, 90, 118, -1, -1}, // Version 27 + { 6, 26, 50, 74, 98, 122, -1}, // Version 28 + { 6, 30, 54, 78, 102, 126, -1}, // Version 29 + { 6, 26, 52, 78, 104, 130, -1}, // Version 30 + { 6, 30, 56, 82, 108, 134, -1}, // Version 31 + { 6, 34, 60, 86, 112, 138, -1}, // Version 32 + { 6, 30, 58, 86, 114, 142, -1}, // Version 33 + { 6, 34, 62, 90, 118, 146, -1}, // Version 34 + { 6, 30, 54, 78, 102, 126, 150}, // Version 35 + { 6, 24, 50, 76, 102, 128, 154}, // Version 36 + { 6, 28, 54, 80, 106, 132, 158}, // Version 37 + { 6, 32, 58, 84, 110, 136, 162}, // Version 38 + { 6, 26, 54, 82, 110, 138, 166}, // Version 39 + { 6, 30, 58, 86, 114, 142, 170}, // Version 40 +}; + +// Type info cells at the left top corner. +const int MatrixUtil::TYPE_INFO_COORDINATES[16][2] = { + {8, 0}, + {8, 1}, + {8, 2}, + {8, 3}, + {8, 4}, + {8, 5}, + {8, 7}, + {8, 8}, + {7, 8}, + {5, 8}, + {4, 8}, + {3, 8}, + {2, 8}, + {1, 8}, + {0, 8}, +}; + +// From Appendix D in JISX0510:2004 (p. 67) +const int MatrixUtil::VERSION_INFO_POLY = 0x1f25; // 1 1111 0010 0101 + +// From Appendix C in JISX0510:2004 (p.65). +const int MatrixUtil::TYPE_INFO_POLY = 0x537; +const int MatrixUtil::TYPE_INFO_MASK_PATTERN = 0x5412; + +void MatrixUtil::buildMatrix(const BitArray& dataBits, + ErrorCorrectionLevel& ecLevel, + Version& version, + int maskPattern, + ByteMatrix& matrix) +{ + clearMatrix(matrix); + embedBasicPatterns(version, matrix); + // Type information appear with any version. + embedTypeInfo(ecLevel, maskPattern, matrix); + // Version info appear if version >= 7. + maybeEmbedVersionInfo(version, matrix); + // Data should be embedded at end. + embedDataBits(dataBits, maskPattern, matrix); +} + +void MatrixUtil::embedBasicPatterns(const Version& version, ByteMatrix& matrix) { + // Let's get started with embedding big squares at corners. + embedPositionDetectionPatternsAndSeparators(matrix); + // Then, embed the dark dot at the left bottom corner. + embedDarkDotAtLeftBottomCorner(matrix); + + // Position adjustment patterns appear if version >= 2. + maybeEmbedPositionAdjustmentPatterns(version, matrix); + // Timing patterns should be embedded after position adj. patterns. + embedTimingPatterns(matrix); +} + +// Embed type information. On success, modify the matrix. +void MatrixUtil::embedTypeInfo(const ErrorCorrectionLevel& ecLevel, int maskPattern, ByteMatrix& matrix) +{ + BitArray typeInfoBits; + makeTypeInfoBits(ecLevel, maskPattern, typeInfoBits); + + for (int i = 0; i < typeInfoBits.getSize(); ++i) { + // Place bits in LSB to MSB order. LSB (least significant bit) is the last value in + // "typeInfoBits". + bool bit = typeInfoBits.get(typeInfoBits.getSize() - 1 - i); + + // Type info bits at the left top corner. See 8.9 of JISX0510:2004 (p.46). + int x1 = TYPE_INFO_COORDINATES[i][0]; + int y1 = TYPE_INFO_COORDINATES[i][1]; + matrix.set(x1, y1, bit); + + if (i < 8) { + // Right top corner. + int x2 = matrix.getWidth() - i - 1; + int y2 = 8; + matrix.set(x2, y2, bit); + } else { + // Left bottom corner. + int x2 = 8; + int y2 = matrix.getHeight() - 7 + (i - 8); + matrix.set(x2, y2, bit); + } + } +} + +void MatrixUtil::maybeEmbedVersionInfo(const Version& version, ByteMatrix& matrix) +{ + if (version.getVersionNumber() < 7) { // Version info is necessary if version >= 7. + return; // Don't need version info. + } + BitArray versionInfoBits; + makeVersionInfoBits(version, versionInfoBits); + + int bitIndex = 6 * 3 - 1; // It will decrease from 17 to 0. + for (int i = 0; i < 6; ++i) { + for (int j = 0; j < 3; ++j) { + // Place bits in LSB (least significant bit) to MSB order. + boolean bit = versionInfoBits.get(bitIndex); + bitIndex--; + // Left bottom corner. + matrix.set(i, matrix.getHeight() - 11 + j, bit); + // Right bottom corner. + matrix.set(matrix.getHeight() - 11 + j, i, bit); + } + } +} + +void MatrixUtil::embedDataBits(const BitArray& dataBits, int maskPattern, ByteMatrix& matrix) +{ + int bitIndex = 0; + int direction = -1; + // Start from the right bottom cell. + int x = matrix.getWidth() - 1; + int y = matrix.getHeight() - 1; + while (x > 0) { + // Skip the vertical timing pattern. + if (x == 6) { + x -= 1; + } + while (y >= 0 && y < matrix.getHeight()) { + for (int i = 0; i < 2; ++i) { + int xx = x - i; + // Skip the cell if it's not empty. + if (!isEmpty(matrix.get(xx, y))) { + continue; + } + boolean bit; + if (bitIndex < dataBits.getSize()) { + bit = dataBits.get(bitIndex); + ++bitIndex; + } else { + // Padding bit. If there is no bit left, we'll fill the left cells with 0, as described + // in 8.4.9 of JISX0510:2004 (p. 24). + bit = false; + } + + // Skip masking if mask_pattern is -1. + if (maskPattern != -1 && MaskUtil::getDataMaskBit(maskPattern, xx, y)) { + bit = !bit; + } + matrix.set(xx, y, bit); + } + y += direction; + } + direction = -direction; // Reverse the direction. + y += direction; + x -= 2; // Move to the left. + } + // All bits should be consumed. + if (bitIndex != dataBits.getSize()) { + throw new zxing::WriterException("Not all bits consumed: " + bitIndex + '/' + dataBits.getSize()); + } +} + +int MatrixUtil::findMSBSet(int value) +{ + int numDigits = 0; + while (value != 0) { + (size_t)value >> 1; // ??value >>>= 1; + ++numDigits; + } + return numDigits; +} + +int MatrixUtil::calculateBCHCode(int value, int poly) +{ + // If poly is "1 1111 0010 0101" (version info poly), msbSetInPoly is 13. We'll subtract 1 + // from 13 to make it 12. + int msbSetInPoly = findMSBSet(poly); + value <<= msbSetInPoly - 1; + // Do the division business using exclusive-or operations. + while (findMSBSet(value) >= msbSetInPoly) { + value ^= poly << (findMSBSet(value) - msbSetInPoly); + } + // Now the "value" is the remainder (i.e. the BCH code) + return value; +} + +// Make bit vector of type information. On success, store the result in "bits" and return true. +// Encode error correction level and mask pattern. See 8.9 of +// JISX0510:2004 (p.45) for details. +void MatrixUtil::makeTypeInfoBits(const ErrorCorrectionLevel& ecLevel, int maskPattern, BitArray& bits) +{ + if (!QRCode::isValidMaskPattern(maskPattern)) { + throw new WriterException("Invalid mask pattern"); + } + int typeInfo = (ecLevel.bits() << 3) | maskPattern; + bits.appendBits(typeInfo, 5); + + int bchCode = calculateBCHCode(typeInfo, TYPE_INFO_POLY); + bits.appendBits(bchCode, 10); + + BitArray maskBits; + maskBits.appendBits(TYPE_INFO_MASK_PATTERN, 15); + bits.xor_(maskBits); + + if (bits.getSize() != 15) { // Just in case. + throw new WriterException("should not happen but we got: " + bits.getSize()); + } +} + +// Make bit vector of version information. On success, store the result in "bits" and return true. +// See 8.10 of JISX0510:2004 (p.45) for details. +void MatrixUtil::makeVersionInfoBits(const Version& version, BitArray& bits) +{ + bits.appendBits(version.getVersionNumber(), 6); + int bchCode = calculateBCHCode(version.getVersionNumber(), VERSION_INFO_POLY); + bits.appendBits(bchCode, 12); + + if (bits.getSize() != 18) { // Just in case. + throw new WriterException("should not happen but we got: " + bits.getSize()); + } +} + +void MatrixUtil::embedTimingPatterns(ByteMatrix& matrix) +{ + // -8 is for skipping position detection patterns (size 7), and two horizontal/vertical + // separation patterns (size 1). Thus, 8 = 7 + 1. + for (size_t i = 8; i < matrix.getWidth() - 8; ++i) { + int bit = (i + 1) % 2; + // Horizontal line. + if (isEmpty(matrix.get(i, 6))) { + matrix.set(i, 6, (char)bit); + } + // Vertical line. + if (isEmpty(matrix.get(6, i))) { + matrix.set(6, i, (char)bit); + } + } +} + +void MatrixUtil::embedDarkDotAtLeftBottomCorner(ByteMatrix& matrix) +{ + if (matrix.get(8, matrix.getHeight() - 8) == 0) { + throw new WriterException(); + } + matrix.set(8, matrix.getHeight() - 8, (char)1); +} + +void MatrixUtil::embedHorizontalSeparationPattern(int xStart, + int yStart, + ByteMatrix& matrix) +{ + for (int x = 0; x < 8; ++x) { + if (!isEmpty(matrix.get(xStart + x, yStart))) { + throw new WriterException(); + } + matrix.set(xStart + x, yStart, (char)0); + } +} + +void MatrixUtil::embedVerticalSeparationPattern(int xStart, + int yStart, + ByteMatrix& matrix) +{ + for (int y = 0; y < 7; ++y) { + if (!isEmpty(matrix.get(xStart, yStart + y))) { + throw new WriterException(); + } + matrix.set(xStart, yStart + y, (char)0); + } +} + +void MatrixUtil::embedPositionAdjustmentPattern(int xStart, int yStart, ByteMatrix& matrix) +{ + for (int y = 0; y < 5; ++y) { + for (int x = 0; x < 5; ++x) { + matrix.set(xStart + x, yStart + y, (char)POSITION_ADJUSTMENT_PATTERN[y][x]); + } + } +} + +void MatrixUtil::embedPositionDetectionPattern(int xStart, int yStart, ByteMatrix& matrix) +{ + for (int y = 0; y < 7; ++y) { + for (int x = 0; x < 7; ++x) { + matrix.set(xStart + x, yStart + y, (char)POSITION_DETECTION_PATTERN[y][x]); + } + } +} + +void MatrixUtil::embedPositionDetectionPatternsAndSeparators(ByteMatrix& matrix) +{ + // Embed three big squares at corners. + int pdpWidth = 7;//need to change this, old version: POSITION_DETECTION_PATTERN[0].length; + // Left top corner. + embedPositionDetectionPattern(0, 0, matrix); + // Right top corner. + embedPositionDetectionPattern(matrix.getWidth() - pdpWidth, 0, matrix); + // Left bottom corner. + embedPositionDetectionPattern(0, matrix.getWidth() - pdpWidth, matrix); + + // Embed horizontal separation patterns around the squares. + int hspWidth = 8; + // Left top corner. + embedHorizontalSeparationPattern(0, hspWidth - 1, matrix); + // Right top corner. + embedHorizontalSeparationPattern(matrix.getWidth() - hspWidth, + hspWidth - 1, matrix); + // Left bottom corner. + embedHorizontalSeparationPattern(0, matrix.getWidth() - hspWidth, matrix); + + // Embed vertical separation patterns around the squares. + int vspSize = 7; + // Left top corner. + embedVerticalSeparationPattern(vspSize, 0, matrix); + // Right top corner. + embedVerticalSeparationPattern(matrix.getHeight() - vspSize - 1, 0, matrix); + // Left bottom corner. + embedVerticalSeparationPattern(vspSize, matrix.getHeight() - vspSize, + matrix); +} + +void MatrixUtil::maybeEmbedPositionAdjustmentPatterns(const Version& version, ByteMatrix& matrix) +{ + if (version.getVersionNumber() < 2) { // The patterns appear if version >= 2 + return; + } + int index = version.getVersionNumber() - 1; + const int *coordinates = POSITION_ADJUSTMENT_PATTERN_COORDINATE_TABLE[index]; + int numCoordinates = 7; //POSITION_ADJUSTMENT_PATTERN_COORDINATE_TABLE[index].length; //need to change the constant 7 + for (int i = 0; i < numCoordinates; ++i) { + for (int j = 0; j < numCoordinates; ++j) { + int y = coordinates[i]; + int x = coordinates[j]; + if (x == -1 || y == -1) { + continue; + } + // If the cell is unset, we embed the position adjustment pattern here. + if (isEmpty(matrix.get(x, y))) { + // -2 is necessary since the x/y coordinates point to the center of the pattern, not the + // left top corner. + embedPositionAdjustmentPattern(x - 2, y - 2, matrix); + } + } + } +} + +} +} diff --git a/source/zxing/zxing/qrcode/encoder/MatrixUtil.h b/source/zxing/zxing/qrcode/encoder/MatrixUtil.h index 458266a..ebb6b89 100644 --- a/source/zxing/zxing/qrcode/encoder/MatrixUtil.h +++ b/source/zxing/zxing/qrcode/encoder/MatrixUtil.h @@ -1,482 +1,142 @@ -///* -// * Copyright 2008 ZXing authors -// * -// * 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. -// */ +#ifndef MATRIXUTIL_H +#define MATRIXUTIL_H //package com.google.zxing.qrcode.encoder; - //import com.google.zxing.WriterException; //import com.google.zxing.common.BitArray; //import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel; //import com.google.zxing.qrcode.decoder.Version; -///** -// * @author satorux@google.com (Satoru Takabayashi) - creator -// * @author dswitkin@google.com (Daniel Switkin) - ported from C++ -// */ -//final class MatrixUtil { +#include "ByteMatrix.h" +#include +#include +#include -// private MatrixUtil() { -// // do nothing -// } +namespace zxing { +namespace qrcode { -// private static final int[][] POSITION_DETECTION_PATTERN = { -// {1, 1, 1, 1, 1, 1, 1}, -// {1, 0, 0, 0, 0, 0, 1}, -// {1, 0, 1, 1, 1, 0, 1}, -// {1, 0, 1, 1, 1, 0, 1}, -// {1, 0, 1, 1, 1, 0, 1}, -// {1, 0, 0, 0, 0, 0, 1}, -// {1, 1, 1, 1, 1, 1, 1}, -// }; +class MatrixUtil { -// private static final int[][] POSITION_ADJUSTMENT_PATTERN = { -// {1, 1, 1, 1, 1}, -// {1, 0, 0, 0, 1}, -// {1, 0, 1, 0, 1}, -// {1, 0, 0, 0, 1}, -// {1, 1, 1, 1, 1}, -// }; +private: + MatrixUtil() {} -// // From Appendix E. Table 1, JIS0510X:2004 (p 71). The table was double-checked by komatsu. -// private static final int[][] POSITION_ADJUSTMENT_PATTERN_COORDINATE_TABLE = { -// {-1, -1, -1, -1, -1, -1, -1}, // Version 1 -// { 6, 18, -1, -1, -1, -1, -1}, // Version 2 -// { 6, 22, -1, -1, -1, -1, -1}, // Version 3 -// { 6, 26, -1, -1, -1, -1, -1}, // Version 4 -// { 6, 30, -1, -1, -1, -1, -1}, // Version 5 -// { 6, 34, -1, -1, -1, -1, -1}, // Version 6 -// { 6, 22, 38, -1, -1, -1, -1}, // Version 7 -// { 6, 24, 42, -1, -1, -1, -1}, // Version 8 -// { 6, 26, 46, -1, -1, -1, -1}, // Version 9 -// { 6, 28, 50, -1, -1, -1, -1}, // Version 10 -// { 6, 30, 54, -1, -1, -1, -1}, // Version 11 -// { 6, 32, 58, -1, -1, -1, -1}, // Version 12 -// { 6, 34, 62, -1, -1, -1, -1}, // Version 13 -// { 6, 26, 46, 66, -1, -1, -1}, // Version 14 -// { 6, 26, 48, 70, -1, -1, -1}, // Version 15 -// { 6, 26, 50, 74, -1, -1, -1}, // Version 16 -// { 6, 30, 54, 78, -1, -1, -1}, // Version 17 -// { 6, 30, 56, 82, -1, -1, -1}, // Version 18 -// { 6, 30, 58, 86, -1, -1, -1}, // Version 19 -// { 6, 34, 62, 90, -1, -1, -1}, // Version 20 -// { 6, 28, 50, 72, 94, -1, -1}, // Version 21 -// { 6, 26, 50, 74, 98, -1, -1}, // Version 22 -// { 6, 30, 54, 78, 102, -1, -1}, // Version 23 -// { 6, 28, 54, 80, 106, -1, -1}, // Version 24 -// { 6, 32, 58, 84, 110, -1, -1}, // Version 25 -// { 6, 30, 58, 86, 114, -1, -1}, // Version 26 -// { 6, 34, 62, 90, 118, -1, -1}, // Version 27 -// { 6, 26, 50, 74, 98, 122, -1}, // Version 28 -// { 6, 30, 54, 78, 102, 126, -1}, // Version 29 -// { 6, 26, 52, 78, 104, 130, -1}, // Version 30 -// { 6, 30, 56, 82, 108, 134, -1}, // Version 31 -// { 6, 34, 60, 86, 112, 138, -1}, // Version 32 -// { 6, 30, 58, 86, 114, 142, -1}, // Version 33 -// { 6, 34, 62, 90, 118, 146, -1}, // Version 34 -// { 6, 30, 54, 78, 102, 126, 150}, // Version 35 -// { 6, 24, 50, 76, 102, 128, 154}, // Version 36 -// { 6, 28, 54, 80, 106, 132, 158}, // Version 37 -// { 6, 32, 58, 84, 110, 136, 162}, // Version 38 -// { 6, 26, 54, 82, 110, 138, 166}, // Version 39 -// { 6, 30, 58, 86, 114, 142, 170}, // Version 40 -// }; + static const int POSITION_DETECTION_PATTERN[7][7]; + static const int POSITION_ADJUSTMENT_PATTERN[5][5]; + static const int POSITION_ADJUSTMENT_PATTERN_COORDINATE_TABLE[40][7]; + static const int TYPE_INFO_COORDINATES[16][2]; + static const int VERSION_INFO_POLY; + static const int TYPE_INFO_POLY; + static const int TYPE_INFO_MASK_PATTERN; -// // Type info cells at the left top corner. -// private static final int[][] TYPE_INFO_COORDINATES = { -// {8, 0}, -// {8, 1}, -// {8, 2}, -// {8, 3}, -// {8, 4}, -// {8, 5}, -// {8, 7}, -// {8, 8}, -// {7, 8}, -// {5, 8}, -// {4, 8}, -// {3, 8}, -// {2, 8}, -// {1, 8}, -// {0, 8}, -// }; + // Set all cells to -1. -1 means that the cell is empty (not set yet). + static void clearMatrix(ByteMatrix& matrix) { + matrix.clear((byte) -1); + } -// // From Appendix D in JISX0510:2004 (p. 67) -// private static final int VERSION_INFO_POLY = 0x1f25; // 1 1111 0010 0101 + // Build 2D matrix of QR Code from "dataBits" with "ecLevel", "version" and "getMaskPattern". On + // success, store the result in "matrix" and return true. + static void buildMatrix(const BitArray& dataBits, + ErrorCorrectionLevel& ecLevel, + Version& version, + int maskPattern, + ByteMatrix& matrix); -// // From Appendix C in JISX0510:2004 (p.65). -// private static final int TYPE_INFO_POLY = 0x537; -// private static final int TYPE_INFO_MASK_PATTERN = 0x5412; + // Embed basic patterns. On success, modify the matrix and return true. + // The basic patterns are: + // - Position detection patterns + // - Timing patterns + // - Dark dot at the left bottom corner + // - Position adjustment patterns, if need be + static void embedBasicPatterns(const Version& version, ByteMatrix& matrix); -// // Set all cells to -1. -1 means that the cell is empty (not set yet). -// // -// // JAVAPORT: We shouldn't need to do this at all. The code should be rewritten to begin encoding -// // with the ByteMatrix initialized all to zero. -// static void clearMatrix(ByteMatrix matrix) { -// matrix.clear((byte) -1); -// } + // Embed type information. On success, modify the matrix. + static void embedTypeInfo(const ErrorCorrectionLevel& ecLevel, int maskPattern, ByteMatrix& matrix); -// // Build 2D matrix of QR Code from "dataBits" with "ecLevel", "version" and "getMaskPattern". On -// // success, store the result in "matrix" and return true. -// static void buildMatrix(BitArray dataBits, -// ErrorCorrectionLevel ecLevel, -// Version version, -// int maskPattern, -// ByteMatrix matrix) throws WriterException { -// clearMatrix(matrix); -// embedBasicPatterns(version, matrix); -// // Type information appear with any version. -// embedTypeInfo(ecLevel, maskPattern, matrix); -// // Version info appear if version >= 7. -// maybeEmbedVersionInfo(version, matrix); -// // Data should be embedded at end. -// embedDataBits(dataBits, maskPattern, matrix); -// } + // Embed version information if need be. On success, modify the matrix and return true. + // See 8.10 of JISX0510:2004 (p.47) for how to embed version information. + static void maybeEmbedVersionInfo(const Version& version, ByteMatrix& matrix); -// // Embed basic patterns. On success, modify the matrix and return true. -// // The basic patterns are: -// // - Position detection patterns -// // - Timing patterns -// // - Dark dot at the left bottom corner -// // - Position adjustment patterns, if need be -// static void embedBasicPatterns(Version version, ByteMatrix matrix) throws WriterException { -// // Let's get started with embedding big squares at corners. -// embedPositionDetectionPatternsAndSeparators(matrix); -// // Then, embed the dark dot at the left bottom corner. -// embedDarkDotAtLeftBottomCorner(matrix); + // Embed "dataBits" using "getMaskPattern". On success, modify the matrix and return true. + // For debugging purposes, it skips masking process if "getMaskPattern" is -1. + // See 8.7 of JISX0510:2004 (p.38) for how to embed data bits. + static void embedDataBits(const BitArray& dataBits, int maskPattern, ByteMatrix& matrix); -// // Position adjustment patterns appear if version >= 2. -// maybeEmbedPositionAdjustmentPatterns(version, matrix); -// // Timing patterns should be embedded after position adj. patterns. -// embedTimingPatterns(matrix); -// } + // Return the position of the most significant bit set (to one) in the "value". The most + // significant bit is position 32. If there is no bit set, return 0. Examples: + // - findMSBSet(0) => 0 + // - findMSBSet(1) => 1 + // - findMSBSet(255) => 8 + static int findMSBSet(int value); -// // Embed type information. On success, modify the matrix. -// static void embedTypeInfo(ErrorCorrectionLevel ecLevel, int maskPattern, ByteMatrix matrix) -// throws WriterException { -// BitArray typeInfoBits = new BitArray(); -// makeTypeInfoBits(ecLevel, maskPattern, typeInfoBits); + // Calculate BCH (Bose-Chaudhuri-Hocquenghem) code for "value" using polynomial "poly". The BCH + // code is used for encoding type information and version information. + // Example: Calculation of version information of 7. + // f(x) is created from 7. + // - 7 = 000111 in 6 bits + // - f(x) = x^2 + x^1 + x^0 + // g(x) is given by the standard (p. 67) + // - g(x) = x^12 + x^11 + x^10 + x^9 + x^8 + x^5 + x^2 + 1 + // Multiply f(x) by x^(18 - 6) + // - f'(x) = f(x) * x^(18 - 6) + // - f'(x) = x^14 + x^13 + x^12 + // Calculate the remainder of f'(x) / g(x) + // x^2 + // __________________________________________________ + // g(x) )x^14 + x^13 + x^12 + // x^14 + x^13 + x^12 + x^11 + x^10 + x^7 + x^4 + x^2 + // -------------------------------------------------- + // x^11 + x^10 + x^7 + x^4 + x^2 + // + // The remainder is x^11 + x^10 + x^7 + x^4 + x^2 + // Encode it in binary: 110010010100 + // The return value is 0xc94 (1100 1001 0100) + // + // Since all coefficients in the polynomials are 1 or 0, we can do the calculation by bit + // operations. We don't care if cofficients are positive or negative. + static int calculateBCHCode(int value, int poly); -// for (int i = 0; i < typeInfoBits.getSize(); ++i) { -// // Place bits in LSB to MSB order. LSB (least significant bit) is the last value in -// // "typeInfoBits". -// boolean bit = typeInfoBits.get(typeInfoBits.getSize() - 1 - i); + // Make bit vector of type information. On success, store the result in "bits" and return true. + // Encode error correction level and mask pattern. See 8.9 of + // JISX0510:2004 (p.45) for details. + static void makeTypeInfoBits(const ErrorCorrectionLevel& ecLevel, int maskPattern, BitArray& bits); -// // Type info bits at the left top corner. See 8.9 of JISX0510:2004 (p.46). -// int x1 = TYPE_INFO_COORDINATES[i][0]; -// int y1 = TYPE_INFO_COORDINATES[i][1]; -// matrix.set(x1, y1, bit); + // Make bit vector of version information. On success, store the result in "bits" and return true. + // See 8.10 of JISX0510:2004 (p.45) for details. + static void makeVersionInfoBits(const Version& version, BitArray& bits); -// if (i < 8) { -// // Right top corner. -// int x2 = matrix.getWidth() - i - 1; -// int y2 = 8; -// matrix.set(x2, y2, bit); -// } else { -// // Left bottom corner. -// int x2 = 8; -// int y2 = matrix.getHeight() - 7 + (i - 8); -// matrix.set(x2, y2, bit); -// } -// } -// } +private: + // Check if "value" is empty. + static bool isEmpty(int value) { return value == -1; } -// // Embed version information if need be. On success, modify the matrix and return true. -// // See 8.10 of JISX0510:2004 (p.47) for how to embed version information. -// static void maybeEmbedVersionInfo(Version version, ByteMatrix matrix) throws WriterException { -// if (version.getVersionNumber() < 7) { // Version info is necessary if version >= 7. -// return; // Don't need version info. -// } -// BitArray versionInfoBits = new BitArray(); -// makeVersionInfoBits(version, versionInfoBits); + static void embedTimingPatterns(ByteMatrix& matrix); -// int bitIndex = 6 * 3 - 1; // It will decrease from 17 to 0. -// for (int i = 0; i < 6; ++i) { -// for (int j = 0; j < 3; ++j) { -// // Place bits in LSB (least significant bit) to MSB order. -// boolean bit = versionInfoBits.get(bitIndex); -// bitIndex--; -// // Left bottom corner. -// matrix.set(i, matrix.getHeight() - 11 + j, bit); -// // Right bottom corner. -// matrix.set(matrix.getHeight() - 11 + j, i, bit); -// } -// } -// } + // Embed the lonely dark dot at left bottom corner. JISX0510:2004 (p.46) + static void embedDarkDotAtLeftBottomCorner(ByteMatrix& matrix); -// // Embed "dataBits" using "getMaskPattern". On success, modify the matrix and return true. -// // For debugging purposes, it skips masking process if "getMaskPattern" is -1. -// // See 8.7 of JISX0510:2004 (p.38) for how to embed data bits. -// static void embedDataBits(BitArray dataBits, int maskPattern, ByteMatrix matrix) -// throws WriterException { -// int bitIndex = 0; -// int direction = -1; -// // Start from the right bottom cell. -// int x = matrix.getWidth() - 1; -// int y = matrix.getHeight() - 1; -// while (x > 0) { -// // Skip the vertical timing pattern. -// if (x == 6) { -// x -= 1; -// } -// while (y >= 0 && y < matrix.getHeight()) { -// for (int i = 0; i < 2; ++i) { -// int xx = x - i; -// // Skip the cell if it's not empty. -// if (!isEmpty(matrix.get(xx, y))) { -// continue; -// } -// boolean bit; -// if (bitIndex < dataBits.getSize()) { -// bit = dataBits.get(bitIndex); -// ++bitIndex; -// } else { -// // Padding bit. If there is no bit left, we'll fill the left cells with 0, as described -// // in 8.4.9 of JISX0510:2004 (p. 24). -// bit = false; -// } + static void embedHorizontalSeparationPattern(int xStart, + int yStart, + ByteMatrix& matrix); -// // Skip masking if mask_pattern is -1. -// if (maskPattern != -1 && MaskUtil.getDataMaskBit(maskPattern, xx, y)) { -// bit = !bit; -// } -// matrix.set(xx, y, bit); -// } -// y += direction; -// } -// direction = -direction; // Reverse the direction. -// y += direction; -// x -= 2; // Move to the left. -// } -// // All bits should be consumed. -// if (bitIndex != dataBits.getSize()) { -// throw new WriterException("Not all bits consumed: " + bitIndex + '/' + dataBits.getSize()); -// } -// } + static void embedVerticalSeparationPattern(int xStart, + int yStart, + ByteMatrix& matrix); -// // Return the position of the most significant bit set (to one) in the "value". The most -// // significant bit is position 32. If there is no bit set, return 0. Examples: -// // - findMSBSet(0) => 0 -// // - findMSBSet(1) => 1 -// // - findMSBSet(255) => 8 -// static int findMSBSet(int value) { -// int numDigits = 0; -// while (value != 0) { -// value >>>= 1; -// ++numDigits; -// } -// return numDigits; -// } + // Note that we cannot unify the function with embedPositionDetectionPattern() despite they are + // almost identical, since we cannot write a function that takes 2D arrays in different sizes in + // C/C++. We should live with the fact. + static void embedPositionAdjustmentPattern(int xStart, int yStart, ByteMatrix& matrix); -// // Calculate BCH (Bose-Chaudhuri-Hocquenghem) code for "value" using polynomial "poly". The BCH -// // code is used for encoding type information and version information. -// // Example: Calculation of version information of 7. -// // f(x) is created from 7. -// // - 7 = 000111 in 6 bits -// // - f(x) = x^2 + x^1 + x^0 -// // g(x) is given by the standard (p. 67) -// // - g(x) = x^12 + x^11 + x^10 + x^9 + x^8 + x^5 + x^2 + 1 -// // Multiply f(x) by x^(18 - 6) -// // - f'(x) = f(x) * x^(18 - 6) -// // - f'(x) = x^14 + x^13 + x^12 -// // Calculate the remainder of f'(x) / g(x) -// // x^2 -// // __________________________________________________ -// // g(x) )x^14 + x^13 + x^12 -// // x^14 + x^13 + x^12 + x^11 + x^10 + x^7 + x^4 + x^2 -// // -------------------------------------------------- -// // x^11 + x^10 + x^7 + x^4 + x^2 -// // -// // The remainder is x^11 + x^10 + x^7 + x^4 + x^2 -// // Encode it in binary: 110010010100 -// // The return value is 0xc94 (1100 1001 0100) -// // -// // Since all coefficients in the polynomials are 1 or 0, we can do the calculation by bit -// // operations. We don't care if cofficients are positive or negative. -// static int calculateBCHCode(int value, int poly) { -// // If poly is "1 1111 0010 0101" (version info poly), msbSetInPoly is 13. We'll subtract 1 -// // from 13 to make it 12. -// int msbSetInPoly = findMSBSet(poly); -// value <<= msbSetInPoly - 1; -// // Do the division business using exclusive-or operations. -// while (findMSBSet(value) >= msbSetInPoly) { -// value ^= poly << (findMSBSet(value) - msbSetInPoly); -// } -// // Now the "value" is the remainder (i.e. the BCH code) -// return value; -// } + static void embedPositionDetectionPattern(int xStart, int yStart, ByteMatrix& matrix); -// // Make bit vector of type information. On success, store the result in "bits" and return true. -// // Encode error correction level and mask pattern. See 8.9 of -// // JISX0510:2004 (p.45) for details. -// static void makeTypeInfoBits(ErrorCorrectionLevel ecLevel, int maskPattern, BitArray bits) -// throws WriterException { -// if (!QRCode.isValidMaskPattern(maskPattern)) { -// throw new WriterException("Invalid mask pattern"); -// } -// int typeInfo = (ecLevel.getBits() << 3) | maskPattern; -// bits.appendBits(typeInfo, 5); + // Embed position detection patterns and surrounding vertical/horizontal separators. + static void embedPositionDetectionPatternsAndSeparators(ByteMatrix& matrix); -// int bchCode = calculateBCHCode(typeInfo, TYPE_INFO_POLY); -// bits.appendBits(bchCode, 10); + // Embed position adjustment patterns if need be. + static void maybeEmbedPositionAdjustmentPatterns(const Version& version, ByteMatrix& matrix); -// BitArray maskBits = new BitArray(); -// maskBits.appendBits(TYPE_INFO_MASK_PATTERN, 15); -// bits.xor(maskBits); +}; -// if (bits.getSize() != 15) { // Just in case. -// throw new WriterException("should not happen but we got: " + bits.getSize()); -// } -// } +} +} -// // Make bit vector of version information. On success, store the result in "bits" and return true. -// // See 8.10 of JISX0510:2004 (p.45) for details. -// static void makeVersionInfoBits(Version version, BitArray bits) throws WriterException { -// bits.appendBits(version.getVersionNumber(), 6); -// int bchCode = calculateBCHCode(version.getVersionNumber(), VERSION_INFO_POLY); -// bits.appendBits(bchCode, 12); - -// if (bits.getSize() != 18) { // Just in case. -// throw new WriterException("should not happen but we got: " + bits.getSize()); -// } -// } - -// // Check if "value" is empty. -// private static boolean isEmpty(int value) { -// return value == -1; -// } - -// private static void embedTimingPatterns(ByteMatrix matrix) { -// // -8 is for skipping position detection patterns (size 7), and two horizontal/vertical -// // separation patterns (size 1). Thus, 8 = 7 + 1. -// for (int i = 8; i < matrix.getWidth() - 8; ++i) { -// int bit = (i + 1) % 2; -// // Horizontal line. -// if (isEmpty(matrix.get(i, 6))) { -// matrix.set(i, 6, bit); -// } -// // Vertical line. -// if (isEmpty(matrix.get(6, i))) { -// matrix.set(6, i, bit); -// } -// } -// } - -// // Embed the lonely dark dot at left bottom corner. JISX0510:2004 (p.46) -// private static void embedDarkDotAtLeftBottomCorner(ByteMatrix matrix) throws WriterException { -// if (matrix.get(8, matrix.getHeight() - 8) == 0) { -// throw new WriterException(); -// } -// matrix.set(8, matrix.getHeight() - 8, 1); -// } - -// private static void embedHorizontalSeparationPattern(int xStart, -// int yStart, -// ByteMatrix matrix) throws WriterException { -// for (int x = 0; x < 8; ++x) { -// if (!isEmpty(matrix.get(xStart + x, yStart))) { -// throw new WriterException(); -// } -// matrix.set(xStart + x, yStart, 0); -// } -// } - -// private static void embedVerticalSeparationPattern(int xStart, -// int yStart, -// ByteMatrix matrix) throws WriterException { -// for (int y = 0; y < 7; ++y) { -// if (!isEmpty(matrix.get(xStart, yStart + y))) { -// throw new WriterException(); -// } -// matrix.set(xStart, yStart + y, 0); -// } -// } - -// // Note that we cannot unify the function with embedPositionDetectionPattern() despite they are -// // almost identical, since we cannot write a function that takes 2D arrays in different sizes in -// // C/C++. We should live with the fact. -// private static void embedPositionAdjustmentPattern(int xStart, int yStart, ByteMatrix matrix) { -// for (int y = 0; y < 5; ++y) { -// for (int x = 0; x < 5; ++x) { -// matrix.set(xStart + x, yStart + y, POSITION_ADJUSTMENT_PATTERN[y][x]); -// } -// } -// } - -// private static void embedPositionDetectionPattern(int xStart, int yStart, ByteMatrix matrix) { -// for (int y = 0; y < 7; ++y) { -// for (int x = 0; x < 7; ++x) { -// matrix.set(xStart + x, yStart + y, POSITION_DETECTION_PATTERN[y][x]); -// } -// } -// } - -// // Embed position detection patterns and surrounding vertical/horizontal separators. -// private static void embedPositionDetectionPatternsAndSeparators(ByteMatrix matrix) throws WriterException { -// // Embed three big squares at corners. -// int pdpWidth = POSITION_DETECTION_PATTERN[0].length; -// // Left top corner. -// embedPositionDetectionPattern(0, 0, matrix); -// // Right top corner. -// embedPositionDetectionPattern(matrix.getWidth() - pdpWidth, 0, matrix); -// // Left bottom corner. -// embedPositionDetectionPattern(0, matrix.getWidth() - pdpWidth, matrix); - -// // Embed horizontal separation patterns around the squares. -// int hspWidth = 8; -// // Left top corner. -// embedHorizontalSeparationPattern(0, hspWidth - 1, matrix); -// // Right top corner. -// embedHorizontalSeparationPattern(matrix.getWidth() - hspWidth, -// hspWidth - 1, matrix); -// // Left bottom corner. -// embedHorizontalSeparationPattern(0, matrix.getWidth() - hspWidth, matrix); - -// // Embed vertical separation patterns around the squares. -// int vspSize = 7; -// // Left top corner. -// embedVerticalSeparationPattern(vspSize, 0, matrix); -// // Right top corner. -// embedVerticalSeparationPattern(matrix.getHeight() - vspSize - 1, 0, matrix); -// // Left bottom corner. -// embedVerticalSeparationPattern(vspSize, matrix.getHeight() - vspSize, -// matrix); -// } - -// // Embed position adjustment patterns if need be. -// private static void maybeEmbedPositionAdjustmentPatterns(Version version, ByteMatrix matrix) { -// if (version.getVersionNumber() < 2) { // The patterns appear if version >= 2 -// return; -// } -// int index = version.getVersionNumber() - 1; -// int[] coordinates = POSITION_ADJUSTMENT_PATTERN_COORDINATE_TABLE[index]; -// int numCoordinates = POSITION_ADJUSTMENT_PATTERN_COORDINATE_TABLE[index].length; -// for (int i = 0; i < numCoordinates; ++i) { -// for (int j = 0; j < numCoordinates; ++j) { -// int y = coordinates[i]; -// int x = coordinates[j]; -// if (x == -1 || y == -1) { -// continue; -// } -// // If the cell is unset, we embed the position adjustment pattern here. -// if (isEmpty(matrix.get(x, y))) { -// // -2 is necessary since the x/y coordinates point to the center of the pattern, not the -// // left top corner. -// embedPositionAdjustmentPattern(x - 2, y - 2, matrix); -// } -// } -// } -// } - -//} +#endif //MATRIXUTIL_H