From 1884640d673824a618036f8ca5a6a91b3cac66e7 Mon Sep 17 00:00:00 2001 From: favoritas37 Date: Sun, 26 Apr 2015 16:29:22 +0300 Subject: [PATCH] First commit for the port of Qr encoder from the ZXing core 2.3 Java version. --- source/zxing/zxing/qrcode/decoder/Mode.h | 2 + source/zxing/zxing/qrcode/decoder/QRMode.cpp | 82 +-- source/zxing/zxing/qrcode/encoder/BlockPair.h | 33 + .../zxing/zxing/qrcode/encoder/ByteMatrix.cpp | 81 +++ .../zxing/zxing/qrcode/encoder/ByteMatrix.h | 37 ++ source/zxing/zxing/qrcode/encoder/Encoder.cpp | 0 source/zxing/zxing/qrcode/encoder/Encoder.h | 582 ++++++++++++++++++ .../zxing/zxing/qrcode/encoder/MaskUtil.cpp | 0 source/zxing/zxing/qrcode/encoder/MaskUtil.h | 217 +++++++ .../zxing/zxing/qrcode/encoder/MatrixUtil.cpp | 0 .../zxing/zxing/qrcode/encoder/MatrixUtil.h | 482 +++++++++++++++ source/zxing/zxing/qrcode/encoder/QRCode.cpp | 82 +++ source/zxing/zxing/qrcode/encoder/QRCode.h | 48 ++ 13 files changed, 1609 insertions(+), 37 deletions(-) create mode 100644 source/zxing/zxing/qrcode/encoder/BlockPair.h create mode 100644 source/zxing/zxing/qrcode/encoder/ByteMatrix.cpp create mode 100644 source/zxing/zxing/qrcode/encoder/ByteMatrix.h create mode 100644 source/zxing/zxing/qrcode/encoder/Encoder.cpp create mode 100644 source/zxing/zxing/qrcode/encoder/Encoder.h create mode 100644 source/zxing/zxing/qrcode/encoder/MaskUtil.cpp create mode 100644 source/zxing/zxing/qrcode/encoder/MaskUtil.h create mode 100644 source/zxing/zxing/qrcode/encoder/MatrixUtil.cpp create mode 100644 source/zxing/zxing/qrcode/encoder/MatrixUtil.h create mode 100644 source/zxing/zxing/qrcode/encoder/QRCode.cpp create mode 100644 source/zxing/zxing/qrcode/encoder/QRCode.h diff --git a/source/zxing/zxing/qrcode/decoder/Mode.h b/source/zxing/zxing/qrcode/decoder/Mode.h index a94a356..8a36d2a 100644 --- a/source/zxing/zxing/qrcode/decoder/Mode.h +++ b/source/zxing/zxing/qrcode/decoder/Mode.h @@ -37,6 +37,8 @@ private: Mode(int cbv0_9, int cbv10_26, int cbv27, int bits, char const* name); public: + Mode(const Mode& mode); + static Mode TERMINATOR; static Mode NUMERIC; static Mode ALPHANUMERIC; diff --git a/source/zxing/zxing/qrcode/decoder/QRMode.cpp b/source/zxing/zxing/qrcode/decoder/QRMode.cpp index 25e4483..6fe70d0 100644 --- a/source/zxing/zxing/qrcode/decoder/QRMode.cpp +++ b/source/zxing/zxing/qrcode/decoder/QRMode.cpp @@ -44,47 +44,55 @@ Mode Mode::FNC1_SECOND_POSITION(0, 0, 0, 0x09, "FNC1_SECOND_POSITION"); Mode Mode::HANZI(8, 10, 12, 0x0D, "HANZI"); Mode::Mode(int cbv0_9, int cbv10_26, int cbv27, int /* bits */, char const* name) : - characterCountBitsForVersions0To9_(cbv0_9), characterCountBitsForVersions10To26_(cbv10_26), - characterCountBitsForVersions27AndHigher_(cbv27), name_(name) { + characterCountBitsForVersions0To9_(cbv0_9), characterCountBitsForVersions10To26_(cbv10_26), + characterCountBitsForVersions27AndHigher_(cbv27), name_(name) { +} + +Mode::Mode(const zxing::qrcode::Mode &mode) +{ + characterCountBitsForVersions0To9_ = mode.characterCountBitsForVersions0To9_; + characterCountBitsForVersions10To26_ = mode.characterCountBitsForVersions10To26_; + characterCountBitsForVersions27AndHigher_ = mode.characterCountBitsForVersions27AndHigher_; + name_ = mode.name_; } Mode& Mode::forBits(int bits) { - switch (bits) { - case 0x0: - return TERMINATOR; - case 0x1: - return NUMERIC; - case 0x2: - return ALPHANUMERIC; - case 0x3: - return STRUCTURED_APPEND; - case 0x4: - return BYTE; - case 0x5: - return FNC1_FIRST_POSITION; - case 0x7: - return ECI; - case 0x8: - return KANJI; - case 0x9: - return FNC1_SECOND_POSITION; - case 0xD: - // 0xD is defined in GBT 18284-2000, may not be supported in foreign country - return HANZI; - default: - ostringstream s; - s << "Illegal mode bits: " << bits; - throw ReaderException(s.str().c_str()); - } + switch (bits) { + case 0x0: + return TERMINATOR; + case 0x1: + return NUMERIC; + case 0x2: + return ALPHANUMERIC; + case 0x3: + return STRUCTURED_APPEND; + case 0x4: + return BYTE; + case 0x5: + return FNC1_FIRST_POSITION; + case 0x7: + return ECI; + case 0x8: + return KANJI; + case 0x9: + return FNC1_SECOND_POSITION; + case 0xD: + // 0xD is defined in GBT 18284-2000, may not be supported in foreign country + return HANZI; + default: + ostringstream s; + s << "Illegal mode bits: " << bits; + throw ReaderException(s.str().c_str()); + } } int Mode::getCharacterCountBits(Version *version) { - int number = version->getVersionNumber(); - if (number <= 9) { - return characterCountBitsForVersions0To9_; - } else if (number <= 26) { - return characterCountBitsForVersions10To26_; - } else { - return characterCountBitsForVersions27AndHigher_; - } + int number = version->getVersionNumber(); + if (number <= 9) { + return characterCountBitsForVersions0To9_; + } else if (number <= 26) { + return characterCountBitsForVersions10To26_; + } else { + return characterCountBitsForVersions27AndHigher_; + } } diff --git a/source/zxing/zxing/qrcode/encoder/BlockPair.h b/source/zxing/zxing/qrcode/encoder/BlockPair.h new file mode 100644 index 0000000..af42afa --- /dev/null +++ b/source/zxing/zxing/qrcode/encoder/BlockPair.h @@ -0,0 +1,33 @@ +#ifndef BLOCKPAIR_H +#define BLOCKPAIR_H + +#include + +using namespace std; + +namespace zxing { +namespace qrcode { + +class BlockPair +{ +private: + vector data_; + vector errorCorrection_; + +public: + BlockPair(const vector &data, const vector &errorCorrection) : + data_(data), errorCorrection_(errorCorrection) {} + + vector getDataBytes() { + return data_; + } + + vector getErrorCorrectionBytes() { + return errorCorrection_; + } +}; + +} +} + +#endif //BLOCKPAIR_H diff --git a/source/zxing/zxing/qrcode/encoder/ByteMatrix.cpp b/source/zxing/zxing/qrcode/encoder/ByteMatrix.cpp new file mode 100644 index 0000000..3e3f055 --- /dev/null +++ b/source/zxing/zxing/qrcode/encoder/ByteMatrix.cpp @@ -0,0 +1,81 @@ +#include "ByteMatrix.h" +#include + +namespace zxing { +namespace qrcode { + +ByteMatrix::ByteMatrix(size_t width, size_t height) : + width_(width), height_(height) +{ + for(size_t i=0; i > ByteMatrix::getArray() +{ + return bytes_; +} + +void ByteMatrix::set(size_t x, size_t y, const char value) +{ + bytes_[y][x] = value; +} + +void ByteMatrix::set(size_t x, size_t y, size_t value) +{ + bytes_[y][x] = (char) value; +} + +void ByteMatrix::set(size_t x, size_t y, bool value) +{ + bytes_[y][x] = (char) (value ? 1 : 0); +} + +void ByteMatrix::clear(const char value) +{ + for (size_t y = 0; y < height_; ++y) { + for (size_t x = 0; x < width_; ++x) { + bytes_[y][x] = value; + } + } +} + +const std::string ByteMatrix::toString() +{ + std::stringstream result;// = new StringBuilder(2 * width * height + 2); + for (size_t y = 0; y < height_; ++y) { + for (size_t x = 0; x < width_; ++x) { + switch (bytes_[y][x]) { + case 0: + result << " 0"; + break; + case 1: + result << " 1"; + break; + default: + result << " "; + break; + } + } + result << '\n' ; + } + return result.str(); +} + +} +} diff --git a/source/zxing/zxing/qrcode/encoder/ByteMatrix.h b/source/zxing/zxing/qrcode/encoder/ByteMatrix.h new file mode 100644 index 0000000..4e91791 --- /dev/null +++ b/source/zxing/zxing/qrcode/encoder/ByteMatrix.h @@ -0,0 +1,37 @@ +#ifndef BYTEMATRIX_H +#define BYTEMATRIX_H + +#include +#include + +namespace zxing { +namespace qrcode { + +class ByteMatrix +{ +private: + std::vector< std::vector > bytes_; + size_t width_; + size_t height_; + +public: + + ByteMatrix(size_t width, size_t height); + + size_t getHeight(); + size_t getWidth(); + char get(size_t x, size_t y); + + std::vector< std::vector > getArray(); + 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(); + +}; + +} +} + +#endif //BYTEMATRIX_H diff --git a/source/zxing/zxing/qrcode/encoder/Encoder.cpp b/source/zxing/zxing/qrcode/encoder/Encoder.cpp new file mode 100644 index 0000000..e69de29 diff --git a/source/zxing/zxing/qrcode/encoder/Encoder.h b/source/zxing/zxing/qrcode/encoder/Encoder.h new file mode 100644 index 0000000..8f52451 --- /dev/null +++ b/source/zxing/zxing/qrcode/encoder/Encoder.h @@ -0,0 +1,582 @@ +///* +// * 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. +// */ + +//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 java.io.UnsupportedEncodingException; +//import java.util.ArrayList; +//import java.util.Collection; +//import java.util.Map; + +///** +// * @author satorux@google.com (Satoru Takabayashi) - creator +// * @author dswitkin@google.com (Daniel Switkin) - ported from C++ +// */ +//public final class Encoder { + +// // 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 +// }; + +// static final String DEFAULT_BYTE_MODE_ENCODING = "ISO-8859-1"; + +// private 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); +// } + +// /** +// * 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/MaskUtil.cpp b/source/zxing/zxing/qrcode/encoder/MaskUtil.cpp new file mode 100644 index 0000000..e69de29 diff --git a/source/zxing/zxing/qrcode/encoder/MaskUtil.h b/source/zxing/zxing/qrcode/encoder/MaskUtil.h new file mode 100644 index 0000000..e7d0b5a --- /dev/null +++ b/source/zxing/zxing/qrcode/encoder/MaskUtil.h @@ -0,0 +1,217 @@ +///* +// * 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. +// */ + +//package com.google.zxing.qrcode.encoder; + +///** +// * @author Satoru Takabayashi +// * @author Daniel Switkin +// * @author Sean Owen +// */ +//final class MaskUtil { + +// // 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; + +// private MaskUtil() { +// // do nothing +// } + +// /** +// * 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); +// } + +// /** +// * 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 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; +// } + +// 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; +// } + +// 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; +// } + +// /** +// * 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; +// } + +// /** +// * 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; +// } + +// /** +// * 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; +// } + +//} diff --git a/source/zxing/zxing/qrcode/encoder/MatrixUtil.cpp b/source/zxing/zxing/qrcode/encoder/MatrixUtil.cpp new file mode 100644 index 0000000..e69de29 diff --git a/source/zxing/zxing/qrcode/encoder/MatrixUtil.h b/source/zxing/zxing/qrcode/encoder/MatrixUtil.h new file mode 100644 index 0000000..458266a --- /dev/null +++ b/source/zxing/zxing/qrcode/encoder/MatrixUtil.h @@ -0,0 +1,482 @@ +///* +// * 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. +// */ + +//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 { + +// private MatrixUtil() { +// // do nothing +// } + +// 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}, +// }; + +// 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}, +// }; + +// // 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 +// }; + +// // 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}, +// }; + +// // From Appendix D in JISX0510:2004 (p. 67) +// private static final int VERSION_INFO_POLY = 0x1f25; // 1 1111 0010 0101 + +// // 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; + +// // 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); +// } + +// // 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 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); + +// // 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. +// static void embedTypeInfo(ErrorCorrectionLevel ecLevel, int maskPattern, ByteMatrix matrix) +// throws WriterException { +// BitArray typeInfoBits = new BitArray(); +// 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". +// boolean 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); +// } +// } +// } + +// // 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); + +// 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 "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; +// } + +// // 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()); +// } +// } + +// // 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; +// } + +// // 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; +// } + +// // 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); + +// int bchCode = calculateBCHCode(typeInfo, TYPE_INFO_POLY); +// bits.appendBits(bchCode, 10); + +// 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); +// } +// } +// } +// } + +//} diff --git a/source/zxing/zxing/qrcode/encoder/QRCode.cpp b/source/zxing/zxing/qrcode/encoder/QRCode.cpp new file mode 100644 index 0000000..addcfe4 --- /dev/null +++ b/source/zxing/zxing/qrcode/encoder/QRCode.cpp @@ -0,0 +1,82 @@ +#include "QRCode.h" + +#include + +namespace zxing { +namespace qrcode { + +QRCode::QRCode() : + mode_ptr_(NULL), + ecLevel_ptr_(NULL), + version_ptr_(NULL), + maskPattern_(-1), + matrix_ptr_(NULL) {} + +const Mode *QRCode::getMode() const { + return mode_ptr_; +} + +const ErrorCorrectionLevel *QRCode::getECLevel() const { + return ecLevel_ptr_; +} + +const Version *QRCode::getVersion() const { + return version_ptr_; +} + +const int QRCode::getMaskPattern() const { + return maskPattern_; +} + +const ByteMatrix *QRCode::getMatrix() const{ + return matrix_ptr_; +} + +const std::string QRCode::toString() { + std::stringstream result; + result << "<<\n"; + result << " mode: {unimpl}"; + //result << mode_; + result << "\n ecLevel: {unimpl}"; + //result << ecLevel_; + result << "\n version: "; + //result << version_; + result << "\n maskPattern: "; + result << maskPattern_; +// if (matrix_ == null) { +// result.append("\n matrix: null\n"); +// } else { + result << "\n matrix:\n"; + result << matrix_ptr_->toString(); +// } + result << ">>\n"; + return result.str(); +} + +void QRCode::setMode(const Mode& value) { + mode_ptr_ = new Mode(value); +} + +/* + * Make copy constructors for all the used classes. + * Also make destructors for all + */ + +void QRCode::setECLevel(const ErrorCorrectionLevel& value) { + //ecLevel_ptr_ = value; +} + +void QRCode::setVersion(const Version& version) { + //version_ptr_ = version; +} + +void QRCode::setMaskPattern(int value) { + //maskPattern_ptr_ = value; +} + +void QRCode::setMatrix(const ByteMatrix &value) { + //matrix_ptr_ = value; +} + +} +} diff --git a/source/zxing/zxing/qrcode/encoder/QRCode.h b/source/zxing/zxing/qrcode/encoder/QRCode.h new file mode 100644 index 0000000..64b4bd3 --- /dev/null +++ b/source/zxing/zxing/qrcode/encoder/QRCode.h @@ -0,0 +1,48 @@ +#ifndef QRCODE_H +#define QRCODE_H + +#include +#include +#include +#include "ByteMatrix.h" +#include + +namespace zxing { +namespace qrcode { + +class QRCode +{ +private: + static const int NUM_MASK_PATTERNS = 8; + + Mode* mode_ptr_; + ErrorCorrectionLevel* ecLevel_ptr_; + Version* version_ptr_; + int maskPattern_; + ByteMatrix* matrix_ptr_; + +public: + + QRCode(); + const Mode* getMode() const; + const ErrorCorrectionLevel* getECLevel() const; + const Version* getVersion() const; + const int getMaskPattern() const; + const ByteMatrix* getMatrix() const; + const std::string toString(); + void setMode(const Mode& value); + void setECLevel(const ErrorCorrectionLevel& value); + void setVersion(const Version& version); + void setMaskPattern(int value); + void setMatrix(const ByteMatrix& value); + + static bool isValidMaskPattern(int maskPattern) { + return maskPattern >= 0 && maskPattern < NUM_MASK_PATTERNS; + } + +}; + +} +} + +#endif //QRCODE_H