mirror of https://github.com/status-im/qzxing.git
multiple refactorings based on latest version of ZXing core
This commit is contained in:
parent
fe43ed8788
commit
069ded5923
|
@ -75,15 +75,17 @@ bool BitArray::isRange(int start, int end, bool value) {
|
|||
for (int i = firstInt; i <= lastInt; i++) {
|
||||
int firstBit = i > firstInt ? 0 : start & 0x1F;
|
||||
int lastBit = i < lastInt ? 31 : end & 0x1F;
|
||||
int mask;
|
||||
if (firstBit == 0 && lastBit == 31) {
|
||||
mask = -1;
|
||||
} else {
|
||||
mask = 0;
|
||||
for (int j = firstBit; j <= lastBit; j++) {
|
||||
mask |= 1 << j;
|
||||
}
|
||||
}
|
||||
|
||||
int mask = (2 << lastBit) - (1 << firstBit);
|
||||
// int mask;
|
||||
// if (firstBit == 0 && lastBit == 31) {
|
||||
// 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
|
||||
|
|
|
@ -60,8 +60,9 @@ const std::string ByteMatrix::toString() const
|
|||
{
|
||||
std::stringstream result;// = new StringBuilder(2 * width * height + 2);
|
||||
for (size_t y = 0; y < height_; y++) {
|
||||
const std::vector<byte>& bytesY = bytes_[y];
|
||||
for (size_t x = 0; x < width_; x++) {
|
||||
switch (bytes_[y][x]) {
|
||||
switch (bytesY[x]) {
|
||||
case 0:
|
||||
result << " 0";
|
||||
break;
|
||||
|
|
|
@ -107,6 +107,14 @@ private:
|
|||
*/
|
||||
static int calculateMaskPenalty(const ByteMatrix& matrix);
|
||||
|
||||
static int calculateBitsNeeded(const Mode &mode, const BitArray &headerBits, const BitArray &dataBits, const
|
||||
Ref<Version> version);
|
||||
static bool willFit(int numInputBits, Ref<Version> version, const ErrorCorrectionLevel &ecLevel);
|
||||
static Ref<Version> recommendVersion(ErrorCorrectionLevel &ecLevel,
|
||||
Mode &mode,
|
||||
BitArray &headerBits,
|
||||
BitArray &dataBits);
|
||||
|
||||
/**
|
||||
* Encode "bytes" with the error correction level "ecLevel". The encoding mode will be chosen
|
||||
* internally by chooseMode(). On success, store the result in "qrCode".
|
||||
|
|
|
@ -32,9 +32,10 @@ int MaskUtil::applyMaskPenaltyRule2(const ByteMatrix& matrix)
|
|||
int width = matrix.getWidth();
|
||||
int height = matrix.getHeight();
|
||||
for (int y = 0; y < height - 1; y++) {
|
||||
const std::vector<byte>& arrayY = array[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]) {
|
||||
int value = arrayY[x];
|
||||
if (value == arrayY[x + 1] && value == array[y + 1][x] && value == array[y + 1][x + 1]) {
|
||||
penalty++;
|
||||
}
|
||||
}
|
||||
|
@ -85,8 +86,10 @@ int MaskUtil::applyMaskPenaltyRule3(const ByteMatrix& matrix)
|
|||
|
||||
bool MaskUtil::isWhiteHorizontal(const std::vector<byte>& rowArray, int from, int to)
|
||||
{
|
||||
from = std::max(from, 0);
|
||||
to = std::min(to, (int)rowArray.size());
|
||||
for (int i = from; i < to; i++) {
|
||||
if (i >= 0 && i < rowArray.size() && rowArray[i] == 1) {
|
||||
if (rowArray[i] == 1) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -95,8 +98,10 @@ bool MaskUtil::isWhiteHorizontal(const std::vector<byte>& rowArray, int from, in
|
|||
|
||||
bool MaskUtil::isWhiteVertical(const std::vector<std::vector<byte> > &array, int col, int from, int to)
|
||||
{
|
||||
from = std::max(from, 0);
|
||||
to = std::min(to, (int)array.size());
|
||||
for (int i = from; i < to; i++) {
|
||||
if (i >= 0 && i < array.size() && array[i][col] == 1) {
|
||||
if (array[i][col] == 1) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -148,7 +153,7 @@ bool MaskUtil::getDataMaskBit(int maskPattern, int x, int y)
|
|||
intermediate = (y + x) % 3;
|
||||
break;
|
||||
case 4:
|
||||
intermediate = ((((unsigned int)y) >> 1) + (x / 3)) & 0x1;
|
||||
intermediate = ((y / 2) + (x / 3)) & 0x1;
|
||||
break;
|
||||
case 5:
|
||||
temp = y * x;
|
||||
|
|
|
@ -224,12 +224,16 @@ void MatrixUtil::embedDataBits(const BitArray& dataBits, int maskPattern, ByteMa
|
|||
|
||||
int MatrixUtil::findMSBSet(int value)
|
||||
{
|
||||
int numDigits = 0;
|
||||
while (value != 0) {
|
||||
value = ((unsigned int)value) >> 1; //need to recheck, original operator >>>=1
|
||||
++numDigits;
|
||||
int sizeOfTypeBits = (sizeof(int)*8);
|
||||
int sample = ( value < 0 ) ? 0 : value;
|
||||
int leadingZeros = ( value < 0 ) ? 0 : sizeOfTypeBits;
|
||||
|
||||
while(sample) {
|
||||
sample >>= 1;
|
||||
--leadingZeros;
|
||||
}
|
||||
return numDigits;
|
||||
|
||||
return sizeOfTypeBits - leadingZeros;
|
||||
}
|
||||
|
||||
int MatrixUtil::calculateBCHCode(int value, int poly)
|
||||
|
@ -389,13 +393,17 @@ void MatrixUtil::maybeEmbedPositionAdjustmentPatterns(const Version& version, By
|
|||
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];
|
||||
|
||||
for (int i = 0; i < numCoordinates; i++) {
|
||||
int y = coordinates[i];
|
||||
if(y < 0)
|
||||
continue;
|
||||
|
||||
for (int j = 0; j < numCoordinates; j++) {
|
||||
int x = coordinates[j];
|
||||
if (x == -1 || y == -1) {
|
||||
if (x < 0)
|
||||
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
|
||||
|
|
|
@ -73,21 +73,32 @@ Ref<QRCode> Encoder::encode(const QString& content, ErrorCorrectionLevel &ecLeve
|
|||
BitArray dataBits;
|
||||
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:
|
||||
// // 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();
|
||||
Ref<Version> provisionalVersion = chooseVersion(provisionalBitsNeeded, ecLevel);
|
||||
// int provisionalBitsNeeded = headerBits.getSize()
|
||||
// + mode.getCharacterCountBits(Version::getVersionForNumber(1))
|
||||
// + dataBits.getSize();
|
||||
// Ref<Version> provisionalVersion = chooseVersion(provisionalBitsNeeded, ecLevel);
|
||||
|
||||
// Use that guess to calculate the right version. I am still not sure this works in 100% of cases.
|
||||
// // 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();
|
||||
Ref<Version> version = chooseVersion(bitsNeeded, ecLevel);
|
||||
// int bitsNeeded = headerBits.getSize()
|
||||
// + mode.getCharacterCountBits(provisionalVersion)
|
||||
// + dataBits.getSize();
|
||||
// Ref<Version> version = chooseVersion(bitsNeeded, ecLevel);
|
||||
|
||||
Ref<Version> version;
|
||||
if (hints != NULL/* && hints->containsKey(EncodeHintType.QR_VERSION)*/) {
|
||||
version = Version::getVersionForNumber(1);
|
||||
int bitsNeeded = calculateBitsNeeded(mode, headerBits, dataBits, version);
|
||||
if (!willFit(bitsNeeded, version, ecLevel)) {
|
||||
throw new WriterException("Data too big for requested version");
|
||||
}
|
||||
} else {
|
||||
version = recommendVersion(ecLevel, mode, headerBits, dataBits);
|
||||
}
|
||||
|
||||
BitArray headerAndDataBits;
|
||||
headerAndDataBits.appendBitArray(headerBits);
|
||||
|
@ -130,6 +141,19 @@ Ref<QRCode> Encoder::encode(const QString& content, ErrorCorrectionLevel &ecLeve
|
|||
//return NULL;
|
||||
}
|
||||
|
||||
bool Encoder::willFit(int numInputBits, Ref<Version> version, const ErrorCorrectionLevel &ecLevel) {
|
||||
// In the following comments, we use numbers of Version 7-H.
|
||||
// numBytes = 196
|
||||
int numBytes = version->getTotalCodewords();
|
||||
// getNumECBytes = 130
|
||||
ECBlocks& ecBlocks = version->getECBlocksForLevel(ecLevel);
|
||||
int numEcBytes = ecBlocks.getTotalECCodewords();
|
||||
// getNumDataBytes = 196 - 130 = 66
|
||||
int numDataBytes = numBytes - numEcBytes;
|
||||
int totalInputBytes = (numInputBits + 7) / 8;
|
||||
return numDataBytes >= totalInputBytes;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the code point of the table used in alphanumeric mode or
|
||||
* -1 if there is no corresponding code in the table.
|
||||
|
@ -217,6 +241,7 @@ int Encoder::chooseMaskPattern(Ref<BitArray> bits,
|
|||
minPenalty = penalty;
|
||||
bestMaskPattern = maskPattern;
|
||||
}
|
||||
std::cout << std::string("i: ") << maskPattern << std::string(", penantly: ") << penalty << std::endl;
|
||||
}
|
||||
return bestMaskPattern;
|
||||
}
|
||||
|
@ -226,18 +251,11 @@ Ref<Version> Encoder::chooseVersion(int numInputBits, const ErrorCorrectionLevel
|
|||
// In the following comments, we use numbers of Version 7-H.
|
||||
for (int versionNum = 1; versionNum <= 40; versionNum++) {
|
||||
Ref<Version> version = Version::getVersionForNumber(versionNum);
|
||||
// numBytes = 196
|
||||
int numBytes = version->getTotalCodewords();
|
||||
// getNumECBytes = 130
|
||||
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) {
|
||||
if (willFit(numInputBits, version, ecLevel)) {
|
||||
return version;
|
||||
}
|
||||
}
|
||||
|
||||
throw WriterException("Data too big");
|
||||
}
|
||||
|
||||
|
@ -585,5 +603,27 @@ void Encoder::appendECI(const zxing::common::CharacterSetECI& eci, BitArray& bit
|
|||
bits.appendBits(eci.getValue(), 8);
|
||||
}
|
||||
|
||||
int Encoder::calculateBitsNeeded(const Mode &mode, const BitArray &headerBits, const BitArray &dataBits, const
|
||||
Ref<Version> version)
|
||||
{
|
||||
return headerBits.getSize() + mode.getCharacterCountBits(&(*version)) + dataBits.getSize();
|
||||
}
|
||||
|
||||
Ref<Version> Encoder::recommendVersion(ErrorCorrectionLevel &ecLevel,
|
||||
Mode &mode,
|
||||
BitArray &headerBits,
|
||||
BitArray &dataBits)
|
||||
{
|
||||
// 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 = calculateBitsNeeded(mode, headerBits, dataBits, Version::getVersionForNumber(1));
|
||||
Ref<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 = calculateBitsNeeded(mode, headerBits, dataBits, provisionalVersion);
|
||||
return chooseVersion(bitsNeeded, ecLevel);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,17 +13,17 @@ void EncoderTests::execute()
|
|||
{
|
||||
testGetAlphanumericCode();
|
||||
testChooseMode();
|
||||
testEncode();
|
||||
testAppendModeInfo();
|
||||
testAppendLengthInfo();
|
||||
testAppendBytes();
|
||||
testTerminateBits();
|
||||
testAppendLengthInfo();
|
||||
testGetNumDataBytesAndNumECBytesForBlockID();
|
||||
testTerminateBits();
|
||||
testInterleaveWithECBytes();
|
||||
testGenerateECBytes();
|
||||
testAppendNumericBytes();
|
||||
testAppendAlphanumericBytes();
|
||||
testAppend8BitBytes();
|
||||
testGenerateECBytes();
|
||||
testEncode();
|
||||
}
|
||||
|
||||
void EncoderTests::testGetAlphanumericCode()
|
||||
|
|
|
@ -240,6 +240,7 @@ void MatrixUtilTests::testFindMSBSet() {
|
|||
assertEquals(0, MatrixUtil::findMSBSet(0));
|
||||
assertEquals(1, MatrixUtil::findMSBSet(1));
|
||||
assertEquals(8, MatrixUtil::findMSBSet(0x80));
|
||||
assertEquals(8, MatrixUtil::findMSBSet(255));
|
||||
assertEquals(32, MatrixUtil::findMSBSet(0x80000000));
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue