Zxing 3.3.0

This commit is contained in:
zzz
2016-10-25 15:04:55 +00:00
parent d2f7b65282
commit 8a8452290c
15 changed files with 129 additions and 117 deletions

View File

@@ -207,7 +207,7 @@ Applications:
Copyright (c) 2000, 2001 Markus Friedl. All rights reserved.
Copyright (c) 2008 Alexander von Gernler. All rights reserved.
See licenses/LICENSE-BSD.txt
Zxing:
Zxing 3.3.0:
See licenses/LICENSE-Apache2.0.txt
Jetty 8.1.21.v20160908:

View File

@@ -355,3 +355,11 @@
3.2.1 (20 Aug 2015)
- Small bug fixes
3.3.0 (16 Sep 2016)
- Minor core API additions like 'Result.getNumBits', raw bytes for Aztec
- Small changes for Java 9 compatibility
- BS 4.7.6 release with Android API 23 support
- TIFF support in online decoder
- Many small bug fixes, typo fixes and project build improvements

View File

@@ -2,5 +2,4 @@ This is a small portion of zxing, including only what's required
to generate QR codes. There are no modifications.
We've added a build.xml for ant.
Pulled from https://github.com/zxing/zxing on Jan. 4, 2016,
rev 4e3abafe3008e02695f894eccf05f8257fca4ee9 dated Dec. 9, 2015.
https://github.com/zxing/zxing/releases Version 3.3.0 Sept. 16, 2016

View File

@@ -1,5 +1,8 @@
<img align="right" src="https://raw.github.com/wiki/zxing/zxing/zxing-logo.png"/>
##Get Started Developing
To get started, please visit: https://github.com/zxing/zxing/wiki/Getting-Started-Developing
ZXing ("zebra crossing") is an open-source, multi-format 1D/2D barcode image processing
library implemented in Java, with ports to other languages.
@@ -50,6 +53,7 @@ library implemented in Java, with ports to other languages.
| [zxing_cpp.rb](https://github.com/glassechidna/zxing_cpp.rb) | bindings for Ruby (not just JRuby), powered by [zxing-cpp](https://github.com/glassechidna/zxing-cpp)
| [python-zxing](https://github.com/oostendo/python-zxing) | bindings for Python
| [ZXing .NET](http://zxingnet.codeplex.com/) | port to .NET and C#, and related Windows platform
| [php-qrcode-detector-decoder](https://github.com/khanamiryan/php-qrcode-detector-decoder) | port to PHP
### Other related third-party open source projects
@@ -61,11 +65,10 @@ library implemented in Java, with ports to other languages.
## Links
* [Online Decoder](http://zxing.org/w/decode.jspx)
* [QR Code Generator](http://zxing.appspot.com/generator)
* [Javadoc](http://zxing.github.io/zxing/apidocs/)
* [Documentation Site](http://zxing.github.io/zxing/)
* [Google+](https://plus.google.com/u/0/b/105889184633382354358/105889184633382354358/posts)
* [Online Decoder](https://zxing.org/w/decode.jspx)
* [QR Code Generator](https://zxing.appspot.com/generator)
* [Javadoc](https://zxing.github.io/zxing/apidocs/)
* [Documentation Site](https://zxing.github.io/zxing/)
## Contacting

View File

@@ -95,4 +95,10 @@ public enum EncodeHintType {
* (Type {@link Integer}, or {@link String} representation of the integer value).
*/
AZTEC_LAYERS,
/**
* Specifies the exact version of QR code to be encoded.
* (Type {@link Integer}, or {@link String} representation of the integer value).
*/
QR_VERSION,
}

View File

@@ -39,10 +39,8 @@ public abstract class ReaderException extends Exception {
}
// Prevent stack traces from being taken
// srowen says: huh, my IDE is saying this is not an override. native methods can't be overridden?
// This, at least, does not hurt. Because we use a singleton pattern here, it doesn't matter anyhow.
@Override
public final Throwable fillInStackTrace() {
public final synchronized Throwable fillInStackTrace() {
return null;
}

View File

@@ -151,7 +151,7 @@ public final class BitArray implements Cloneable {
* @param end end of range, exclusive
*/
public void setRange(int start, int end) {
if (end < start) {
if (end < start || start < 0 || end > size) {
throw new IllegalArgumentException();
}
if (end == start) {
@@ -163,15 +163,8 @@ public final class BitArray implements Cloneable {
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;
}
}
// Ones from firstBit to lastBit, inclusive
int mask = (2 << lastBit) - (1 << firstBit);
bits[i] |= mask;
}
}
@@ -193,10 +186,10 @@ public final class BitArray implements Cloneable {
* @param end end of range, exclusive
* @param value if true, checks that bits in range are set, otherwise checks that they are not set
* @return true iff all bits are set or not set in range, according to value argument
* @throws IllegalArgumentException if end is less than or equal to start
* @throws IllegalArgumentException if end is less than start or the range is not contained in the array
*/
public boolean isRange(int start, int end, boolean value) {
if (end < start) {
if (end < start || start < 0 || end > size) {
throw new IllegalArgumentException();
}
if (end == start) {
@@ -208,15 +201,8 @@ public final class BitArray implements Cloneable {
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;
}
}
// Ones from firstBit to lastBit, inclusive
int mask = (2 << lastBit) - (1 << firstBit);
// 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
@@ -262,11 +248,11 @@ public final class BitArray implements Cloneable {
}
public void xor(BitArray other) {
if (bits.length != other.bits.length) {
if (size != other.size) {
throw new IllegalArgumentException("Sizes don't match");
}
for (int i = 0; i < bits.length; i++) {
// The last byte could be incomplete (i.e. not have 8 bits in
// The last int could be incomplete (i.e. not have 32 bits in
// it) but there is no problem since 0 XOR 0 == 0.
bits[i] ^= other.bits[i];
}
@@ -307,10 +293,10 @@ public final class BitArray implements Cloneable {
public void reverse() {
int[] newBits = new int[bits.length];
// reverse all int's first
int len = ((size-1) / 32);
int len = (size - 1) / 32;
int oldBitsLen = len + 1;
for (int i = 0; i < oldBitsLen; i++) {
long x = (long) bits[i];
long x = bits[i];
x = ((x >> 1) & 0x55555555L) | ((x & 0x55555555L) << 1);
x = ((x >> 2) & 0x33333333L) | ((x & 0x33333333L) << 2);
x = ((x >> 4) & 0x0f0f0f0fL) | ((x & 0x0f0f0f0fL) << 4);
@@ -321,16 +307,12 @@ public final class BitArray implements Cloneable {
// now correct the int's if the bit size isn't a multiple of 32
if (size != oldBitsLen * 32) {
int leftOffset = oldBitsLen * 32 - size;
int mask = 1;
for (int i = 0; i < 31 - leftOffset; i++) {
mask = (mask << 1) | 1;
}
int currentInt = (newBits[0] >> leftOffset) & mask;
int currentInt = newBits[0] >>> leftOffset;
for (int i = 1; i < oldBitsLen; i++) {
int nextInt = newBits[i];
currentInt |= nextInt << (32 - leftOffset);
newBits[i - 1] = currentInt;
currentInt = (nextInt >> leftOffset) & mask;
currentInt = nextInt >>> leftOffset;
}
newBits[oldBitsLen - 1] = currentInt;
}
@@ -372,4 +354,4 @@ public final class BitArray implements Cloneable {
return new BitArray(bits.clone(), size);
}
}
}

View File

@@ -102,7 +102,7 @@ public final class BitMatrix implements Cloneable {
// no EOL at end?
if (bitsPos > rowStartPos) {
if(rowLength == -1) {
if (rowLength == -1) {
rowLength = bitsPos - rowStartPos;
} else if (bitsPos - rowStartPos != rowLength) {
throw new IllegalArgumentException("row lengths do not match");
@@ -254,7 +254,7 @@ public final class BitMatrix implements Cloneable {
int height = getHeight();
BitArray topRow = new BitArray(width);
BitArray bottomRow = new BitArray(width);
for (int i = 0; i < (height+1) / 2; i++) {
for (int i = 0; i < (height + 1) / 2; i++) {
topRow = getRow(i, topRow);
bottomRow = getRow(height - 1 - i, bottomRow);
topRow.reverse();
@@ -307,14 +307,11 @@ public final class BitMatrix implements Cloneable {
}
}
int width = right - left;
int height = bottom - top;
if (width < 0 || height < 0) {
if (right < left || bottom < top) {
return null;
}
return new int[] {left, top, width, height};
return new int[] {left, top, right - left + 1, bottom - top + 1};
}
/**
@@ -335,7 +332,7 @@ public final class BitMatrix implements Cloneable {
int theBits = bits[bitsOffset];
int bit = 0;
while ((theBits << (31-bit)) == 0) {
while ((theBits << (31 - bit)) == 0) {
bit++;
}
x += bit;
@@ -419,7 +416,7 @@ public final class BitMatrix implements Cloneable {
* @return string representation of entire matrix utilizing given strings
*/
public String toString(String setString, String unsetString) {
return toString(setString, unsetString, "\n");
return buildToString(setString, unsetString, "\n");
}
/**
@@ -431,6 +428,10 @@ public final class BitMatrix implements Cloneable {
*/
@Deprecated
public String toString(String setString, String unsetString, String lineSeparator) {
return buildToString(setString, unsetString, lineSeparator);
}
private String buildToString(String setString, String unsetString, String lineSeparator) {
StringBuilder result = new StringBuilder(height * (width + 1));
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {

View File

@@ -70,10 +70,10 @@ public final class GenericGF {
x *= 2; // we're assuming the generator alpha is 2
if (x >= size) {
x ^= primitive;
x &= size-1;
x &= size - 1;
}
}
for (int i = 0; i < size-1; i++) {
for (int i = 0; i < size - 1; i++) {
logTable[expTable[i]] = i;
}
// logTable[0] == 0 but this should never be used

View File

@@ -99,7 +99,6 @@ final class GenericGFPoly {
// Just return the x^0 coefficient
return getCoefficient(0);
}
int size = coefficients.length;
if (a == 1) {
// Just the sum of the coefficients
int result = 0;
@@ -109,6 +108,7 @@ final class GenericGFPoly {
return result;
}
int result = coefficients[0];
int size = coefficients.length;
for (int i = 1; i < size; i++) {
result = GenericGF.addOrSubtract(field.multiply(a, result), coefficients[i]);
}

View File

@@ -66,12 +66,6 @@ final class FormatInformation {
{0x2BED, 0x1F},
};
/**
* Offset i holds the number of 1 bits in the binary representation of i
*/
private static final int[] BITS_SET_IN_HALF_BYTE =
{0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4};
private final ErrorCorrectionLevel errorCorrectionLevel;
private final byte dataMask;
@@ -83,16 +77,7 @@ final class FormatInformation {
}
static int numBitsDiffering(int a, int b) {
a ^= b; // a now has a 1 bit exactly where its bit differs with b's
// Count bits set quickly with a series of lookups:
return BITS_SET_IN_HALF_BYTE[a & 0x0F] +
BITS_SET_IN_HALF_BYTE[(a >>> 4 & 0x0F)] +
BITS_SET_IN_HALF_BYTE[(a >>> 8 & 0x0F)] +
BITS_SET_IN_HALF_BYTE[(a >>> 12 & 0x0F)] +
BITS_SET_IN_HALF_BYTE[(a >>> 16 & 0x0F)] +
BITS_SET_IN_HALF_BYTE[(a >>> 20 & 0x0F)] +
BITS_SET_IN_HALF_BYTE[(a >>> 24 & 0x0F)] +
BITS_SET_IN_HALF_BYTE[(a >>> 28 & 0x0F)];
return Integer.bitCount(a ^ b);
}
/**
@@ -156,7 +141,7 @@ final class FormatInformation {
@Override
public int hashCode() {
return (errorCorrectionLevel.ordinal() << 3) | (int) dataMask;
return (errorCorrectionLevel.ordinal() << 3) | dataMask;
}
@Override

View File

@@ -153,7 +153,7 @@ public final class Version {
int i = alignmentPatternCenters[x] - 2;
for (int y = 0; y < max; y++) {
if ((x == 0 && (y == 0 || y == max - 1)) || (x == max - 1 && y == 0)) {
// No alignment patterns near the three finder paterns
// No alignment patterns near the three finder patterns
continue;
}
bitMatrix.setRegion(alignmentPatternCenters[y] - 2, i, 5, 5);
@@ -212,7 +212,7 @@ public final class Version {
}
/**
* <p>Encapsualtes the parameters for one error-correction block in one symbol version.
* <p>Encapsulates the parameters for one error-correction block in one symbol version.
* This includes the number of data codewords, and the number of times a block with these
* parameters is used consecutively in the QR code version's format.</p>
*/

View File

@@ -106,21 +106,17 @@ public final class Encoder {
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);
Version version;
if (hints != null && hints.containsKey(EncodeHintType.QR_VERSION)) {
int versionNumber = Integer.parseInt(hints.get(EncodeHintType.QR_VERSION).toString());
version = Version.getVersionForNumber(versionNumber);
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 = new BitArray();
headerAndDataBits.appendBitArray(headerBits);
@@ -161,6 +157,33 @@ public final class Encoder {
return qrCode;
}
/**
* Decides the smallest version of QR code that will contain all of the provided data.
*
* @throws WriterException if the data cannot fit in any version
*/
private static Version recommendVersion(ErrorCorrectionLevel ecLevel,
Mode mode,
BitArray headerBits,
BitArray dataBits) throws WriterException {
// 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));
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);
}
private static int calculateBitsNeeded(Mode mode,
BitArray headerBits,
BitArray dataBits,
Version version) {
return headerBits.getSize() + mode.getCharacterCountBits(version) + dataBits.getSize();
}
/**
* @return the code point of the table used in alphanumeric mode or
* -1 if there is no corresponding code in the table.
@@ -246,9 +269,21 @@ public final class Encoder {
}
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);
if (willFit(numInputBits, version, ecLevel)) {
return version;
}
}
throw new WriterException("Data too big");
}
/**
* @return true if the number of input bits will fit in a code with the specified version and
* error correction level.
*/
private static boolean willFit(int numInputBits, Version version, ErrorCorrectionLevel ecLevel) {
// In the following comments, we use numbers of Version 7-H.
// numBytes = 196
int numBytes = version.getTotalCodewords();
// getNumECBytes = 130
@@ -257,11 +292,7 @@ public final class Encoder {
// getNumDataBytes = 196 - 130 = 66
int numDataBytes = numBytes - numEcBytes;
int totalInputBytes = (numInputBits + 7) / 8;
if (numDataBytes >= totalInputBytes) {
return version;
}
}
throw new WriterException("Data too big");
return numDataBytes >= totalInputBytes;
}
/**
@@ -383,7 +414,7 @@ public final class Encoder {
int size = numDataBytesInBlock[0];
byte[] dataBytes = new byte[size];
bits.toBytes(8*dataBytesOffset, dataBytes, 0, size);
bits.toBytes(8 * dataBytesOffset, dataBytes, 0, size);
byte[] ecBytes = generateECBytes(dataBytes, numEcBytesInBlock[0]);
blocks.add(new BlockPair(dataBytes, ecBytes));

View File

@@ -77,23 +77,23 @@ final class MaskUtil {
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 &&
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 &&
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++;
}
@@ -103,8 +103,10 @@ final class MaskUtil {
}
private static boolean isWhiteHorizontal(byte[] rowArray, int from, int to) {
from = Math.max(from, 0);
to = Math.min(to, rowArray.length);
for (int i = from; i < to; i++) {
if (i >= 0 && i < rowArray.length && rowArray[i] == 1) {
if (rowArray[i] == 1) {
return false;
}
}
@@ -112,8 +114,10 @@ final class MaskUtil {
}
private static boolean isWhiteVertical(byte[][] array, int col, int from, int to) {
from = Math.max(from, 0);
to = Math.min(to, array.length);
for (int i = from; i < to; i++) {
if (i >= 0 && i < array.length && array[i][col] == 1) {
if (array[i][col] == 1) {
return false;
}
}

View File

@@ -271,12 +271,7 @@ final class MatrixUtil {
// - findMSBSet(1) => 1
// - findMSBSet(255) => 8
static int findMSBSet(int value) {
int numDigits = 0;
while (value != 0) {
value >>>= 1;
++numDigits;
}
return numDigits;
return 32 - Integer.numberOfLeadingZeros(value);
}
// Calculate BCH (Bose-Chaudhuri-Hocquenghem) code for "value" using polynomial "poly". The BCH