multiple refactorings based on latest version of ZXing core

This commit is contained in:
favoritas37 2017-08-25 02:46:43 +03:00
parent fe43ed8788
commit 069ded5923
8 changed files with 115 additions and 50 deletions

View File

@ -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

View File

@ -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;

View File

@ -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".

View File

@ -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;

View File

@ -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

View File

@ -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);
}
}
}

View File

@ -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()

View File

@ -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));
}