Update zxing-core to 3.2.0

This commit is contained in:
Daniel Martí 2015-03-31 19:04:21 +02:00
parent dd1853cab3
commit 474cc194ca
65 changed files with 564 additions and 369 deletions

View File

@ -30,8 +30,23 @@ public final class ChecksumException extends ReaderException {
// do nothing
}
public static ChecksumException getChecksumInstance() {
return instance;
private ChecksumException(Throwable cause) {
super(cause);
}
public static ChecksumException getChecksumInstance() {
if (isStackTrace) {
return new ChecksumException();
} else {
return instance;
}
}
public static ChecksumException getChecksumInstance(Throwable cause) {
if (isStackTrace) {
return new ChecksumException(cause);
} else {
return instance;
}
}
}

View File

@ -44,12 +44,19 @@ public enum EncodeHintType {
/**
* Specifies a minimum barcode size (type {@link Dimension}). Only applicable to Data Matrix now.
*
* @deprecated use width/height params in
* {@link com.google.zxing.datamatrix.DataMatrixWriter#encode(String, BarcodeFormat, int, int)}
*/
@Deprecated
MIN_SIZE,
/**
* Specifies a maximum barcode size (type {@link Dimension}). Only applicable to Data Matrix now.
*
* @deprecated without replacement
*/
@Deprecated
MAX_SIZE,
/**

View File

@ -28,11 +28,25 @@ public final class FormatException extends ReaderException {
private static final FormatException instance = new FormatException();
private FormatException() {
// do nothing
}
private FormatException(Throwable cause) {
super(cause);
}
public static FormatException getFormatInstance() {
if (isStackTrace) {
return new FormatException();
} else {
return instance;
}
}
public static FormatException getFormatInstance(Throwable cause) {
if (isStackTrace) {
return new FormatException(cause);
} else {
return instance;
}
}
}

View File

@ -54,7 +54,7 @@ public final class RGBLuminanceSource extends LuminanceSource {
luminances[offset + x] = (byte) r;
} else {
// Calculate luminance cheaply, favoring green.
luminances[offset + x] = (byte) ((r + g + g + b) >> 2);
luminances[offset + x] = (byte) ((r + 2 * g + b) / 4);
}
}
}

View File

@ -25,10 +25,17 @@ package com.google.zxing;
*/
public abstract class ReaderException extends Exception {
// disable stack traces when not running inside test units
protected static final boolean isStackTrace = System.getProperty("surefire.test.class.path") != null;
ReaderException() {
// do nothing
}
ReaderException(Throwable cause) {
super(cause);
}
// 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.

View File

@ -71,7 +71,7 @@ public class ResultPoint {
* Orders an array of three ResultPoints in an order [A,B,C] such that AB is less than AC
* and BC is less than AC, and the angle between BC and BA is less than 180 degrees.
*
* @param patterns array of three {@link ResultPoint} to order
* @param patterns array of three {@code ResultPoint} to order
*/
public static void orderBestPatterns(ResultPoint[] patterns) {

View File

@ -215,6 +215,9 @@ public final class Decoder {
int numDataCodewords = ddata.getNbDatablocks();
int numCodewords = rawbits.length / codewordSize;
if (numCodewords < numDataCodewords) {
throw FormatException.getFormatInstance();
}
int offset = rawbits.length % codewordSize;
int numECCodewords = numCodewords - numDataCodewords;
@ -226,8 +229,8 @@ public final class Decoder {
try {
ReedSolomonDecoder rsDecoder = new ReedSolomonDecoder(gf);
rsDecoder.decode(dataWords, numECCodewords);
} catch (ReedSolomonException ignored) {
throw FormatException.getFormatInstance();
} catch (ReedSolomonException ex) {
throw FormatException.getFormatInstance(ex);
}
// Now perform the unstuffing operation.
@ -323,7 +326,7 @@ public final class Decoder {
for (int i = startIndex; i < startIndex + length; i++) {
res <<= 1;
if (rawbits[i]) {
res++;
res |= 0x01;
}
}
return res;

View File

@ -21,24 +21,48 @@ package com.google.zxing.client.result;
*/
public final class EmailAddressParsedResult extends ParsedResult {
private final String emailAddress;
private final String[] tos;
private final String[] ccs;
private final String[] bccs;
private final String subject;
private final String body;
private final String mailtoURI;
EmailAddressParsedResult(String emailAddress,
String subject,
String body,
String mailtoURI) {
super(ParsedResultType.EMAIL_ADDRESS);
this.emailAddress = emailAddress;
this.subject = subject;
this.body = body;
this.mailtoURI = mailtoURI;
EmailAddressParsedResult(String to) {
this(new String[] {to}, null, null, null, null);
}
EmailAddressParsedResult(String[] tos,
String[] ccs,
String[] bccs,
String subject,
String body) {
super(ParsedResultType.EMAIL_ADDRESS);
this.tos = tos;
this.ccs = ccs;
this.bccs = bccs;
this.subject = subject;
this.body = body;
}
/**
* @return first elements of {@link #getTos()} or {@code null} if none
* @deprecated use {@link #getTos()}
*/
@Deprecated
public String getEmailAddress() {
return emailAddress;
return tos == null || tos.length == 0 ? null : tos[0];
}
public String[] getTos() {
return tos;
}
public String[] getCCs() {
return ccs;
}
public String[] getBCCs() {
return bccs;
}
public String getSubject() {
@ -49,14 +73,21 @@ public final class EmailAddressParsedResult extends ParsedResult {
return body;
}
/**
* @return "mailto:"
* @deprecated without replacement
*/
@Deprecated
public String getMailtoURI() {
return mailtoURI;
return "mailto:";
}
@Override
public String getDisplayResult() {
StringBuilder result = new StringBuilder(30);
maybeAppend(emailAddress, result);
maybeAppend(tos, result);
maybeAppend(ccs, result);
maybeAppend(bccs, result);
maybeAppend(subject, result);
maybeAppend(body, result);
return result.toString();

View File

@ -19,6 +19,7 @@ package com.google.zxing.client.result;
import com.google.zxing.Result;
import java.util.Map;
import java.util.regex.Pattern;
/**
* Represents a result that encodes an e-mail address, either as a plain address
@ -28,35 +29,52 @@ import java.util.Map;
*/
public final class EmailAddressResultParser extends ResultParser {
private static final Pattern COMMA = Pattern.compile(",");
@Override
public EmailAddressParsedResult parse(Result result) {
String rawText = getMassagedText(result);
String emailAddress;
if (rawText.startsWith("mailto:") || rawText.startsWith("MAILTO:")) {
// If it starts with mailto:, assume it is definitely trying to be an email address
emailAddress = rawText.substring(7);
int queryStart = emailAddress.indexOf('?');
String hostEmail = rawText.substring(7);
int queryStart = hostEmail.indexOf('?');
if (queryStart >= 0) {
emailAddress = emailAddress.substring(0, queryStart);
hostEmail = hostEmail.substring(0, queryStart);
}
hostEmail = urlDecode(hostEmail);
String[] tos = null;
if (!hostEmail.isEmpty()) {
tos = COMMA.split(hostEmail);
}
emailAddress = urlDecode(emailAddress);
Map<String,String> nameValues = parseNameValuePairs(rawText);
String[] ccs = null;
String[] bccs = null;
String subject = null;
String body = null;
if (nameValues != null) {
if (emailAddress.isEmpty()) {
emailAddress = nameValues.get("to");
if (tos == null) {
String tosString = nameValues.get("to");
if (tosString != null) {
tos = COMMA.split(tosString);
}
}
String ccString = nameValues.get("cc");
if (ccString != null) {
ccs = COMMA.split(ccString);
}
String bccString = nameValues.get("bcc");
if (bccString != null) {
bccs = COMMA.split(bccString);
}
subject = nameValues.get("subject");
body = nameValues.get("body");
}
return new EmailAddressParsedResult(emailAddress, subject, body, rawText);
return new EmailAddressParsedResult(tos, ccs, bccs, subject, body);
} else {
if (!EmailDoCoMoResultParser.isBasicallyValidEmailAddress(rawText)) {
return null;
}
emailAddress = rawText;
return new EmailAddressParsedResult(emailAddress, null, null, "mailto:" + emailAddress);
return new EmailAddressParsedResult(rawText);
}
}

View File

@ -37,17 +37,18 @@ public final class EmailDoCoMoResultParser extends AbstractDoCoMoResultParser {
if (!rawText.startsWith("MATMSG:")) {
return null;
}
String[] rawTo = matchDoCoMoPrefixedField("TO:", rawText, true);
if (rawTo == null) {
String[] tos = matchDoCoMoPrefixedField("TO:", rawText, true);
if (tos == null) {
return null;
}
String to = rawTo[0];
for (String to : tos) {
if (!isBasicallyValidEmailAddress(to)) {
return null;
}
}
String subject = matchSingleDoCoMoPrefixedField("SUB:", rawText, false);
String body = matchSingleDoCoMoPrefixedField("BODY:", rawText, false);
return new EmailAddressParsedResult(to, subject, body, "mailto:" + to);
return new EmailAddressParsedResult(tos, null, null, subject, body);
}
/**

View File

@ -116,7 +116,7 @@ public abstract class ResultParser {
}
protected static String unescapeBackslash(String escaped) {
int backslash = escaped.indexOf((int) '\\');
int backslash = escaped.indexOf('\\');
if (backslash < 0) {
return escaped;
}
@ -208,13 +208,13 @@ public abstract class ResultParser {
int start = i; // Found the start of a match here
boolean more = true;
while (more) {
i = rawText.indexOf((int) endChar, i);
i = rawText.indexOf(endChar, i);
if (i < 0) {
// No terminating end character? uh, done. Set i such that loop terminates and break
i = rawText.length();
more = false;
} else if (rawText.charAt(i - 1) == '\\') {
// semicolon was escaped so continue
} else if (countPrecedingBackslashes(rawText, i) % 2 != 0) {
// semicolon was escaped (odd count of preceding backslashes) so continue
i++;
} else {
// found a match
@ -239,6 +239,18 @@ public abstract class ResultParser {
return matches.toArray(new String[matches.size()]);
}
private static int countPrecedingBackslashes(CharSequence s, int pos) {
int count = 0;
for (int i = pos - 1; i >= 0; i--) {
if (s.charAt(i) == '\\') {
count++;
} else {
break;
}
}
return count;
}
static String matchSinglePrefixedField(String prefix, String rawText, char endChar, boolean trim) {
String[] matches = matchPrefixedField(prefix, rawText, endChar, trim);
return matches == null ? null : matches[0];

View File

@ -45,7 +45,10 @@ public final class SMTPResultParser extends ResultParser {
subject = subject.substring(0, colon);
}
}
String mailtoURI = "mailto:" + emailAddress;
return new EmailAddressParsedResult(emailAddress, subject, body, mailtoURI);
return new EmailAddressParsedResult(new String[] {emailAddress},
null,
null,
subject,
body);
}
}

View File

@ -28,7 +28,8 @@ import java.util.regex.Pattern;
*/
public final class URIResultParser extends ResultParser {
private static final Pattern URL_WITH_PROTOCOL_PATTERN = Pattern.compile("[a-zA-Z0-9]{2,}:");
// See http://www.ietf.org/rfc/rfc2396.txt
private static final Pattern URL_WITH_PROTOCOL_PATTERN = Pattern.compile("[a-zA-Z][a-zA-Z0-9+-.]+:");
private static final Pattern URL_WITHOUT_PROTOCOL_PATTERN = Pattern.compile(
"([a-zA-Z0-9\\-]+\\.)+[a-zA-Z]{2,}" + // host name elements
"(:\\d{1,5})?" + // maybe port

View File

@ -51,7 +51,7 @@ public final class BitMatrix implements Cloneable {
}
this.width = width;
this.height = height;
this.rowSize = (width + 31) >> 5;
this.rowSize = (width + 31) / 32;
bits = new int[rowSize * height];
}
@ -62,6 +62,66 @@ public final class BitMatrix implements Cloneable {
this.bits = bits;
}
public static BitMatrix parse(String stringRepresentation, String setString, String unsetString) {
if (stringRepresentation == null) {
throw new IllegalArgumentException();
}
boolean[] bits = new boolean[stringRepresentation.length()];
int bitsPos = 0;
int rowStartPos = 0;
int rowLength = -1;
int nRows = 0;
int pos = 0;
while (pos < stringRepresentation.length()) {
if (stringRepresentation.charAt(pos) == '\n' ||
stringRepresentation.charAt(pos) == '\r') {
if (bitsPos > rowStartPos) {
if(rowLength == -1) {
rowLength = bitsPos - rowStartPos;
}
else if (bitsPos - rowStartPos != rowLength) {
throw new IllegalArgumentException("row lengths do not match");
}
rowStartPos = bitsPos;
nRows++;
}
pos++;
}
else if (stringRepresentation.substring(pos, pos + setString.length()).equals(setString)) {
pos += setString.length();
bits[bitsPos] = true;
bitsPos++;
}
else if (stringRepresentation.substring(pos, pos + unsetString.length()).equals(unsetString)) {
pos += unsetString.length();
bits[bitsPos] = false;
bitsPos++;
} else {
throw new IllegalArgumentException(
"illegal character encountered: " + stringRepresentation.substring(pos));
}
}
// no EOL at end?
if (bitsPos > rowStartPos) {
if(rowLength == -1) {
rowLength = bitsPos - rowStartPos;
} else if (bitsPos - rowStartPos != rowLength) {
throw new IllegalArgumentException("row lengths do not match");
}
nRows++;
}
BitMatrix matrix = new BitMatrix(rowLength, nRows);
for (int i = 0; i < bitsPos; i++) {
if (bits[i]) {
matrix.set(i % rowLength, i / rowLength);
}
}
return matrix;
}
/**
* <p>Gets the requested bit, where true means black.</p>
*
@ -70,7 +130,7 @@ public final class BitMatrix implements Cloneable {
* @return value of given bit in matrix
*/
public boolean get(int x, int y) {
int offset = y * rowSize + (x >> 5);
int offset = y * rowSize + (x / 32);
return ((bits[offset] >>> (x & 0x1f)) & 1) != 0;
}
@ -81,10 +141,15 @@ public final class BitMatrix implements Cloneable {
* @param y The vertical component (i.e. which row)
*/
public void set(int x, int y) {
int offset = y * rowSize + (x >> 5);
int offset = y * rowSize + (x / 32);
bits[offset] |= 1 << (x & 0x1f);
}
public void unset(int x, int y) {
int offset = y * rowSize + (x / 32);
bits[offset] &= ~(1 << (x & 0x1f));
}
/**
* <p>Flips the given bit.</p>
*
@ -92,10 +157,31 @@ public final class BitMatrix implements Cloneable {
* @param y The vertical component (i.e. which row)
*/
public void flip(int x, int y) {
int offset = y * rowSize + (x >> 5);
int offset = y * rowSize + (x / 32);
bits[offset] ^= 1 << (x & 0x1f);
}
/**
* Exclusive-or (XOR): Flip the bit in this {@code BitMatrix} if the corresponding
* mask bit is set.
*
* @param mask XOR mask
*/
public void xor(BitMatrix mask) {
if (width != mask.getWidth() || height != mask.getHeight()
|| rowSize != mask.getRowSize()) {
throw new IllegalArgumentException("input matrix dimensions do not match");
}
BitArray rowArray = new BitArray(width / 32 + 1);
for (int y = 0; y < height; y++) {
int offset = y * rowSize;
int[] row = mask.getRow(y, rowArray).getBitArray();
for (int x = 0; x < rowSize; x++) {
bits[offset + x] ^= row[x];
}
}
}
/**
* Clears all bits (sets to false).
*/
@ -129,7 +215,7 @@ public final class BitMatrix implements Cloneable {
for (int y = top; y < bottom; y++) {
int offset = y * rowSize;
for (int x = left; x < right; x++) {
bits[offset + (x >> 5)] |= 1 << (x & 0x1f);
bits[offset + (x / 32)] |= 1 << (x & 0x1f);
}
}
}
@ -150,7 +236,7 @@ public final class BitMatrix implements Cloneable {
}
int offset = y * rowSize;
for (int x = 0; x < rowSize; x++) {
row.setBulk(x << 5, bits[offset + x]);
row.setBulk(x * 32, bits[offset + x]);
}
return row;
}
@ -248,7 +334,7 @@ public final class BitMatrix implements Cloneable {
return null;
}
int y = bitsOffset / rowSize;
int x = (bitsOffset % rowSize) << 5;
int x = (bitsOffset % rowSize) * 32;
int theBits = bits[bitsOffset];
int bit = 0;
@ -269,7 +355,7 @@ public final class BitMatrix implements Cloneable {
}
int y = bitsOffset / rowSize;
int x = (bitsOffset % rowSize) << 5;
int x = (bitsOffset % rowSize) * 32;
int theBits = bits[bitsOffset];
int bit = 31;
@ -295,6 +381,13 @@ public final class BitMatrix implements Cloneable {
return height;
}
/**
* @return The row size of the matrix
*/
public int getRowSize() {
return rowSize;
}
@Override
public boolean equals(Object o) {
if (!(o instanceof BitMatrix)) {
@ -317,12 +410,24 @@ public final class BitMatrix implements Cloneable {
@Override
public String toString() {
return toString("X ", " ");
}
public String toString(String setString, String unsetString) {
return toString(setString, unsetString, "\n");
}
/**
* @deprecated call {@link #toString(String,String)} only, which uses \n line separator always
*/
@Deprecated
public String toString(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++) {
result.append(get(x, y) ? "X " : " ");
result.append(get(x, y) ? setString : unsetString);
}
result.append('\n');
result.append(lineSeparator);
}
return result.toString();
}

View File

@ -95,7 +95,7 @@ public enum CharacterSetECI {
/**
* @param value character set ECI value
* @return {@link CharacterSetECI} representing ECI of given value, or null if it is legal but
* @return {@code CharacterSetECI} representing ECI of given value, or null if it is legal but
* unsupported
* @throws FormatException if ECI value is invalid
*/

View File

@ -52,12 +52,12 @@ public final class DefaultGridSampler extends GridSampler {
throw NotFoundException.getNotFoundInstance();
}
BitMatrix bits = new BitMatrix(dimensionX, dimensionY);
float[] points = new float[dimensionX << 1];
float[] points = new float[2 * dimensionX];
for (int y = 0; y < dimensionY; y++) {
int max = points.length;
float iValue = (float) y + 0.5f;
for (int x = 0; x < max; x += 2) {
points[x] = (float) (x >> 1) + 0.5f;
points[x] = (float) (x / 2) + 0.5f;
points[x + 1] = iValue;
}
transform.transformPoints(points);
@ -68,7 +68,7 @@ public final class DefaultGridSampler extends GridSampler {
for (int x = 0; x < max; x += 2) {
if (image.get((int) points[x], (int) points[x + 1])) {
// Black(-ish) pixel
bits.set(x >> 1, y);
bits.set(x / 2, y);
}
}
} catch (ArrayIndexOutOfBoundsException aioobe) {

View File

@ -72,7 +72,7 @@ public class GlobalHistogramBinarizer extends Binarizer {
for (int x = 1; x < width - 1; x++) {
int right = localLuminances[x + 1] & 0xff;
// A simple -1 4 -1 box filter with a weight of 2.
int luminance = ((center << 2) - left - right) >> 1;
int luminance = ((center * 4) - left - right) / 2;
if (luminance < blackPoint) {
row.set(x);
}
@ -97,7 +97,7 @@ public class GlobalHistogramBinarizer extends Binarizer {
for (int y = 1; y < 5; y++) {
int row = height * y / 5;
byte[] localLuminances = source.getRow(row, luminances);
int right = (width << 2) / 5;
int right = (width * 4) / 5;
for (int x = width / 5; x < right; x++) {
int pixel = localLuminances[x] & 0xff;
localBuckets[pixel >> LUMINANCE_SHIFT]++;
@ -174,7 +174,7 @@ public class GlobalHistogramBinarizer extends Binarizer {
// If there is too little contrast in the image to pick a meaningful black point, throw rather
// than waste time trying to decode the image, and risk false positives.
if (secondPeak - firstPeak <= numBuckets >> 4) {
if (secondPeak - firstPeak <= numBuckets / 16) {
throw NotFoundException.getNotFoundInstance();
}

View File

@ -211,7 +211,7 @@ public final class HybridBinarizer extends GlobalHistogramBinarizer {
//
// The default assumption is that the block is light/background. Since no estimate for
// the level of dark pixels exists locally, use half the min for the block.
average = min >> 1;
average = min / 2;
if (y > 0 && x > 0) {
// Correct the "white background" assumption for blocks that have neighbors by comparing
@ -221,8 +221,8 @@ public final class HybridBinarizer extends GlobalHistogramBinarizer {
// the boundaries is used for the interior.
// The (min < bp) is arbitrary but works better than other heuristics that were tried.
int averageNeighborBlackPoint = (blackPoints[y - 1][x] + (2 * blackPoints[y][x - 1]) +
blackPoints[y - 1][x - 1]) >> 2;
int averageNeighborBlackPoint =
(blackPoints[y - 1][x] + (2 * blackPoints[y][x - 1]) + blackPoints[y - 1][x - 1]) / 4;
if (min < averageNeighborBlackPoint) {
average = averageNeighborBlackPoint;
}

View File

@ -23,13 +23,15 @@ public final class MathUtils {
/**
* Ends up being a bit faster than {@link Math#round(float)}. This merely rounds its
* argument to the nearest int, where x.5 rounds up to x+1.
* argument to the nearest int, where x.5 rounds up to x+1. Semantics of this shortcut
* differ slightly from {@link Math#round(float)} in that half rounds down for negative
* values. -2.5 rounds to -3, not -2. For purposes here it makes no difference.
*
* @param d real value to round
* @return nearest {@code int}
*/
public static int round(float d) {
return (int) (d + 0.5f);
return (int) (d + (d < 0.0f ? -0.5f : 0.5f));
}
public static float distance(float aX, float aY, float bX, float bY) {

View File

@ -50,31 +50,31 @@ public final class MonochromeRectangleDetector {
public ResultPoint[] detect() throws NotFoundException {
int height = image.getHeight();
int width = image.getWidth();
int halfHeight = height >> 1;
int halfWidth = width >> 1;
int deltaY = Math.max(1, height / (MAX_MODULES << 3));
int deltaX = Math.max(1, width / (MAX_MODULES << 3));
int halfHeight = height / 2;
int halfWidth = width / 2;
int deltaY = Math.max(1, height / (MAX_MODULES * 8));
int deltaX = Math.max(1, width / (MAX_MODULES * 8));
int top = 0;
int bottom = height;
int left = 0;
int right = width;
ResultPoint pointA = findCornerFromCenter(halfWidth, 0, left, right,
halfHeight, -deltaY, top, bottom, halfWidth >> 1);
halfHeight, -deltaY, top, bottom, halfWidth / 2);
top = (int) pointA.getY() - 1;
ResultPoint pointB = findCornerFromCenter(halfWidth, -deltaX, left, right,
halfHeight, 0, top, bottom, halfHeight >> 1);
halfHeight, 0, top, bottom, halfHeight / 2);
left = (int) pointB.getX() - 1;
ResultPoint pointC = findCornerFromCenter(halfWidth, deltaX, left, right,
halfHeight, 0, top, bottom, halfHeight >> 1);
halfHeight, 0, top, bottom, halfHeight / 2);
right = (int) pointC.getX() + 1;
ResultPoint pointD = findCornerFromCenter(halfWidth, 0, left, right,
halfHeight, deltaY, top, bottom, halfWidth >> 1);
halfHeight, deltaY, top, bottom, halfWidth / 2);
bottom = (int) pointD.getY() + 1;
// Go try to find point A again with better information -- might have been off at first.
pointA = findCornerFromCenter(halfWidth, 0, left, right,
halfHeight, -deltaY, top, bottom, halfWidth >> 2);
halfHeight, -deltaY, top, bottom, halfWidth / 4);
return new ResultPoint[] { pointA, pointB, pointC, pointD };
}
@ -167,7 +167,7 @@ public final class MonochromeRectangleDetector {
*/
private int[] blackWhiteRange(int fixedDimension, int maxWhiteRun, int minDim, int maxDim, boolean horizontal) {
int center = (minDim + maxDim) >> 1;
int center = (minDim + maxDim) / 2;
// Scan left/up first
int start = center;

View File

@ -38,16 +38,13 @@ public final class GenericGF {
public static final GenericGF AZTEC_DATA_8 = DATA_MATRIX_FIELD_256;
public static final GenericGF MAXICODE_FIELD_64 = AZTEC_DATA_6;
private static final int INITIALIZATION_THRESHOLD = 0;
private int[] expTable;
private int[] logTable;
private GenericGFPoly zero;
private GenericGFPoly one;
private final int[] expTable;
private final int[] logTable;
private final GenericGFPoly zero;
private final GenericGFPoly one;
private final int size;
private final int primitive;
private final int generatorBase;
private boolean initialized = false;
/**
* Create a representation of GF(size) using the given primitive polynomial.
@ -65,18 +62,12 @@ public final class GenericGF {
this.size = size;
this.generatorBase = b;
if (size <= INITIALIZATION_THRESHOLD) {
initialize();
}
}
private void initialize() {
expTable = new int[size];
logTable = new int[size];
int x = 1;
for (int i = 0; i < size; i++) {
expTable[i] = x;
x <<= 1; // x = x * 2; we're assuming the generator alpha is 2
x *= 2; // we're assuming the generator alpha is 2
if (x >= size) {
x ^= primitive;
x &= size-1;
@ -88,24 +79,13 @@ public final class GenericGF {
// logTable[0] == 0 but this should never be used
zero = new GenericGFPoly(this, new int[]{0});
one = new GenericGFPoly(this, new int[]{1});
initialized = true;
}
private void checkInit() {
if (!initialized) {
initialize();
}
}
GenericGFPoly getZero() {
checkInit();
return zero;
}
GenericGFPoly getOne() {
checkInit();
return one;
}
@ -113,8 +93,6 @@ public final class GenericGF {
* @return the monomial representing coefficient * x^degree
*/
GenericGFPoly buildMonomial(int degree, int coefficient) {
checkInit();
if (degree < 0) {
throw new IllegalArgumentException();
}
@ -139,8 +117,6 @@ public final class GenericGF {
* @return 2 to the power of a in GF(size)
*/
int exp(int a) {
checkInit();
return expTable[a];
}
@ -148,8 +124,6 @@ public final class GenericGF {
* @return base 2 log of a in GF(size)
*/
int log(int a) {
checkInit();
if (a == 0) {
throw new IllegalArgumentException();
}
@ -160,8 +134,6 @@ public final class GenericGF {
* @return multiplicative inverse of a
*/
int inverse(int a) {
checkInit();
if (a == 0) {
throw new ArithmeticException();
}
@ -172,8 +144,6 @@ public final class GenericGF {
* @return product of a and b in GF(size)
*/
int multiply(int a, int b) {
checkInit();
if (a == 0 || b == 0) {
return 0;
}

View File

@ -52,7 +52,7 @@ final class GenericGFPoly {
firstNonZero++;
}
if (firstNonZero == coefficientsLength) {
this.coefficients = field.getZero().coefficients;
this.coefficients = new int[]{0};
} else {
this.coefficients = new int[coefficientsLength - firstNonZero];
System.arraycopy(coefficients,

View File

@ -123,7 +123,7 @@ public final class DataMatrixReader implements Reader {
// Push in the "border" by half the module width so that we start
// sampling in the middle of the module. Just in case the image is a
// little off, this will help recover.
int nudge = moduleSize >> 1;
int nudge = moduleSize / 2;
top += nudge;
left += nudge;

View File

@ -60,17 +60,19 @@ public final class DataMatrixWriter implements Writer {
// Try to get force shape & min / max size
SymbolShapeHint shape = SymbolShapeHint.FORCE_NONE;
Dimension minSize = null;
Dimension minSize = new Dimension(width, height);
Dimension maxSize = null;
if (hints != null) {
SymbolShapeHint requestedShape = (SymbolShapeHint) hints.get(EncodeHintType.DATA_MATRIX_SHAPE);
if (requestedShape != null) {
shape = requestedShape;
}
@SuppressWarnings("deprecation")
Dimension requestedMinSize = (Dimension) hints.get(EncodeHintType.MIN_SIZE);
if (requestedMinSize != null) {
minSize = requestedMinSize;
}
@SuppressWarnings("deprecation")
Dimension requestedMaxSize = (Dimension) hints.get(EncodeHintType.MAX_SIZE);
if (requestedMaxSize != null) {
maxSize = requestedMaxSize;

View File

@ -94,8 +94,9 @@ final class DataBlock {
int max = result[0].codewords.length;
for (int i = longerBlocksNumDataCodewords; i < max; i++) {
for (int j = 0; j < numResultBlocks; j++) {
int iOffset = specialVersion && j > 7 ? i - 1 : i;
result[j].codewords[iOffset] = rawCodewords[rawCodewordsOffset++];
int jOffset = specialVersion ? (j + 8) % numResultBlocks : j;
int iOffset = specialVersion && jOffset > 7 ? i - 1 : i;
result[jOffset].codewords[iOffset] = rawCodewords[rawCodewordsOffset++];
}
}

View File

@ -71,6 +71,9 @@ final class DecodedBitStreamParser {
'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'
};
// Shift 2 for Text is the same encoding as C40
private static final char[] TEXT_SHIFT2_SET_CHARS = C40_SHIFT2_SET_CHARS;
private static final char[] TEXT_SHIFT3_SET_CHARS = {
'`', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '{', '|', '}', '~', (char) 127
@ -139,7 +142,7 @@ final class DecodedBitStreamParser {
return Mode.PAD_ENCODE;
} else if (oneByte <= 229) { // 2-digit data 00-99 (Numeric Value + 130)
int value = oneByte - 130;
if (value < 10) { // padd with '0' for single digit values
if (value < 10) { // pad with '0' for single digit values
result.append('0');
}
result.append(value);
@ -319,13 +322,13 @@ final class DecodedBitStreamParser {
break;
case 2:
// Shift 2 for Text is the same encoding as C40
if (cValue < C40_SHIFT2_SET_CHARS.length) {
char c40char = C40_SHIFT2_SET_CHARS[cValue];
if (cValue < TEXT_SHIFT2_SET_CHARS.length) {
char textChar = TEXT_SHIFT2_SET_CHARS[cValue];
if (upperShift) {
result.append((char) (c40char + 128));
result.append((char) (textChar + 128));
upperShift = false;
} else {
result.append(c40char);
result.append(textChar);
}
} else if (cValue == 27) { // FNC1
result.append((char) 29); // translate as ASCII 29

View File

@ -370,7 +370,7 @@ public final class Detector {
int dx = Math.abs(toX - fromX);
int dy = Math.abs(toY - fromY);
int error = -dx >> 1;
int error = -dx / 2;
int ystep = fromY < toY ? 1 : -1;
int xstep = fromX < toX ? 1 : -1;
int transitions = 0;

View File

@ -81,7 +81,7 @@ public final class ErrorCorrection {
for (int i = 0; i < 255; i++) {
ALOG[i] = p;
LOG[p] = i;
p <<= 1;
p *= 2;
if (p >= 256) {
p ^= MODULO_VALUE;
}

View File

@ -72,16 +72,12 @@ final class X12Encoder extends C40Encoder {
context.updateSymbolInfo();
int available = context.getSymbolInfo().getDataCapacity() - context.getCodewordCount();
int count = buffer.length();
if (count == 2) {
context.writeCodeword(HighLevelEncoder.X12_UNLATCH);
context.pos -= 2;
context.signalEncoderChange(HighLevelEncoder.ASCII_ENCODATION);
} else if (count == 1) {
context.pos--;
if (available > 1) {
context.pos -= count;
if (context.getRemainingCharacters() > 1 || available > 1 ||
context.getRemainingCharacters() != available) {
context.writeCodeword(HighLevelEncoder.X12_UNLATCH);
}
//NOP - No unlatch necessary
if (context.getNewEncoding() < 0) {
context.signalEncoderChange(HighLevelEncoder.ASCII_ENCODATION);
}
}

View File

@ -98,6 +98,9 @@ final class DecodedBitStreamParser {
}
private static int getInt(byte[] bytes, byte[] x) {
if (x.length == 0) {
throw new IllegalArgumentException();
}
int val = 0;
for (int i = 0; i < x.length; i++) {
val += getBit(x[i], bytes) << (x.length - i - 1);

View File

@ -23,6 +23,7 @@ import com.google.zxing.FormatException;
import com.google.zxing.NotFoundException;
import com.google.zxing.Reader;
import com.google.zxing.Result;
import com.google.zxing.ResultPoint;
import java.util.Map;
@ -58,30 +59,33 @@ public final class ByQuadrantReader implements Reader {
int halfWidth = width / 2;
int halfHeight = height / 2;
BinaryBitmap topLeft = image.crop(0, 0, halfWidth, halfHeight);
try {
return delegate.decode(topLeft, hints);
// No need to call makeAbsolute as results will be relative to original top left here
return delegate.decode(image.crop(0, 0, halfWidth, halfHeight), hints);
} catch (NotFoundException re) {
// continue
}
BinaryBitmap topRight = image.crop(halfWidth, 0, halfWidth, halfHeight);
try {
return delegate.decode(topRight, hints);
Result result = delegate.decode(image.crop(halfWidth, 0, halfWidth, halfHeight), hints);
makeAbsolute(result.getResultPoints(), halfWidth, 0);
return result;
} catch (NotFoundException re) {
// continue
}
BinaryBitmap bottomLeft = image.crop(0, halfHeight, halfWidth, halfHeight);
try {
return delegate.decode(bottomLeft, hints);
Result result = delegate.decode(image.crop(0, halfHeight, halfWidth, halfHeight), hints);
makeAbsolute(result.getResultPoints(), 0, halfHeight);
return result;
} catch (NotFoundException re) {
// continue
}
BinaryBitmap bottomRight = image.crop(halfWidth, halfHeight, halfWidth, halfHeight);
try {
return delegate.decode(bottomRight, hints);
Result result = delegate.decode(image.crop(halfWidth, halfHeight, halfWidth, halfHeight), hints);
makeAbsolute(result.getResultPoints(), halfWidth, halfHeight);
return result;
} catch (NotFoundException re) {
// continue
}
@ -89,7 +93,9 @@ public final class ByQuadrantReader implements Reader {
int quarterWidth = halfWidth / 2;
int quarterHeight = halfHeight / 2;
BinaryBitmap center = image.crop(quarterWidth, quarterHeight, halfWidth, halfHeight);
return delegate.decode(center, hints);
Result result = delegate.decode(center, hints);
makeAbsolute(result.getResultPoints(), quarterWidth, quarterHeight);
return result;
}
@Override
@ -97,4 +103,13 @@ public final class ByQuadrantReader implements Reader {
delegate.reset();
}
private static void makeAbsolute(ResultPoint[] points, int leftOffset, int topOffset) {
if (points != null) {
for (int i = 0; i < points.length; i++) {
ResultPoint relative = points[i];
points[i] = new ResultPoint(relative.getX() + leftOffset, relative.getY() + topOffset);
}
}
}
}

View File

@ -106,6 +106,9 @@ public final class GenericMultipleBarcodeReader implements MultipleBarcodeReader
float maxX = 0.0f;
float maxY = 0.0f;
for (ResultPoint point : resultPoints) {
if (point == null) {
continue;
}
float x = point.getX();
float y = point.getY();
if (x < minX) {
@ -160,8 +163,10 @@ public final class GenericMultipleBarcodeReader implements MultipleBarcodeReader
ResultPoint[] newResultPoints = new ResultPoint[oldResultPoints.length];
for (int i = 0; i < oldResultPoints.length; i++) {
ResultPoint oldPoint = oldResultPoints[i];
if (oldPoint != null) {
newResultPoints[i] = new ResultPoint(oldPoint.getX() + xOffset, oldPoint.getY() + yOffset);
}
}
Result newResult = new Result(result.getText(), result.getRawBytes(), newResultPoints, result.getBarcodeFormat());
newResult.putAllMetadata(result.getResultMetadata());
return newResult;

View File

@ -37,8 +37,8 @@ public final class CodaBarReader extends OneDReader {
// These values are critical for determining how permissive the decoding
// will be. All stripe sizes must be within the window these define, as
// compared to the average stripe size.
private static final int MAX_ACCEPTABLE = (int) (PATTERN_MATCH_RESULT_SCALE_FACTOR * 2.0f);
private static final int PADDING = (int) (PATTERN_MATCH_RESULT_SCALE_FACTOR * 1.5f);
private static final float MAX_ACCEPTABLE = 2.0f;
private static final float PADDING = 1.5f;
private static final String ALPHABET_STRING = "0123456789-$:/.+ABCD";
static final char[] ALPHABET = ALPHABET_STRING.toCharArray();
@ -188,15 +188,14 @@ public final class CodaBarReader extends OneDReader {
}
// Calculate our allowable size thresholds using fixed-point math.
int[] maxes = new int[4];
int[] mins = new int[4];
float[] maxes = new float[4];
float[] mins = new float[4];
// Define the threshold of acceptability to be the midpoint between the
// average small stripe and the average large stripe. No stripe lengths
// should be on the "wrong" side of that line.
for (int i = 0; i < 2; i++) {
mins[i] = 0; // Accept arbitrarily small "short" stripes.
mins[i + 2] = ((sizes[i] << INTEGER_MATH_SHIFT) / counts[i] +
(sizes[i + 2] << INTEGER_MATH_SHIFT) / counts[i + 2]) >> 1;
mins[i] = 0.0f; // Accept arbitrarily small "short" stripes.
mins[i + 2] = ((float) sizes[i] / counts[i] + (float) sizes[i + 2] / counts[i + 2]) / 2.0f;
maxes[i] = mins[i + 2];
maxes[i + 2] = (sizes[i + 2] * MAX_ACCEPTABLE + PADDING) / counts[i + 2];
}
@ -209,7 +208,7 @@ public final class CodaBarReader extends OneDReader {
// Even j = bars, while odd j = spaces. Categories 2 and 3 are for
// long stripes, while 0 and 1 are for short stripes.
int category = (j & 1) + (pattern & 1) * 2;
int size = counters[pos + j] << INTEGER_MATH_SHIFT;
int size = counters[pos + j];
if (size < mins[category] || size > maxes[category]) {
throw NotFoundException.getNotFoundInstance();
}

View File

@ -16,8 +16,6 @@
package com.google.zxing.oned;
import java.util.Arrays;
/**
* This class renders CodaBar as {@code boolean[]}.
*
@ -28,26 +26,40 @@ public final class CodaBarWriter extends OneDimensionalCodeWriter {
private static final char[] START_END_CHARS = {'A', 'B', 'C', 'D'};
private static final char[] ALT_START_END_CHARS = {'T', 'N', '*', 'E'};
private static final char[] CHARS_WHICH_ARE_TEN_LENGTH_EACH_AFTER_DECODED = {'/', ':', '+', '.'};
private static final char DEFAULT_GUARD = START_END_CHARS[0];
@Override
public boolean[] encode(String contents) {
if (contents.length() < 2) {
throw new IllegalArgumentException("Codabar should start/end with start/stop symbols");
}
// Can't have a start/end guard, so tentatively add default guards
contents = DEFAULT_GUARD + contents + DEFAULT_GUARD;
} else {
// Verify input and calculate decoded length.
char firstChar = Character.toUpperCase(contents.charAt(0));
char lastChar = Character.toUpperCase(contents.charAt(contents.length() - 1));
boolean startsEndsNormal =
CodaBarReader.arrayContains(START_END_CHARS, firstChar) &&
CodaBarReader.arrayContains(START_END_CHARS, lastChar);
boolean startsEndsAlt =
CodaBarReader.arrayContains(ALT_START_END_CHARS, firstChar) &&
CodaBarReader.arrayContains(ALT_START_END_CHARS, lastChar);
if (!(startsEndsNormal || startsEndsAlt)) {
throw new IllegalArgumentException(
"Codabar should start/end with " + Arrays.toString(START_END_CHARS) +
", or start/end with " + Arrays.toString(ALT_START_END_CHARS));
boolean startsNormal = CodaBarReader.arrayContains(START_END_CHARS, firstChar);
boolean endsNormal = CodaBarReader.arrayContains(START_END_CHARS, lastChar);
boolean startsAlt = CodaBarReader.arrayContains(ALT_START_END_CHARS, firstChar);
boolean endsAlt = CodaBarReader.arrayContains(ALT_START_END_CHARS, lastChar);
if (startsNormal) {
if (!endsNormal) {
throw new IllegalArgumentException("Invalid start/end guards: " + contents);
}
// else already has valid start/end
} else if (startsAlt) {
if (!endsAlt) {
throw new IllegalArgumentException("Invalid start/end guards: " + contents);
}
// else already has valid start/end
} else {
// Doesn't start with a guard
if (endsNormal || endsAlt) {
throw new IllegalArgumentException("Invalid start/end guards: " + contents);
}
// else doesn't end with guard either, so add a default
contents = DEFAULT_GUARD + contents + DEFAULT_GUARD;
}
}
// The start character and the end character are decoded to 10 length each.

View File

@ -146,8 +146,8 @@ public final class Code128Reader extends OneDReader {
{2, 3, 3, 1, 1, 1, 2}
};
private static final int MAX_AVG_VARIANCE = (int) (PATTERN_MATCH_RESULT_SCALE_FACTOR * 0.25f);
private static final int MAX_INDIVIDUAL_VARIANCE = (int) (PATTERN_MATCH_RESULT_SCALE_FACTOR * 0.7f);
private static final float MAX_AVG_VARIANCE = 0.25f;
private static final float MAX_INDIVIDUAL_VARIANCE = 0.7f;
private static final int CODE_SHIFT = 98;
@ -181,10 +181,10 @@ public final class Code128Reader extends OneDReader {
counters[counterPosition]++;
} else {
if (counterPosition == patternLength - 1) {
int bestVariance = MAX_AVG_VARIANCE;
float bestVariance = MAX_AVG_VARIANCE;
int bestMatch = -1;
for (int startCode = CODE_START_A; startCode <= CODE_START_C; startCode++) {
int variance = patternMatchVariance(counters, CODE_PATTERNS[startCode],
float variance = patternMatchVariance(counters, CODE_PATTERNS[startCode],
MAX_INDIVIDUAL_VARIANCE);
if (variance < bestVariance) {
bestVariance = variance;
@ -214,11 +214,11 @@ public final class Code128Reader extends OneDReader {
private static int decodeCode(BitArray row, int[] counters, int rowOffset)
throws NotFoundException {
recordPattern(row, rowOffset, counters);
int bestVariance = MAX_AVG_VARIANCE; // worst variance we'll accept
float bestVariance = MAX_AVG_VARIANCE; // worst variance we'll accept
int bestMatch = -1;
for (int d = 0; d < CODE_PATTERNS.length; d++) {
int[] pattern = CODE_PATTERNS[d];
int variance = patternMatchVariance(counters, pattern, MAX_INDIVIDUAL_VARIANCE);
float variance = patternMatchVariance(counters, pattern, MAX_INDIVIDUAL_VARIANCE);
if (variance < bestVariance) {
bestVariance = variance;
bestMatch = d;

View File

@ -136,7 +136,7 @@ public final class Code39Reader extends OneDReader {
int whiteSpaceAfterEnd = nextStart - lastStart - lastPatternSize;
// If 50% of last pattern size, following last pattern, is not whitespace, fail
// (but if it's whitespace to the very end of the image, that's OK)
if (nextStart != end && (whiteSpaceAfterEnd << 1) < lastPatternSize) {
if (nextStart != end && (whiteSpaceAfterEnd * 2) < lastPatternSize) {
throw NotFoundException.getNotFoundInstance();
}
@ -192,7 +192,7 @@ public final class Code39Reader extends OneDReader {
if (counterPosition == patternLength - 1) {
// Look for whitespace before start pattern, >= 50% of width of start pattern
if (toNarrowWidePattern(counters) == ASTERISK_ENCODING &&
row.isRange(Math.max(0, patternStart - ((i - patternStart) >> 1)), patternStart, false)) {
row.isRange(Math.max(0, patternStart - ((i - patternStart) / 2)), patternStart, false)) {
return new int[]{patternStart, i};
}
patternStart += counters[0] + counters[1];
@ -244,7 +244,7 @@ public final class Code39Reader extends OneDReader {
if (counter > maxNarrowCounter) {
wideCounters--;
// totalWideCountersWidth = 3 * average, so this checks if counter >= 3/2 * average
if ((counter << 1) >= totalWideCountersWidth) {
if ((counter * 2) >= totalWideCountersWidth) {
return -1;
}
}

View File

@ -170,20 +170,16 @@ public final class Code93Reader extends OneDReader {
}
int pattern = 0;
for (int i = 0; i < max; i++) {
int scaledShifted = (counters[i] << INTEGER_MATH_SHIFT) * 9 / sum;
int scaledUnshifted = scaledShifted >> INTEGER_MATH_SHIFT;
if ((scaledShifted & 0xFF) > 0x7F) {
scaledUnshifted++;
}
if (scaledUnshifted < 1 || scaledUnshifted > 4) {
int scaled = Math.round(counters[i] * 9.0f / sum);
if (scaled < 1 || scaled > 4) {
return -1;
}
if ((i & 0x01) == 0) {
for (int j = 0; j < scaledUnshifted; j++) {
for (int j = 0; j < scaled; j++) {
pattern = (pattern << 1) | 0x01;
}
} else {
pattern <<= scaledUnshifted;
pattern <<= scaled;
}
}
return pattern;

View File

@ -44,8 +44,8 @@ import java.util.Map;
*/
public final class ITFReader extends OneDReader {
private static final int MAX_AVG_VARIANCE = (int) (PATTERN_MATCH_RESULT_SCALE_FACTOR * 0.42f);
private static final int MAX_INDIVIDUAL_VARIANCE = (int) (PATTERN_MATCH_RESULT_SCALE_FACTOR * 0.78f);
private static final float MAX_AVG_VARIANCE = 0.38f;
private static final float MAX_INDIVIDUAL_VARIANCE = 0.78f;
private static final int W = 3; // Pixel width of a wide line
private static final int N = 1; // Pixed width of a narrow line
@ -157,7 +157,7 @@ public final class ITFReader extends OneDReader {
recordPattern(row, payloadStart, counterDigitPair);
// Split them into each array
for (int k = 0; k < 5; k++) {
int twoK = k << 1;
int twoK = 2 * k;
counterBlack[k] = counterDigitPair[twoK];
counterWhite[k] = counterDigitPair[twoK + 1];
}
@ -188,7 +188,7 @@ public final class ITFReader extends OneDReader {
// Determine the width of a narrow line in pixels. We can do this by
// getting the width of the start pattern and dividing by 4 because its
// made up of 4 narrow lines.
this.narrowLineWidth = (startPattern[1] - startPattern[0]) >> 2;
this.narrowLineWidth = (startPattern[1] - startPattern[0]) / 4;
validateQuietZone(row, startPattern[0]);
@ -336,13 +336,12 @@ public final class ITFReader extends OneDReader {
* @throws NotFoundException if digit cannot be decoded
*/
private static int decodeDigit(int[] counters) throws NotFoundException {
int bestVariance = MAX_AVG_VARIANCE; // worst variance we'll accept
float bestVariance = MAX_AVG_VARIANCE; // worst variance we'll accept
int bestMatch = -1;
int max = PATTERNS.length;
for (int i = 0; i < max; i++) {
int[] pattern = PATTERNS[i];
int variance = patternMatchVariance(counters, pattern, MAX_INDIVIDUAL_VARIANCE);
float variance = patternMatchVariance(counters, pattern, MAX_INDIVIDUAL_VARIANCE);
if (variance < bestVariance) {
bestVariance = variance;
bestMatch = i;

View File

@ -63,8 +63,8 @@ public final class ITFWriter extends OneDimensionalCodeWriter {
int two = Character.digit(contents.charAt(i+1), 10);
int[] encoding = new int[18];
for (int j = 0; j < 5; j++) {
encoding[j << 1] = ITFReader.PATTERNS[one][j];
encoding[(j << 1) + 1] = ITFReader.PATTERNS[two][j];
encoding[2 * j] = ITFReader.PATTERNS[one][j];
encoding[2 * j + 1] = ITFReader.PATTERNS[two][j];
}
pos += appendPattern(result, pos, encoding, true);
}

View File

@ -41,9 +41,6 @@ import java.util.Map;
*/
public abstract class OneDReader implements Reader {
protected static final int INTEGER_MATH_SHIFT = 8;
protected static final int PATTERN_MATCH_RESULT_SCALE_FACTOR = 1 << INTEGER_MATH_SHIFT;
@Override
public Result decode(BinaryBitmap image) throws NotFoundException, FormatException {
return decode(image, null);
@ -122,7 +119,7 @@ public abstract class OneDReader implements Reader {
for (int x = 0; x < maxLines; x++) {
// Scanning from the middle out. Determine which row we're looking at next:
int rowStepsAboveOrBelow = (x + 1) >> 1;
int rowStepsAboveOrBelow = (x + 1) / 2;
boolean isAbove = (x & 0x01) == 0; // i.e. is x even?
int rowNumber = middle + rowStep * (isAbove ? rowStepsAboveOrBelow : -rowStepsAboveOrBelow);
if (rowNumber < 0 || rowNumber >= height) {
@ -248,14 +245,11 @@ public abstract class OneDReader implements Reader {
* @param counters observed counters
* @param pattern expected pattern
* @param maxIndividualVariance The most any counter can differ before we give up
* @return ratio of total variance between counters and pattern compared to total pattern size,
* where the ratio has been multiplied by 256. So, 0 means no variance (perfect match); 256 means
* the total variance between counters and patterns equals the pattern length, higher values mean
* even more variance
* @return ratio of total variance between counters and pattern compared to total pattern size
*/
protected static int patternMatchVariance(int[] counters,
protected static float patternMatchVariance(int[] counters,
int[] pattern,
int maxIndividualVariance) {
float maxIndividualVariance) {
int numCounters = counters.length;
int total = 0;
int patternLength = 0;
@ -266,21 +260,19 @@ public abstract class OneDReader implements Reader {
if (total < patternLength) {
// If we don't even have one pixel per unit of bar width, assume this is too small
// to reliably match, so fail:
return Integer.MAX_VALUE;
return Float.POSITIVE_INFINITY;
}
// We're going to fake floating-point math in integers. We just need to use more bits.
// Scale up patternLength so that intermediate values below like scaledCounter will have
// more "significant digits"
int unitBarWidth = (total << INTEGER_MATH_SHIFT) / patternLength;
maxIndividualVariance = (maxIndividualVariance * unitBarWidth) >> INTEGER_MATH_SHIFT;
int totalVariance = 0;
float unitBarWidth = (float) total / patternLength;
maxIndividualVariance *= unitBarWidth;
float totalVariance = 0.0f;
for (int x = 0; x < numCounters; x++) {
int counter = counters[x] << INTEGER_MATH_SHIFT;
int scaledPattern = pattern[x] * unitBarWidth;
int variance = counter > scaledPattern ? counter - scaledPattern : scaledPattern - counter;
int counter = counters[x];
float scaledPattern = pattern[x] * unitBarWidth;
float variance = counter > scaledPattern ? counter - scaledPattern : scaledPattern - counter;
if (variance > maxIndividualVariance) {
return Integer.MAX_VALUE;
return Float.POSITIVE_INFINITY;
}
totalVariance += variance;
}

View File

@ -44,8 +44,8 @@ public abstract class UPCEANReader extends OneDReader {
// These two values are critical for determining how permissive the decoding will be.
// We've arrived at these values through a lot of trial and error. Setting them any higher
// lets false positives creep in quickly.
private static final int MAX_AVG_VARIANCE = (int) (PATTERN_MATCH_RESULT_SCALE_FACTOR * 0.48f);
private static final int MAX_INDIVIDUAL_VARIANCE = (int) (PATTERN_MATCH_RESULT_SCALE_FACTOR * 0.7f);
private static final float MAX_AVG_VARIANCE = 0.48f;
private static final float MAX_INDIVIDUAL_VARIANCE = 0.7f;
/**
* Start/end guard pattern.
@ -353,12 +353,12 @@ public abstract class UPCEANReader extends OneDReader {
static int decodeDigit(BitArray row, int[] counters, int rowOffset, int[][] patterns)
throws NotFoundException {
recordPattern(row, rowOffset, counters);
int bestVariance = MAX_AVG_VARIANCE; // worst variance we'll accept
float bestVariance = MAX_AVG_VARIANCE; // worst variance we'll accept
int bestMatch = -1;
int max = patterns.length;
for (int i = 0; i < max; i++) {
int[] pattern = patterns[i];
int variance = patternMatchVariance(counters, pattern, MAX_INDIVIDUAL_VARIANCE);
float variance = patternMatchVariance(counters, pattern, MAX_INDIVIDUAL_VARIANCE);
if (variance < bestVariance) {
bestVariance = variance;
bestMatch = i;

View File

@ -21,8 +21,8 @@ import com.google.zxing.oned.OneDReader;
public abstract class AbstractRSSReader extends OneDReader {
private static final int MAX_AVG_VARIANCE = (int) (PATTERN_MATCH_RESULT_SCALE_FACTOR * 0.2f);
private static final int MAX_INDIVIDUAL_VARIANCE = (int) (PATTERN_MATCH_RESULT_SCALE_FACTOR * 0.45f);
private static final float MAX_AVG_VARIANCE = 0.2f;
private static final float MAX_INDIVIDUAL_VARIANCE = 0.45f;
private static final float MIN_FINDER_PATTERN_RATIO = 9.5f / 12.0f;
private static final float MAX_FINDER_PATTERN_RATIO = 12.5f / 14.0f;

View File

@ -228,7 +228,7 @@ public final class RSS14Reader extends AbstractRSSReader {
} else if (count > 8) {
count = 8;
}
int offset = i >> 1;
int offset = i / 2;
if ((i & 0x01) == 0) {
oddCounts[offset] = count;
oddRoundingErrors[offset] = value - count;

View File

@ -129,7 +129,7 @@ public final class RSSUtils {
/*
static int[] elements(int[] eDist, int N, int K) {
int[] widths = new int[eDist.length + 2];
int twoK = K << 1;
int twoK = 2 * K;
widths[0] = 1;
int i;
int minEven = 10;

View File

@ -40,7 +40,7 @@ final class BitArrayBuilder {
}
static BitArray buildBitArray(List<ExpandedPair> pairs) {
int charNumber = (pairs.size() << 1) - 1;
int charNumber = (pairs.size() * 2) - 1;
if (pairs.get(pairs.size() - 1).getRightChar() == null) {
charNumber -= 1;
}

View File

@ -639,7 +639,7 @@ public final class RSSExpandedReader extends AbstractRSSReader {
}
count = 8;
}
int offset = i >> 1;
int offset = i / 2;
if ((i & 0x01) == 0) {
oddCounts[offset] = count;
oddRoundingErrors[offset] = value - count;

View File

@ -15,6 +15,7 @@
*/
package com.google.zxing.pdf417;
import java.util.Arrays;
import java.util.Collection;
/**
@ -63,38 +64,14 @@ public final class PDF417Common {
* @param symbol encoded symbol to translate to a codeword
* @return the codeword corresponding to the symbol.
*/
public static int getCodeword(long symbol) {
long sym = symbol & 0x3FFFF;
int i = findCodewordIndex(sym);
if (i == -1) {
public static int getCodeword(int symbol) {
int i = Arrays.binarySearch(SYMBOL_TABLE, symbol & 0x3FFFF);
if (i < 0) {
return -1;
}
return (CODEWORD_TABLE[i] - 1) % NUMBER_OF_CODEWORDS;
}
/**
* Use a binary search to find the index of the codeword corresponding to
* this symbol.
*
* @param symbol the symbol from the barcode.
* @return the index into the codeword table.
*/
private static int findCodewordIndex(long symbol) {
int first = 0;
int upto = SYMBOL_TABLE.length;
while (first < upto) {
int mid = (first + upto) >>> 1; // Compute mid point.
if (symbol < SYMBOL_TABLE[mid]) {
upto = mid; // continue search in bottom half.
} else if (symbol > SYMBOL_TABLE[mid]) {
first = mid + 1; // continue search in top half.
} else {
return mid; // Found it. return position
}
}
return -1;
}
/**
* The sorted table of all possible symbols. Extracted from the PDF417
* specification. The index of a symbol in this table corresponds to the

View File

@ -17,10 +17,13 @@
package com.google.zxing.pdf417.decoder;
import com.google.zxing.FormatException;
import com.google.zxing.common.CharacterSetECI;
import com.google.zxing.common.DecoderResult;
import com.google.zxing.pdf417.PDF417ResultMetadata;
import java.io.ByteArrayOutputStream;
import java.math.BigInteger;
import java.nio.charset.Charset;
import java.util.Arrays;
/**
@ -44,6 +47,9 @@ final class DecodedBitStreamParser {
private static final int BYTE_COMPACTION_MODE_LATCH = 901;
private static final int NUMERIC_COMPACTION_MODE_LATCH = 902;
private static final int BYTE_COMPACTION_MODE_LATCH_6 = 924;
private static final int ECI_USER_DEFINED = 925;
private static final int ECI_GENERAL_PURPOSE = 926;
private static final int ECI_CHARSET = 927;
private static final int BEGIN_MACRO_PDF417_CONTROL_BLOCK = 928;
private static final int BEGIN_MACRO_PDF417_OPTIONAL_FIELD = 923;
private static final int MACRO_PDF417_TERMINATOR = 922;
@ -59,7 +65,7 @@ final class DecodedBitStreamParser {
private static final int PAL = 29;
private static final char[] PUNCT_CHARS = {
';', '<', '>', '@', '[', '\\', '}', '_', '`', '~', '!',
';', '<', '>', '@', '[', '\\', ']', '_', '`', '~', '!',
'\r', '\t', ',', ':', '\n', '-', '.', '$', '/', '"', '|', '*',
'(', ')', '?', '{', '}', '\''};
@ -68,6 +74,8 @@ final class DecodedBitStreamParser {
'\r', '\t', ',', ':', '#', '-', '.', '$', '/', '+', '%', '*',
'=', '^'};
private static final Charset DEFAULT_ENCODING = Charset.forName("ISO-8859-1");
/**
* Table containing values for the exponent of 900.
* This is used in the numeric compaction decode algorithm.
@ -90,6 +98,7 @@ final class DecodedBitStreamParser {
static DecoderResult decode(int[] codewords, String ecLevel) throws FormatException {
StringBuilder result = new StringBuilder(codewords.length * 2);
Charset encoding = DEFAULT_ENCODING;
// Get compaction mode
int codeIndex = 1;
int code = codewords[codeIndex++];
@ -101,12 +110,27 @@ final class DecodedBitStreamParser {
break;
case BYTE_COMPACTION_MODE_LATCH:
case BYTE_COMPACTION_MODE_LATCH_6:
codeIndex = byteCompaction(code, codewords, encoding, codeIndex, result);
break;
case MODE_SHIFT_TO_BYTE_COMPACTION_MODE:
codeIndex = byteCompaction(code, codewords, codeIndex, result);
result.append((char) codewords[codeIndex++]);
break;
case NUMERIC_COMPACTION_MODE_LATCH:
codeIndex = numericCompaction(codewords, codeIndex, result);
break;
case ECI_CHARSET:
CharacterSetECI charsetECI =
CharacterSetECI.getCharacterSetECIByValue(codewords[codeIndex++]);
encoding = Charset.forName(charsetECI.name());
break;
case ECI_GENERAL_PURPOSE:
// Can't do anything with generic ECI; skip its 2 characters
codeIndex += 2;
break;
case ECI_USER_DEFINED:
// Can't do anything with user ECI; skip its 1 character
codeIndex ++;
break;
case BEGIN_MACRO_PDF417_CONTROL_BLOCK:
codeIndex = decodeMacroBlock(codewords, codeIndex, resultMetadata);
break;
@ -197,9 +221,9 @@ final class DecodedBitStreamParser {
*/
private static int textCompaction(int[] codewords, int codeIndex, StringBuilder result) {
// 2 character per codeword
int[] textCompactionData = new int[(codewords[0] - codeIndex) << 1];
int[] textCompactionData = new int[(codewords[0] - codeIndex) * 2];
// Used to hold the byte compaction value if there is a mode shift
int[] byteCompactionData = new int[(codewords[0] - codeIndex) << 1];
int[] byteCompactionData = new int[(codewords[0] - codeIndex) * 2];
int index = 0;
boolean end = false;
@ -316,6 +340,7 @@ final class DecodedBitStreamParser {
priorToShiftMode = subMode;
subMode = Mode.PUNCT_SHIFT;
} else if (subModeCh == MODE_SHIFT_TO_BYTE_COMPACTION_MODE) {
// TODO Does this need to use the current character encoding? See other occurrences below
result.append((char) byteCompactionData[i]);
} else if (subModeCh == TEXT_COMPACTION_MODE_LATCH) {
subMode = Mode.ALPHA;
@ -410,17 +435,22 @@ final class DecodedBitStreamParser {
*
* @param mode The byte compaction mode i.e. 901 or 924
* @param codewords The array of codewords (data + error)
* @param encoding Currently active character encoding
* @param codeIndex The current index into the codeword array.
* @param result The decoded data is appended to the result.
* @return The next index into the codeword array.
*/
private static int byteCompaction(int mode, int[] codewords, int codeIndex, StringBuilder result) {
private static int byteCompaction(int mode,
int[] codewords,
Charset encoding,
int codeIndex,
StringBuilder result) {
ByteArrayOutputStream decodedBytes = new ByteArrayOutputStream();
if (mode == BYTE_COMPACTION_MODE_LATCH) {
// Total number of Byte Compaction characters to be encoded
// is not a multiple of 6
int count = 0;
long value = 0;
char[] decodedData = new char[6];
int[] byteCompactedCodewords = new int[6];
boolean end = false;
int nextCode = codewords[codeIndex++];
@ -444,10 +474,9 @@ final class DecodedBitStreamParser {
// Decode every 5 codewords
// Convert to Base 256
for (int j = 0; j < 6; ++j) {
decodedData[5 - j] = (char) (value % 256);
value >>= 8;
decodedBytes.write((byte) (value >> (8 * (5 - j))));
}
result.append(decodedData);
value = 0;
count = 0;
}
}
@ -462,7 +491,7 @@ final class DecodedBitStreamParser {
// the last group of codewords is interpreted directly
// as one byte per codeword, without compaction.
for (int i = 0; i < count; i++) {
result.append((char) byteCompactedCodewords[i]);
decodedBytes.write((byte) byteCompactedCodewords[i]);
}
} else if (mode == BYTE_COMPACTION_MODE_LATCH_6) {
@ -492,16 +521,15 @@ final class DecodedBitStreamParser {
if ((count % 5 == 0) && (count > 0)) {
// Decode every 5 codewords
// Convert to Base 256
char[] decodedData = new char[6];
for (int j = 0; j < 6; ++j) {
decodedData[5 - j] = (char) (value & 0xFF);
value >>= 8;
decodedBytes.write((byte) (value >> (8 * (5 - j))));
}
result.append(decodedData);
value = 0;
count = 0;
}
}
}
result.append(new String(decodedBytes.toByteArray(), encoding));
return codeIndex;
}
@ -545,11 +573,13 @@ final class DecodedBitStreamParser {
// while in Numeric Compaction mode) serves to terminate the
// current Numeric Compaction mode grouping as described in 5.4.4.2,
// and then to start a new one grouping.
if (count > 0) {
String s = decodeBase900toBase10(numericCodewords, count);
result.append(s);
count = 0;
}
}
}
return codeIndex;
}

View File

@ -326,28 +326,32 @@ public final class PDF417ScanningDecoder {
throw ChecksumException.getChecksumInstance();
}
private static BarcodeValue[][] createBarcodeMatrix(DetectionResult detectionResult) {
BarcodeValue[][] barcodeMatrix = new BarcodeValue[detectionResult.getBarcodeRowCount()][detectionResult
.getBarcodeColumnCount() + 2];
private static BarcodeValue[][] createBarcodeMatrix(DetectionResult detectionResult) throws FormatException {
BarcodeValue[][] barcodeMatrix =
new BarcodeValue[detectionResult.getBarcodeRowCount()][detectionResult.getBarcodeColumnCount() + 2];
for (int row = 0; row < barcodeMatrix.length; row++) {
for (int column = 0; column < barcodeMatrix[row].length; column++) {
barcodeMatrix[row][column] = new BarcodeValue();
}
}
int column = -1;
int column = 0;
for (DetectionResultColumn detectionResultColumn : detectionResult.getDetectionResultColumns()) {
column++;
if (detectionResultColumn == null) {
continue;
}
if (detectionResultColumn != null) {
for (Codeword codeword : detectionResultColumn.getCodewords()) {
if (codeword == null || codeword.getRowNumber() == -1) {
continue;
if (codeword != null) {
int rowNumber = codeword.getRowNumber();
if (rowNumber >= 0) {
if (rowNumber >= barcodeMatrix.length) {
throw FormatException.getFormatInstance();
}
barcodeMatrix[codeword.getRowNumber()][column].setValue(codeword.getValue());
barcodeMatrix[rowNumber][column].setValue(codeword.getValue());
}
}
}
}
column++;
}
return barcodeMatrix;
}
@ -416,7 +420,7 @@ public final class PDF417ScanningDecoder {
if (leftToRight) {
endColumn = startColumn + codewordBitCount;
} else {
for (int i = 0; i < moduleBitCount.length >> 1; i++) {
for (int i = 0; i < moduleBitCount.length / 2; i++) {
int tmpCount = moduleBitCount[i];
moduleBitCount[i] = moduleBitCount[moduleBitCount.length - 1 - i];
moduleBitCount[moduleBitCount.length - 1 - i] = tmpCount;

View File

@ -62,12 +62,14 @@ public final class ErrorCorrection {
}
ModulusPoly knownErrors = field.getOne();
if (erasures != null) {
for (int erasure : erasures) {
int b = field.exp(received.length - 1 - erasure);
// Add (1 - bx) term:
ModulusPoly term = new ModulusPoly(field, new int[] { field.subtract(0, b), 1 });
ModulusPoly term = new ModulusPoly(field, new int[]{field.subtract(0, b), 1});
knownErrors = knownErrors.multiply(term);
}
}
ModulusPoly syndrome = new ModulusPoly(field, S);
//syndrome = syndrome.multiply(knownErrors);

View File

@ -38,7 +38,7 @@ final class ModulusPoly {
firstNonZero++;
}
if (firstNonZero == coefficientsLength) {
this.coefficients = field.getZero().coefficients;
this.coefficients = new int[]{0};
} else {
this.coefficients = new int[coefficientsLength - firstNonZero];
System.arraycopy(coefficients,

View File

@ -39,10 +39,8 @@ public final class Detector {
private static final int[] INDEXES_START_PATTERN = {0, 4, 1, 5};
private static final int[] INDEXES_STOP_PATTERN = {6, 2, 7, 3};
private static final int INTEGER_MATH_SHIFT = 8;
private static final int PATTERN_MATCH_RESULT_SCALE_FACTOR = 1 << INTEGER_MATH_SHIFT;
private static final int MAX_AVG_VARIANCE = (int) (PATTERN_MATCH_RESULT_SCALE_FACTOR * 0.42f);
private static final int MAX_INDIVIDUAL_VARIANCE = (int) (PATTERN_MATCH_RESULT_SCALE_FACTOR * 0.8f);
private static final float MAX_AVG_VARIANCE = 0.42f;
private static final float MAX_INDIVIDUAL_VARIANCE = 0.8f;
// B S B S B S B S Bar/Space pattern
// 11111111 0 1 0 1 0 1 000
@ -310,13 +308,9 @@ public final class Detector {
* @param counters observed counters
* @param pattern expected pattern
* @param maxIndividualVariance The most any counter can differ before we give up
* @return ratio of total variance between counters and pattern compared to
* total pattern size, where the ratio has been multiplied by 256.
* So, 0 means no variance (perfect match); 256 means the total
* variance between counters and patterns equals the pattern length,
* higher values mean even more variance
* @return ratio of total variance between counters and pattern compared to total pattern size
*/
private static int patternMatchVariance(int[] counters, int[] pattern, int maxIndividualVariance) {
private static float patternMatchVariance(int[] counters, int[] pattern, float maxIndividualVariance) {
int numCounters = counters.length;
int total = 0;
int patternLength = 0;
@ -327,21 +321,21 @@ public final class Detector {
if (total < patternLength) {
// If we don't even have one pixel per unit of bar width, assume this
// is too small to reliably match, so fail:
return Integer.MAX_VALUE;
return Float.POSITIVE_INFINITY;
}
// We're going to fake floating-point math in integers. We just need to use more bits.
// Scale up patternLength so that intermediate values below like scaledCounter will have
// more "significant digits".
int unitBarWidth = (total << INTEGER_MATH_SHIFT) / patternLength;
maxIndividualVariance = (maxIndividualVariance * unitBarWidth) >> INTEGER_MATH_SHIFT;
float unitBarWidth = (float) total / patternLength;
maxIndividualVariance *= unitBarWidth;
int totalVariance = 0;
float totalVariance = 0.0f;
for (int x = 0; x < numCounters; x++) {
int counter = counters[x] << INTEGER_MATH_SHIFT;
int scaledPattern = pattern[x] * unitBarWidth;
int variance = counter > scaledPattern ? counter - scaledPattern : scaledPattern - counter;
int counter = counters[x];
float scaledPattern = pattern[x] * unitBarWidth;
float variance = counter > scaledPattern ? counter - scaledPattern : scaledPattern - counter;
if (variance > maxIndividualVariance) {
return Integer.MAX_VALUE;
return Float.POSITIVE_INFINITY;
}
totalVariance += variance;
}

View File

@ -25,9 +25,7 @@ import com.google.zxing.common.CharacterSetECI;
import java.math.BigInteger;
import java.nio.charset.Charset;
import java.nio.charset.UnsupportedCharsetException;
import java.util.Arrays;
import java.util.List;
/**
* PDF417 high-level encoder following the algorithm described in ISO/IEC 15438:2001(E) in
@ -127,7 +125,7 @@ final class PDF417HighLevelEncoder {
private static final byte[] MIXED = new byte[128];
private static final byte[] PUNCTUATION = new byte[128];
private static final List<String> DEFAULT_ENCODING_NAMES = Arrays.asList("Cp437", "IBM437");
private static final Charset DEFAULT_ENCODING = Charset.forName("ISO-8859-1");
private PDF417HighLevelEncoder() {
}
@ -166,7 +164,9 @@ final class PDF417HighLevelEncoder {
//the codewords 0..928 are encoded as Unicode characters
StringBuilder sb = new StringBuilder(msg.length());
if (encoding != null || !DEFAULT_ENCODING_NAMES.contains(encoding.name())) {
if (encoding == null) {
encoding = DEFAULT_ENCODING;
} else if (!DEFAULT_ENCODING.equals(encoding)) {
CharacterSetECI eci = CharacterSetECI.getCharacterSetECIByName(encoding.name());
if (eci != null) {
encodingECI(eci.getValue(), sb);
@ -183,7 +183,7 @@ final class PDF417HighLevelEncoder {
encodeText(msg, p, len, sb, textSubMode);
} else if (compaction == Compaction.BYTE) {
bytes = toBytes(msg, encoding);
bytes = msg.getBytes(encoding);
encodeBinary(bytes, p, bytes.length, BYTE_COMPACTION, sb);
} else if (compaction == Compaction.NUMERIC) {
@ -212,7 +212,7 @@ final class PDF417HighLevelEncoder {
p += t;
} else {
if (bytes == null) {
bytes = toBytes(msg, encoding);
bytes = msg.getBytes(encoding);
}
int b = determineConsecutiveBinaryCount(msg, bytes, p);
if (b == 0) {
@ -236,24 +236,6 @@ final class PDF417HighLevelEncoder {
return sb.toString();
}
private static byte[] toBytes(String msg, Charset encoding) throws WriterException {
// Defer instantiating default Charset until needed, since it may be for an unsupported
// encoding. For example the default of Cp437 doesn't seem to exist on Android.
if (encoding == null) {
for (String encodingName : DEFAULT_ENCODING_NAMES) {
try {
encoding = Charset.forName(encodingName);
} catch (UnsupportedCharsetException uce) {
// continue
}
}
if (encoding == null) {
throw new WriterException("No support for any encoding: " + DEFAULT_ENCODING_NAMES);
}
}
return msg.getBytes(encoding);
}
/**
* Encode parts of the message using Text Compaction as described in ISO/IEC 15438:2001(E),
* chapter 4.4.2.
@ -439,7 +421,7 @@ final class PDF417HighLevelEncoder {
StringBuilder tmp = new StringBuilder(count / 3 + 1);
BigInteger num900 = BigInteger.valueOf(900);
BigInteger num0 = BigInteger.valueOf(0);
while (idx < count - 1) {
while (idx < count) {
tmp.setLength(0);
int len = Math.min(44, count - idx);
String part = '1' + msg.substring(startpos + idx, startpos + idx + len);
@ -572,18 +554,6 @@ final class PDF417HighLevelEncoder {
if (numericCount >= 13) {
return idx - startpos;
}
int textCount = 0;
while (textCount < 5 && isText(ch)) {
textCount++;
int i = idx + textCount;
if (i >= len) {
break;
}
ch = msg.charAt(i);
}
if (textCount >= 5) {
return idx - startpos;
}
ch = msg.charAt(idx);
//Check if character is encodable

View File

@ -159,7 +159,9 @@ public class QRCodeReader implements Reader {
left += nudge;
// But careful that this does not sample off the edge
int nudgedTooFarRight = left + (int) ((matrixWidth - 1) * moduleSize) - (right - 1);
// "right" is the farthest-right valid pixel location -- right+1 is not necessarily
// This is positive by how much the inner x loop below would be too large
int nudgedTooFarRight = left + (int) ((matrixWidth - 1) * moduleSize) - right;
if (nudgedTooFarRight > 0) {
if (nudgedTooFarRight > nudge) {
// Neither way fits; abort
@ -167,7 +169,8 @@ public class QRCodeReader implements Reader {
}
left -= nudgedTooFarRight;
}
int nudgedTooFarDown = top + (int) ((matrixHeight - 1) * moduleSize) - (bottom - 1);
// See logic above
int nudgedTooFarDown = top + (int) ((matrixHeight - 1) * moduleSize) - bottom;
if (nudgedTooFarDown > 0) {
if (nudgedTooFarDown > nudge) {
// Neither way fits; abort

View File

@ -90,8 +90,8 @@ public final class QRCodeWriter implements Writer {
}
int inputWidth = input.getWidth();
int inputHeight = input.getHeight();
int qrWidth = inputWidth + (quietZone << 1);
int qrHeight = inputHeight + (quietZone << 1);
int qrWidth = inputWidth + (quietZone * 2);
int qrHeight = inputHeight + (quietZone * 2);
int outputWidth = Math.max(width, qrWidth);
int outputHeight = Math.max(height, qrHeight);

View File

@ -101,7 +101,7 @@ final class BitMatrixParser {
int dimension = bitMatrix.getHeight();
int provisionalVersion = (dimension - 17) >> 2;
int provisionalVersion = (dimension - 17) / 4;
if (provisionalVersion <= 6) {
return Version.getVersionForNumber(provisionalVersion);
}

View File

@ -125,7 +125,7 @@ abstract class DataMask {
private static final class DataMask100 extends DataMask {
@Override
boolean isMasked(int i, int j) {
return (((i >>> 1) + (j /3)) & 0x01) == 0;
return (((i / 2) + (j /3)) & 0x01) == 0;
}
}

View File

@ -217,7 +217,7 @@ final class DecodedBitStreamParser {
Collection<byte[]> byteSegments,
Map<DecodeHintType,?> hints) throws FormatException {
// Don't crash trying to read more bits than we have available.
if (count << 3 > bits.available()) {
if (8 * count > bits.available()) {
throw FormatException.getFormatInstance();
}

View File

@ -94,7 +94,7 @@ public final class Version {
throw FormatException.getFormatInstance();
}
try {
return getVersionForNumber((dimension - 17) >> 2);
return getVersionForNumber((dimension - 17) / 4);
} catch (IllegalArgumentException ignored) {
throw FormatException.getFormatInstance();
}

View File

@ -88,13 +88,13 @@ final class AlignmentPatternFinder {
int startX = this.startX;
int height = this.height;
int maxJ = startX + width;
int middleI = startY + (height >> 1);
int middleI = startY + (height / 2);
// We are looking for black/white/black modules in 1:1:1 ratio;
// this tracks the number of black/white/black modules seen so far
int[] stateCount = new int[3];
for (int iGen = 0; iGen < height; iGen++) {
// Search from middle outwards
int i = middleI + ((iGen & 0x01) == 0 ? (iGen + 1) >> 1 : -((iGen + 1) >> 1));
int i = middleI + ((iGen & 0x01) == 0 ? (iGen + 1) / 2 : -((iGen + 1) / 2));
stateCount[0] = 0;
stateCount[1] = 0;
stateCount[2] = 0;

View File

@ -201,7 +201,7 @@ public class Detector {
float moduleSize) throws NotFoundException {
int tltrCentersDimension = MathUtils.round(ResultPoint.distance(topLeft, topRight) / moduleSize);
int tlblCentersDimension = MathUtils.round(ResultPoint.distance(topLeft, bottomLeft) / moduleSize);
int dimension = ((tltrCentersDimension + tlblCentersDimension) >> 1) + 7;
int dimension = ((tltrCentersDimension + tlblCentersDimension) / 2) + 7;
switch (dimension & 0x03) { // mod 4
case 0:
dimension++;
@ -318,7 +318,7 @@ public class Detector {
int dx = Math.abs(toX - fromX);
int dy = Math.abs(toY - fromY);
int error = -dx >> 1;
int error = -dx / 2;
int xstep = fromX < toX ? 1 : -1;
int ystep = fromY < toY ? 1 : -1;

View File

@ -42,7 +42,6 @@ public class FinderPatternFinder {
private static final int CENTER_QUORUM = 2;
protected static final int MIN_SKIP = 3; // 1 pixel/module times 3 modules/center
protected static final int MAX_MODULES = 57; // support up to version 10 for mobile clients
private static final int INTEGER_MATH_SHIFT = 8;
private final BitMatrix image;
private final List<FinderPattern> possibleCenters;
@ -209,14 +208,15 @@ public class FinderPatternFinder {
if (totalModuleSize < 7) {
return false;
}
int moduleSize = (totalModuleSize << INTEGER_MATH_SHIFT) / 7;
int maxVariance = moduleSize / 2;
float moduleSize = totalModuleSize / 7.0f;
float maxVariance = moduleSize / 2.0f;
// Allow less than 50% variance from 1-1-3-1-1 proportions
return Math.abs(moduleSize - (stateCount[0] << INTEGER_MATH_SHIFT)) < maxVariance &&
Math.abs(moduleSize - (stateCount[1] << INTEGER_MATH_SHIFT)) < maxVariance &&
Math.abs(3 * moduleSize - (stateCount[2] << INTEGER_MATH_SHIFT)) < 3 * maxVariance &&
Math.abs(moduleSize - (stateCount[3] << INTEGER_MATH_SHIFT)) < maxVariance &&
Math.abs(moduleSize - (stateCount[4] << INTEGER_MATH_SHIFT)) < maxVariance;
return
Math.abs(moduleSize - stateCount[0]) < maxVariance &&
Math.abs(moduleSize - stateCount[1]) < maxVariance &&
Math.abs(3.0f * moduleSize - stateCount[2]) < 3 * maxVariance &&
Math.abs(moduleSize - stateCount[3]) < maxVariance &&
Math.abs(moduleSize - stateCount[4]) < maxVariance;
}
private int[] getCrossCheckStateCount() {

View File

@ -268,7 +268,7 @@ public final class Encoder {
* 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;
int capacity = numDataBytes * 8;
if (bits.getSize() > capacity) {
throw new WriterException("data bits cannot fit in the QR Code" + bits.getSize() + " > " +
capacity);

View File

@ -163,7 +163,7 @@ final class MaskUtil {
intermediate = (y + x) % 3;
break;
case 4:
intermediate = ((y >>> 1) + (x / 3)) & 0x1;
intermediate = ((y / 2) + (x / 3)) & 0x1;
break;
case 5:
temp = y * x;

View File

@ -305,6 +305,9 @@ final class MatrixUtil {
// 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 == 0) {
throw new IllegalArgumentException("0 polynomial");
}
// 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);