Update zxing-core to 3.2.0
This commit is contained in:
parent
dd1853cab3
commit
474cc194ca
@ -30,8 +30,23 @@ public final class ChecksumException extends ReaderException {
|
|||||||
// do nothing
|
// do nothing
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ChecksumException getChecksumInstance() {
|
private ChecksumException(Throwable cause) {
|
||||||
return instance;
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
@ -44,12 +44,19 @@ public enum EncodeHintType {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Specifies a minimum barcode size (type {@link Dimension}). Only applicable to Data Matrix now.
|
* 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,
|
MIN_SIZE,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Specifies a maximum barcode size (type {@link Dimension}). Only applicable to Data Matrix now.
|
* Specifies a maximum barcode size (type {@link Dimension}). Only applicable to Data Matrix now.
|
||||||
|
*
|
||||||
|
* @deprecated without replacement
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
MAX_SIZE,
|
MAX_SIZE,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -28,11 +28,25 @@ public final class FormatException extends ReaderException {
|
|||||||
private static final FormatException instance = new FormatException();
|
private static final FormatException instance = new FormatException();
|
||||||
|
|
||||||
private FormatException() {
|
private FormatException() {
|
||||||
// do nothing
|
}
|
||||||
|
|
||||||
|
private FormatException(Throwable cause) {
|
||||||
|
super(cause);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static FormatException getFormatInstance() {
|
public static FormatException getFormatInstance() {
|
||||||
return instance;
|
if (isStackTrace) {
|
||||||
|
return new FormatException();
|
||||||
|
} else {
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static FormatException getFormatInstance(Throwable cause) {
|
||||||
|
if (isStackTrace) {
|
||||||
|
return new FormatException(cause);
|
||||||
|
} else {
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -54,7 +54,7 @@ public final class RGBLuminanceSource extends LuminanceSource {
|
|||||||
luminances[offset + x] = (byte) r;
|
luminances[offset + x] = (byte) r;
|
||||||
} else {
|
} else {
|
||||||
// Calculate luminance cheaply, favoring green.
|
// Calculate luminance cheaply, favoring green.
|
||||||
luminances[offset + x] = (byte) ((r + g + g + b) >> 2);
|
luminances[offset + x] = (byte) ((r + 2 * g + b) / 4);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,10 +25,17 @@ package com.google.zxing;
|
|||||||
*/
|
*/
|
||||||
public abstract class ReaderException extends Exception {
|
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() {
|
ReaderException() {
|
||||||
// do nothing
|
// do nothing
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ReaderException(Throwable cause) {
|
||||||
|
super(cause);
|
||||||
|
}
|
||||||
|
|
||||||
// Prevent stack traces from being taken
|
// Prevent stack traces from being taken
|
||||||
// srowen says: huh, my IDE is saying this is not an override. native methods can't be overridden?
|
// 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.
|
// This, at least, does not hurt. Because we use a singleton pattern here, it doesn't matter anyhow.
|
||||||
|
@ -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
|
* 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.
|
* 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) {
|
public static void orderBestPatterns(ResultPoint[] patterns) {
|
||||||
|
|
||||||
|
@ -215,6 +215,9 @@ public final class Decoder {
|
|||||||
|
|
||||||
int numDataCodewords = ddata.getNbDatablocks();
|
int numDataCodewords = ddata.getNbDatablocks();
|
||||||
int numCodewords = rawbits.length / codewordSize;
|
int numCodewords = rawbits.length / codewordSize;
|
||||||
|
if (numCodewords < numDataCodewords) {
|
||||||
|
throw FormatException.getFormatInstance();
|
||||||
|
}
|
||||||
int offset = rawbits.length % codewordSize;
|
int offset = rawbits.length % codewordSize;
|
||||||
int numECCodewords = numCodewords - numDataCodewords;
|
int numECCodewords = numCodewords - numDataCodewords;
|
||||||
|
|
||||||
@ -226,8 +229,8 @@ public final class Decoder {
|
|||||||
try {
|
try {
|
||||||
ReedSolomonDecoder rsDecoder = new ReedSolomonDecoder(gf);
|
ReedSolomonDecoder rsDecoder = new ReedSolomonDecoder(gf);
|
||||||
rsDecoder.decode(dataWords, numECCodewords);
|
rsDecoder.decode(dataWords, numECCodewords);
|
||||||
} catch (ReedSolomonException ignored) {
|
} catch (ReedSolomonException ex) {
|
||||||
throw FormatException.getFormatInstance();
|
throw FormatException.getFormatInstance(ex);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now perform the unstuffing operation.
|
// Now perform the unstuffing operation.
|
||||||
@ -323,7 +326,7 @@ public final class Decoder {
|
|||||||
for (int i = startIndex; i < startIndex + length; i++) {
|
for (int i = startIndex; i < startIndex + length; i++) {
|
||||||
res <<= 1;
|
res <<= 1;
|
||||||
if (rawbits[i]) {
|
if (rawbits[i]) {
|
||||||
res++;
|
res |= 0x01;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
|
@ -21,24 +21,48 @@ package com.google.zxing.client.result;
|
|||||||
*/
|
*/
|
||||||
public final class EmailAddressParsedResult extends ParsedResult {
|
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 subject;
|
||||||
private final String body;
|
private final String body;
|
||||||
private final String mailtoURI;
|
|
||||||
|
|
||||||
EmailAddressParsedResult(String emailAddress,
|
EmailAddressParsedResult(String to) {
|
||||||
String subject,
|
this(new String[] {to}, null, null, null, null);
|
||||||
String body,
|
|
||||||
String mailtoURI) {
|
|
||||||
super(ParsedResultType.EMAIL_ADDRESS);
|
|
||||||
this.emailAddress = emailAddress;
|
|
||||||
this.subject = subject;
|
|
||||||
this.body = body;
|
|
||||||
this.mailtoURI = mailtoURI;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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() {
|
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() {
|
public String getSubject() {
|
||||||
@ -49,14 +73,21 @@ public final class EmailAddressParsedResult extends ParsedResult {
|
|||||||
return body;
|
return body;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return "mailto:"
|
||||||
|
* @deprecated without replacement
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
public String getMailtoURI() {
|
public String getMailtoURI() {
|
||||||
return mailtoURI;
|
return "mailto:";
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getDisplayResult() {
|
public String getDisplayResult() {
|
||||||
StringBuilder result = new StringBuilder(30);
|
StringBuilder result = new StringBuilder(30);
|
||||||
maybeAppend(emailAddress, result);
|
maybeAppend(tos, result);
|
||||||
|
maybeAppend(ccs, result);
|
||||||
|
maybeAppend(bccs, result);
|
||||||
maybeAppend(subject, result);
|
maybeAppend(subject, result);
|
||||||
maybeAppend(body, result);
|
maybeAppend(body, result);
|
||||||
return result.toString();
|
return result.toString();
|
||||||
|
@ -19,6 +19,7 @@ package com.google.zxing.client.result;
|
|||||||
import com.google.zxing.Result;
|
import com.google.zxing.Result;
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a result that encodes an e-mail address, either as a plain address
|
* 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 {
|
public final class EmailAddressResultParser extends ResultParser {
|
||||||
|
|
||||||
|
private static final Pattern COMMA = Pattern.compile(",");
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public EmailAddressParsedResult parse(Result result) {
|
public EmailAddressParsedResult parse(Result result) {
|
||||||
String rawText = getMassagedText(result);
|
String rawText = getMassagedText(result);
|
||||||
String emailAddress;
|
|
||||||
if (rawText.startsWith("mailto:") || rawText.startsWith("MAILTO:")) {
|
if (rawText.startsWith("mailto:") || rawText.startsWith("MAILTO:")) {
|
||||||
// If it starts with mailto:, assume it is definitely trying to be an email address
|
// If it starts with mailto:, assume it is definitely trying to be an email address
|
||||||
emailAddress = rawText.substring(7);
|
String hostEmail = rawText.substring(7);
|
||||||
int queryStart = emailAddress.indexOf('?');
|
int queryStart = hostEmail.indexOf('?');
|
||||||
if (queryStart >= 0) {
|
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);
|
Map<String,String> nameValues = parseNameValuePairs(rawText);
|
||||||
|
String[] ccs = null;
|
||||||
|
String[] bccs = null;
|
||||||
String subject = null;
|
String subject = null;
|
||||||
String body = null;
|
String body = null;
|
||||||
if (nameValues != null) {
|
if (nameValues != null) {
|
||||||
if (emailAddress.isEmpty()) {
|
if (tos == null) {
|
||||||
emailAddress = nameValues.get("to");
|
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");
|
subject = nameValues.get("subject");
|
||||||
body = nameValues.get("body");
|
body = nameValues.get("body");
|
||||||
}
|
}
|
||||||
return new EmailAddressParsedResult(emailAddress, subject, body, rawText);
|
return new EmailAddressParsedResult(tos, ccs, bccs, subject, body);
|
||||||
} else {
|
} else {
|
||||||
if (!EmailDoCoMoResultParser.isBasicallyValidEmailAddress(rawText)) {
|
if (!EmailDoCoMoResultParser.isBasicallyValidEmailAddress(rawText)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
emailAddress = rawText;
|
return new EmailAddressParsedResult(rawText);
|
||||||
return new EmailAddressParsedResult(emailAddress, null, null, "mailto:" + emailAddress);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,17 +37,18 @@ public final class EmailDoCoMoResultParser extends AbstractDoCoMoResultParser {
|
|||||||
if (!rawText.startsWith("MATMSG:")) {
|
if (!rawText.startsWith("MATMSG:")) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
String[] rawTo = matchDoCoMoPrefixedField("TO:", rawText, true);
|
String[] tos = matchDoCoMoPrefixedField("TO:", rawText, true);
|
||||||
if (rawTo == null) {
|
if (tos == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
String to = rawTo[0];
|
for (String to : tos) {
|
||||||
if (!isBasicallyValidEmailAddress(to)) {
|
if (!isBasicallyValidEmailAddress(to)) {
|
||||||
return null;
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
String subject = matchSingleDoCoMoPrefixedField("SUB:", rawText, false);
|
String subject = matchSingleDoCoMoPrefixedField("SUB:", rawText, false);
|
||||||
String body = matchSingleDoCoMoPrefixedField("BODY:", rawText, false);
|
String body = matchSingleDoCoMoPrefixedField("BODY:", rawText, false);
|
||||||
return new EmailAddressParsedResult(to, subject, body, "mailto:" + to);
|
return new EmailAddressParsedResult(tos, null, null, subject, body);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -116,7 +116,7 @@ public abstract class ResultParser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected static String unescapeBackslash(String escaped) {
|
protected static String unescapeBackslash(String escaped) {
|
||||||
int backslash = escaped.indexOf((int) '\\');
|
int backslash = escaped.indexOf('\\');
|
||||||
if (backslash < 0) {
|
if (backslash < 0) {
|
||||||
return escaped;
|
return escaped;
|
||||||
}
|
}
|
||||||
@ -208,13 +208,13 @@ public abstract class ResultParser {
|
|||||||
int start = i; // Found the start of a match here
|
int start = i; // Found the start of a match here
|
||||||
boolean more = true;
|
boolean more = true;
|
||||||
while (more) {
|
while (more) {
|
||||||
i = rawText.indexOf((int) endChar, i);
|
i = rawText.indexOf(endChar, i);
|
||||||
if (i < 0) {
|
if (i < 0) {
|
||||||
// No terminating end character? uh, done. Set i such that loop terminates and break
|
// No terminating end character? uh, done. Set i such that loop terminates and break
|
||||||
i = rawText.length();
|
i = rawText.length();
|
||||||
more = false;
|
more = false;
|
||||||
} else if (rawText.charAt(i - 1) == '\\') {
|
} else if (countPrecedingBackslashes(rawText, i) % 2 != 0) {
|
||||||
// semicolon was escaped so continue
|
// semicolon was escaped (odd count of preceding backslashes) so continue
|
||||||
i++;
|
i++;
|
||||||
} else {
|
} else {
|
||||||
// found a match
|
// found a match
|
||||||
@ -239,6 +239,18 @@ public abstract class ResultParser {
|
|||||||
return matches.toArray(new String[matches.size()]);
|
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) {
|
static String matchSinglePrefixedField(String prefix, String rawText, char endChar, boolean trim) {
|
||||||
String[] matches = matchPrefixedField(prefix, rawText, endChar, trim);
|
String[] matches = matchPrefixedField(prefix, rawText, endChar, trim);
|
||||||
return matches == null ? null : matches[0];
|
return matches == null ? null : matches[0];
|
||||||
|
@ -45,7 +45,10 @@ public final class SMTPResultParser extends ResultParser {
|
|||||||
subject = subject.substring(0, colon);
|
subject = subject.substring(0, colon);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
String mailtoURI = "mailto:" + emailAddress;
|
return new EmailAddressParsedResult(new String[] {emailAddress},
|
||||||
return new EmailAddressParsedResult(emailAddress, subject, body, mailtoURI);
|
null,
|
||||||
|
null,
|
||||||
|
subject,
|
||||||
|
body);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -28,7 +28,8 @@ import java.util.regex.Pattern;
|
|||||||
*/
|
*/
|
||||||
public final class URIResultParser extends ResultParser {
|
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(
|
private static final Pattern URL_WITHOUT_PROTOCOL_PATTERN = Pattern.compile(
|
||||||
"([a-zA-Z0-9\\-]+\\.)+[a-zA-Z]{2,}" + // host name elements
|
"([a-zA-Z0-9\\-]+\\.)+[a-zA-Z]{2,}" + // host name elements
|
||||||
"(:\\d{1,5})?" + // maybe port
|
"(:\\d{1,5})?" + // maybe port
|
||||||
|
@ -51,7 +51,7 @@ public final class BitMatrix implements Cloneable {
|
|||||||
}
|
}
|
||||||
this.width = width;
|
this.width = width;
|
||||||
this.height = height;
|
this.height = height;
|
||||||
this.rowSize = (width + 31) >> 5;
|
this.rowSize = (width + 31) / 32;
|
||||||
bits = new int[rowSize * height];
|
bits = new int[rowSize * height];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -62,6 +62,66 @@ public final class BitMatrix implements Cloneable {
|
|||||||
this.bits = bits;
|
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>
|
* <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
|
* @return value of given bit in matrix
|
||||||
*/
|
*/
|
||||||
public boolean get(int x, int y) {
|
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;
|
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)
|
* @param y The vertical component (i.e. which row)
|
||||||
*/
|
*/
|
||||||
public void set(int x, int y) {
|
public void set(int x, int y) {
|
||||||
int offset = y * rowSize + (x >> 5);
|
int offset = y * rowSize + (x / 32);
|
||||||
bits[offset] |= 1 << (x & 0x1f);
|
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>
|
* <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)
|
* @param y The vertical component (i.e. which row)
|
||||||
*/
|
*/
|
||||||
public void flip(int x, int y) {
|
public void flip(int x, int y) {
|
||||||
int offset = y * rowSize + (x >> 5);
|
int offset = y * rowSize + (x / 32);
|
||||||
bits[offset] ^= 1 << (x & 0x1f);
|
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).
|
* Clears all bits (sets to false).
|
||||||
*/
|
*/
|
||||||
@ -129,7 +215,7 @@ public final class BitMatrix implements Cloneable {
|
|||||||
for (int y = top; y < bottom; y++) {
|
for (int y = top; y < bottom; y++) {
|
||||||
int offset = y * rowSize;
|
int offset = y * rowSize;
|
||||||
for (int x = left; x < right; x++) {
|
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;
|
int offset = y * rowSize;
|
||||||
for (int x = 0; x < rowSize; x++) {
|
for (int x = 0; x < rowSize; x++) {
|
||||||
row.setBulk(x << 5, bits[offset + x]);
|
row.setBulk(x * 32, bits[offset + x]);
|
||||||
}
|
}
|
||||||
return row;
|
return row;
|
||||||
}
|
}
|
||||||
@ -248,7 +334,7 @@ public final class BitMatrix implements Cloneable {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
int y = bitsOffset / rowSize;
|
int y = bitsOffset / rowSize;
|
||||||
int x = (bitsOffset % rowSize) << 5;
|
int x = (bitsOffset % rowSize) * 32;
|
||||||
|
|
||||||
int theBits = bits[bitsOffset];
|
int theBits = bits[bitsOffset];
|
||||||
int bit = 0;
|
int bit = 0;
|
||||||
@ -269,7 +355,7 @@ public final class BitMatrix implements Cloneable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int y = bitsOffset / rowSize;
|
int y = bitsOffset / rowSize;
|
||||||
int x = (bitsOffset % rowSize) << 5;
|
int x = (bitsOffset % rowSize) * 32;
|
||||||
|
|
||||||
int theBits = bits[bitsOffset];
|
int theBits = bits[bitsOffset];
|
||||||
int bit = 31;
|
int bit = 31;
|
||||||
@ -295,6 +381,13 @@ public final class BitMatrix implements Cloneable {
|
|||||||
return height;
|
return height;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return The row size of the matrix
|
||||||
|
*/
|
||||||
|
public int getRowSize() {
|
||||||
|
return rowSize;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object o) {
|
public boolean equals(Object o) {
|
||||||
if (!(o instanceof BitMatrix)) {
|
if (!(o instanceof BitMatrix)) {
|
||||||
@ -317,12 +410,24 @@ public final class BitMatrix implements Cloneable {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
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));
|
StringBuilder result = new StringBuilder(height * (width + 1));
|
||||||
for (int y = 0; y < height; y++) {
|
for (int y = 0; y < height; y++) {
|
||||||
for (int x = 0; x < width; x++) {
|
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();
|
return result.toString();
|
||||||
}
|
}
|
||||||
|
@ -95,7 +95,7 @@ public enum CharacterSetECI {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @param value character set ECI value
|
* @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
|
* unsupported
|
||||||
* @throws FormatException if ECI value is invalid
|
* @throws FormatException if ECI value is invalid
|
||||||
*/
|
*/
|
||||||
|
@ -52,12 +52,12 @@ public final class DefaultGridSampler extends GridSampler {
|
|||||||
throw NotFoundException.getNotFoundInstance();
|
throw NotFoundException.getNotFoundInstance();
|
||||||
}
|
}
|
||||||
BitMatrix bits = new BitMatrix(dimensionX, dimensionY);
|
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++) {
|
for (int y = 0; y < dimensionY; y++) {
|
||||||
int max = points.length;
|
int max = points.length;
|
||||||
float iValue = (float) y + 0.5f;
|
float iValue = (float) y + 0.5f;
|
||||||
for (int x = 0; x < max; x += 2) {
|
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;
|
points[x + 1] = iValue;
|
||||||
}
|
}
|
||||||
transform.transformPoints(points);
|
transform.transformPoints(points);
|
||||||
@ -68,7 +68,7 @@ public final class DefaultGridSampler extends GridSampler {
|
|||||||
for (int x = 0; x < max; x += 2) {
|
for (int x = 0; x < max; x += 2) {
|
||||||
if (image.get((int) points[x], (int) points[x + 1])) {
|
if (image.get((int) points[x], (int) points[x + 1])) {
|
||||||
// Black(-ish) pixel
|
// Black(-ish) pixel
|
||||||
bits.set(x >> 1, y);
|
bits.set(x / 2, y);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (ArrayIndexOutOfBoundsException aioobe) {
|
} catch (ArrayIndexOutOfBoundsException aioobe) {
|
||||||
|
@ -72,7 +72,7 @@ public class GlobalHistogramBinarizer extends Binarizer {
|
|||||||
for (int x = 1; x < width - 1; x++) {
|
for (int x = 1; x < width - 1; x++) {
|
||||||
int right = localLuminances[x + 1] & 0xff;
|
int right = localLuminances[x + 1] & 0xff;
|
||||||
// A simple -1 4 -1 box filter with a weight of 2.
|
// 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) {
|
if (luminance < blackPoint) {
|
||||||
row.set(x);
|
row.set(x);
|
||||||
}
|
}
|
||||||
@ -97,7 +97,7 @@ public class GlobalHistogramBinarizer extends Binarizer {
|
|||||||
for (int y = 1; y < 5; y++) {
|
for (int y = 1; y < 5; y++) {
|
||||||
int row = height * y / 5;
|
int row = height * y / 5;
|
||||||
byte[] localLuminances = source.getRow(row, luminances);
|
byte[] localLuminances = source.getRow(row, luminances);
|
||||||
int right = (width << 2) / 5;
|
int right = (width * 4) / 5;
|
||||||
for (int x = width / 5; x < right; x++) {
|
for (int x = width / 5; x < right; x++) {
|
||||||
int pixel = localLuminances[x] & 0xff;
|
int pixel = localLuminances[x] & 0xff;
|
||||||
localBuckets[pixel >> LUMINANCE_SHIFT]++;
|
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
|
// 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.
|
// 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();
|
throw NotFoundException.getNotFoundInstance();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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 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.
|
// 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) {
|
if (y > 0 && x > 0) {
|
||||||
// Correct the "white background" assumption for blocks that have neighbors by comparing
|
// 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 boundaries is used for the interior.
|
||||||
|
|
||||||
// The (min < bp) is arbitrary but works better than other heuristics that were tried.
|
// 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]) +
|
int averageNeighborBlackPoint =
|
||||||
blackPoints[y - 1][x - 1]) >> 2;
|
(blackPoints[y - 1][x] + (2 * blackPoints[y][x - 1]) + blackPoints[y - 1][x - 1]) / 4;
|
||||||
if (min < averageNeighborBlackPoint) {
|
if (min < averageNeighborBlackPoint) {
|
||||||
average = averageNeighborBlackPoint;
|
average = averageNeighborBlackPoint;
|
||||||
}
|
}
|
||||||
|
@ -23,13 +23,15 @@ public final class MathUtils {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Ends up being a bit faster than {@link Math#round(float)}. This merely rounds its
|
* 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
|
* @param d real value to round
|
||||||
* @return nearest {@code int}
|
* @return nearest {@code int}
|
||||||
*/
|
*/
|
||||||
public static int round(float d) {
|
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) {
|
public static float distance(float aX, float aY, float bX, float bY) {
|
||||||
|
@ -50,31 +50,31 @@ public final class MonochromeRectangleDetector {
|
|||||||
public ResultPoint[] detect() throws NotFoundException {
|
public ResultPoint[] detect() throws NotFoundException {
|
||||||
int height = image.getHeight();
|
int height = image.getHeight();
|
||||||
int width = image.getWidth();
|
int width = image.getWidth();
|
||||||
int halfHeight = height >> 1;
|
int halfHeight = height / 2;
|
||||||
int halfWidth = width >> 1;
|
int halfWidth = width / 2;
|
||||||
int deltaY = Math.max(1, height / (MAX_MODULES << 3));
|
int deltaY = Math.max(1, height / (MAX_MODULES * 8));
|
||||||
int deltaX = Math.max(1, width / (MAX_MODULES << 3));
|
int deltaX = Math.max(1, width / (MAX_MODULES * 8));
|
||||||
|
|
||||||
int top = 0;
|
int top = 0;
|
||||||
int bottom = height;
|
int bottom = height;
|
||||||
int left = 0;
|
int left = 0;
|
||||||
int right = width;
|
int right = width;
|
||||||
ResultPoint pointA = findCornerFromCenter(halfWidth, 0, left, right,
|
ResultPoint pointA = findCornerFromCenter(halfWidth, 0, left, right,
|
||||||
halfHeight, -deltaY, top, bottom, halfWidth >> 1);
|
halfHeight, -deltaY, top, bottom, halfWidth / 2);
|
||||||
top = (int) pointA.getY() - 1;
|
top = (int) pointA.getY() - 1;
|
||||||
ResultPoint pointB = findCornerFromCenter(halfWidth, -deltaX, left, right,
|
ResultPoint pointB = findCornerFromCenter(halfWidth, -deltaX, left, right,
|
||||||
halfHeight, 0, top, bottom, halfHeight >> 1);
|
halfHeight, 0, top, bottom, halfHeight / 2);
|
||||||
left = (int) pointB.getX() - 1;
|
left = (int) pointB.getX() - 1;
|
||||||
ResultPoint pointC = findCornerFromCenter(halfWidth, deltaX, left, right,
|
ResultPoint pointC = findCornerFromCenter(halfWidth, deltaX, left, right,
|
||||||
halfHeight, 0, top, bottom, halfHeight >> 1);
|
halfHeight, 0, top, bottom, halfHeight / 2);
|
||||||
right = (int) pointC.getX() + 1;
|
right = (int) pointC.getX() + 1;
|
||||||
ResultPoint pointD = findCornerFromCenter(halfWidth, 0, left, right,
|
ResultPoint pointD = findCornerFromCenter(halfWidth, 0, left, right,
|
||||||
halfHeight, deltaY, top, bottom, halfWidth >> 1);
|
halfHeight, deltaY, top, bottom, halfWidth / 2);
|
||||||
bottom = (int) pointD.getY() + 1;
|
bottom = (int) pointD.getY() + 1;
|
||||||
|
|
||||||
// Go try to find point A again with better information -- might have been off at first.
|
// Go try to find point A again with better information -- might have been off at first.
|
||||||
pointA = findCornerFromCenter(halfWidth, 0, left, right,
|
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 };
|
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) {
|
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
|
// Scan left/up first
|
||||||
int start = center;
|
int start = center;
|
||||||
|
@ -38,16 +38,13 @@ public final class GenericGF {
|
|||||||
public static final GenericGF AZTEC_DATA_8 = DATA_MATRIX_FIELD_256;
|
public static final GenericGF AZTEC_DATA_8 = DATA_MATRIX_FIELD_256;
|
||||||
public static final GenericGF MAXICODE_FIELD_64 = AZTEC_DATA_6;
|
public static final GenericGF MAXICODE_FIELD_64 = AZTEC_DATA_6;
|
||||||
|
|
||||||
private static final int INITIALIZATION_THRESHOLD = 0;
|
private final int[] expTable;
|
||||||
|
private final int[] logTable;
|
||||||
private int[] expTable;
|
private final GenericGFPoly zero;
|
||||||
private int[] logTable;
|
private final GenericGFPoly one;
|
||||||
private GenericGFPoly zero;
|
|
||||||
private GenericGFPoly one;
|
|
||||||
private final int size;
|
private final int size;
|
||||||
private final int primitive;
|
private final int primitive;
|
||||||
private final int generatorBase;
|
private final int generatorBase;
|
||||||
private boolean initialized = false;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a representation of GF(size) using the given primitive polynomial.
|
* Create a representation of GF(size) using the given primitive polynomial.
|
||||||
@ -64,19 +61,13 @@ public final class GenericGF {
|
|||||||
this.primitive = primitive;
|
this.primitive = primitive;
|
||||||
this.size = size;
|
this.size = size;
|
||||||
this.generatorBase = b;
|
this.generatorBase = b;
|
||||||
|
|
||||||
if (size <= INITIALIZATION_THRESHOLD) {
|
|
||||||
initialize();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void initialize() {
|
|
||||||
expTable = new int[size];
|
expTable = new int[size];
|
||||||
logTable = new int[size];
|
logTable = new int[size];
|
||||||
int x = 1;
|
int x = 1;
|
||||||
for (int i = 0; i < size; i++) {
|
for (int i = 0; i < size; i++) {
|
||||||
expTable[i] = x;
|
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) {
|
if (x >= size) {
|
||||||
x ^= primitive;
|
x ^= primitive;
|
||||||
x &= size-1;
|
x &= size-1;
|
||||||
@ -88,24 +79,13 @@ public final class GenericGF {
|
|||||||
// logTable[0] == 0 but this should never be used
|
// logTable[0] == 0 but this should never be used
|
||||||
zero = new GenericGFPoly(this, new int[]{0});
|
zero = new GenericGFPoly(this, new int[]{0});
|
||||||
one = new GenericGFPoly(this, new int[]{1});
|
one = new GenericGFPoly(this, new int[]{1});
|
||||||
initialized = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkInit() {
|
|
||||||
if (!initialized) {
|
|
||||||
initialize();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
GenericGFPoly getZero() {
|
|
||||||
checkInit();
|
|
||||||
|
|
||||||
|
GenericGFPoly getZero() {
|
||||||
return zero;
|
return zero;
|
||||||
}
|
}
|
||||||
|
|
||||||
GenericGFPoly getOne() {
|
GenericGFPoly getOne() {
|
||||||
checkInit();
|
|
||||||
|
|
||||||
return one;
|
return one;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -113,8 +93,6 @@ public final class GenericGF {
|
|||||||
* @return the monomial representing coefficient * x^degree
|
* @return the monomial representing coefficient * x^degree
|
||||||
*/
|
*/
|
||||||
GenericGFPoly buildMonomial(int degree, int coefficient) {
|
GenericGFPoly buildMonomial(int degree, int coefficient) {
|
||||||
checkInit();
|
|
||||||
|
|
||||||
if (degree < 0) {
|
if (degree < 0) {
|
||||||
throw new IllegalArgumentException();
|
throw new IllegalArgumentException();
|
||||||
}
|
}
|
||||||
@ -139,8 +117,6 @@ public final class GenericGF {
|
|||||||
* @return 2 to the power of a in GF(size)
|
* @return 2 to the power of a in GF(size)
|
||||||
*/
|
*/
|
||||||
int exp(int a) {
|
int exp(int a) {
|
||||||
checkInit();
|
|
||||||
|
|
||||||
return expTable[a];
|
return expTable[a];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -148,8 +124,6 @@ public final class GenericGF {
|
|||||||
* @return base 2 log of a in GF(size)
|
* @return base 2 log of a in GF(size)
|
||||||
*/
|
*/
|
||||||
int log(int a) {
|
int log(int a) {
|
||||||
checkInit();
|
|
||||||
|
|
||||||
if (a == 0) {
|
if (a == 0) {
|
||||||
throw new IllegalArgumentException();
|
throw new IllegalArgumentException();
|
||||||
}
|
}
|
||||||
@ -160,8 +134,6 @@ public final class GenericGF {
|
|||||||
* @return multiplicative inverse of a
|
* @return multiplicative inverse of a
|
||||||
*/
|
*/
|
||||||
int inverse(int a) {
|
int inverse(int a) {
|
||||||
checkInit();
|
|
||||||
|
|
||||||
if (a == 0) {
|
if (a == 0) {
|
||||||
throw new ArithmeticException();
|
throw new ArithmeticException();
|
||||||
}
|
}
|
||||||
@ -172,8 +144,6 @@ public final class GenericGF {
|
|||||||
* @return product of a and b in GF(size)
|
* @return product of a and b in GF(size)
|
||||||
*/
|
*/
|
||||||
int multiply(int a, int b) {
|
int multiply(int a, int b) {
|
||||||
checkInit();
|
|
||||||
|
|
||||||
if (a == 0 || b == 0) {
|
if (a == 0 || b == 0) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -52,7 +52,7 @@ final class GenericGFPoly {
|
|||||||
firstNonZero++;
|
firstNonZero++;
|
||||||
}
|
}
|
||||||
if (firstNonZero == coefficientsLength) {
|
if (firstNonZero == coefficientsLength) {
|
||||||
this.coefficients = field.getZero().coefficients;
|
this.coefficients = new int[]{0};
|
||||||
} else {
|
} else {
|
||||||
this.coefficients = new int[coefficientsLength - firstNonZero];
|
this.coefficients = new int[coefficientsLength - firstNonZero];
|
||||||
System.arraycopy(coefficients,
|
System.arraycopy(coefficients,
|
||||||
|
@ -123,7 +123,7 @@ public final class DataMatrixReader implements Reader {
|
|||||||
// Push in the "border" by half the module width so that we start
|
// 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
|
// sampling in the middle of the module. Just in case the image is a
|
||||||
// little off, this will help recover.
|
// little off, this will help recover.
|
||||||
int nudge = moduleSize >> 1;
|
int nudge = moduleSize / 2;
|
||||||
top += nudge;
|
top += nudge;
|
||||||
left += nudge;
|
left += nudge;
|
||||||
|
|
||||||
|
@ -60,17 +60,19 @@ public final class DataMatrixWriter implements Writer {
|
|||||||
|
|
||||||
// Try to get force shape & min / max size
|
// Try to get force shape & min / max size
|
||||||
SymbolShapeHint shape = SymbolShapeHint.FORCE_NONE;
|
SymbolShapeHint shape = SymbolShapeHint.FORCE_NONE;
|
||||||
Dimension minSize = null;
|
Dimension minSize = new Dimension(width, height);
|
||||||
Dimension maxSize = null;
|
Dimension maxSize = null;
|
||||||
if (hints != null) {
|
if (hints != null) {
|
||||||
SymbolShapeHint requestedShape = (SymbolShapeHint) hints.get(EncodeHintType.DATA_MATRIX_SHAPE);
|
SymbolShapeHint requestedShape = (SymbolShapeHint) hints.get(EncodeHintType.DATA_MATRIX_SHAPE);
|
||||||
if (requestedShape != null) {
|
if (requestedShape != null) {
|
||||||
shape = requestedShape;
|
shape = requestedShape;
|
||||||
}
|
}
|
||||||
|
@SuppressWarnings("deprecation")
|
||||||
Dimension requestedMinSize = (Dimension) hints.get(EncodeHintType.MIN_SIZE);
|
Dimension requestedMinSize = (Dimension) hints.get(EncodeHintType.MIN_SIZE);
|
||||||
if (requestedMinSize != null) {
|
if (requestedMinSize != null) {
|
||||||
minSize = requestedMinSize;
|
minSize = requestedMinSize;
|
||||||
}
|
}
|
||||||
|
@SuppressWarnings("deprecation")
|
||||||
Dimension requestedMaxSize = (Dimension) hints.get(EncodeHintType.MAX_SIZE);
|
Dimension requestedMaxSize = (Dimension) hints.get(EncodeHintType.MAX_SIZE);
|
||||||
if (requestedMaxSize != null) {
|
if (requestedMaxSize != null) {
|
||||||
maxSize = requestedMaxSize;
|
maxSize = requestedMaxSize;
|
||||||
|
@ -94,8 +94,9 @@ final class DataBlock {
|
|||||||
int max = result[0].codewords.length;
|
int max = result[0].codewords.length;
|
||||||
for (int i = longerBlocksNumDataCodewords; i < max; i++) {
|
for (int i = longerBlocksNumDataCodewords; i < max; i++) {
|
||||||
for (int j = 0; j < numResultBlocks; j++) {
|
for (int j = 0; j < numResultBlocks; j++) {
|
||||||
int iOffset = specialVersion && j > 7 ? i - 1 : i;
|
int jOffset = specialVersion ? (j + 8) % numResultBlocks : j;
|
||||||
result[j].codewords[iOffset] = rawCodewords[rawCodewordsOffset++];
|
int iOffset = specialVersion && jOffset > 7 ? i - 1 : i;
|
||||||
|
result[jOffset].codewords[iOffset] = rawCodewords[rawCodewordsOffset++];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -71,6 +71,9 @@ final class DecodedBitStreamParser {
|
|||||||
'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'
|
'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 = {
|
private static final char[] TEXT_SHIFT3_SET_CHARS = {
|
||||||
'`', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
|
'`', '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
|
'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;
|
return Mode.PAD_ENCODE;
|
||||||
} else if (oneByte <= 229) { // 2-digit data 00-99 (Numeric Value + 130)
|
} else if (oneByte <= 229) { // 2-digit data 00-99 (Numeric Value + 130)
|
||||||
int value = oneByte - 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('0');
|
||||||
}
|
}
|
||||||
result.append(value);
|
result.append(value);
|
||||||
@ -319,13 +322,13 @@ final class DecodedBitStreamParser {
|
|||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
// Shift 2 for Text is the same encoding as C40
|
// Shift 2 for Text is the same encoding as C40
|
||||||
if (cValue < C40_SHIFT2_SET_CHARS.length) {
|
if (cValue < TEXT_SHIFT2_SET_CHARS.length) {
|
||||||
char c40char = C40_SHIFT2_SET_CHARS[cValue];
|
char textChar = TEXT_SHIFT2_SET_CHARS[cValue];
|
||||||
if (upperShift) {
|
if (upperShift) {
|
||||||
result.append((char) (c40char + 128));
|
result.append((char) (textChar + 128));
|
||||||
upperShift = false;
|
upperShift = false;
|
||||||
} else {
|
} else {
|
||||||
result.append(c40char);
|
result.append(textChar);
|
||||||
}
|
}
|
||||||
} else if (cValue == 27) { // FNC1
|
} else if (cValue == 27) { // FNC1
|
||||||
result.append((char) 29); // translate as ASCII 29
|
result.append((char) 29); // translate as ASCII 29
|
||||||
|
@ -370,7 +370,7 @@ public final class Detector {
|
|||||||
|
|
||||||
int dx = Math.abs(toX - fromX);
|
int dx = Math.abs(toX - fromX);
|
||||||
int dy = Math.abs(toY - fromY);
|
int dy = Math.abs(toY - fromY);
|
||||||
int error = -dx >> 1;
|
int error = -dx / 2;
|
||||||
int ystep = fromY < toY ? 1 : -1;
|
int ystep = fromY < toY ? 1 : -1;
|
||||||
int xstep = fromX < toX ? 1 : -1;
|
int xstep = fromX < toX ? 1 : -1;
|
||||||
int transitions = 0;
|
int transitions = 0;
|
||||||
|
@ -81,7 +81,7 @@ public final class ErrorCorrection {
|
|||||||
for (int i = 0; i < 255; i++) {
|
for (int i = 0; i < 255; i++) {
|
||||||
ALOG[i] = p;
|
ALOG[i] = p;
|
||||||
LOG[p] = i;
|
LOG[p] = i;
|
||||||
p <<= 1;
|
p *= 2;
|
||||||
if (p >= 256) {
|
if (p >= 256) {
|
||||||
p ^= MODULO_VALUE;
|
p ^= MODULO_VALUE;
|
||||||
}
|
}
|
||||||
|
@ -72,16 +72,12 @@ final class X12Encoder extends C40Encoder {
|
|||||||
context.updateSymbolInfo();
|
context.updateSymbolInfo();
|
||||||
int available = context.getSymbolInfo().getDataCapacity() - context.getCodewordCount();
|
int available = context.getSymbolInfo().getDataCapacity() - context.getCodewordCount();
|
||||||
int count = buffer.length();
|
int count = buffer.length();
|
||||||
if (count == 2) {
|
context.pos -= count;
|
||||||
|
if (context.getRemainingCharacters() > 1 || available > 1 ||
|
||||||
|
context.getRemainingCharacters() != available) {
|
||||||
context.writeCodeword(HighLevelEncoder.X12_UNLATCH);
|
context.writeCodeword(HighLevelEncoder.X12_UNLATCH);
|
||||||
context.pos -= 2;
|
}
|
||||||
context.signalEncoderChange(HighLevelEncoder.ASCII_ENCODATION);
|
if (context.getNewEncoding() < 0) {
|
||||||
} else if (count == 1) {
|
|
||||||
context.pos--;
|
|
||||||
if (available > 1) {
|
|
||||||
context.writeCodeword(HighLevelEncoder.X12_UNLATCH);
|
|
||||||
}
|
|
||||||
//NOP - No unlatch necessary
|
|
||||||
context.signalEncoderChange(HighLevelEncoder.ASCII_ENCODATION);
|
context.signalEncoderChange(HighLevelEncoder.ASCII_ENCODATION);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -98,6 +98,9 @@ final class DecodedBitStreamParser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static int getInt(byte[] bytes, byte[] x) {
|
private static int getInt(byte[] bytes, byte[] x) {
|
||||||
|
if (x.length == 0) {
|
||||||
|
throw new IllegalArgumentException();
|
||||||
|
}
|
||||||
int val = 0;
|
int val = 0;
|
||||||
for (int i = 0; i < x.length; i++) {
|
for (int i = 0; i < x.length; i++) {
|
||||||
val += getBit(x[i], bytes) << (x.length - i - 1);
|
val += getBit(x[i], bytes) << (x.length - i - 1);
|
||||||
|
@ -23,6 +23,7 @@ import com.google.zxing.FormatException;
|
|||||||
import com.google.zxing.NotFoundException;
|
import com.google.zxing.NotFoundException;
|
||||||
import com.google.zxing.Reader;
|
import com.google.zxing.Reader;
|
||||||
import com.google.zxing.Result;
|
import com.google.zxing.Result;
|
||||||
|
import com.google.zxing.ResultPoint;
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
@ -58,30 +59,33 @@ public final class ByQuadrantReader implements Reader {
|
|||||||
int halfWidth = width / 2;
|
int halfWidth = width / 2;
|
||||||
int halfHeight = height / 2;
|
int halfHeight = height / 2;
|
||||||
|
|
||||||
BinaryBitmap topLeft = image.crop(0, 0, halfWidth, halfHeight);
|
|
||||||
try {
|
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) {
|
} catch (NotFoundException re) {
|
||||||
// continue
|
// continue
|
||||||
}
|
}
|
||||||
|
|
||||||
BinaryBitmap topRight = image.crop(halfWidth, 0, halfWidth, halfHeight);
|
|
||||||
try {
|
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) {
|
} catch (NotFoundException re) {
|
||||||
// continue
|
// continue
|
||||||
}
|
}
|
||||||
|
|
||||||
BinaryBitmap bottomLeft = image.crop(0, halfHeight, halfWidth, halfHeight);
|
|
||||||
try {
|
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) {
|
} catch (NotFoundException re) {
|
||||||
// continue
|
// continue
|
||||||
}
|
}
|
||||||
|
|
||||||
BinaryBitmap bottomRight = image.crop(halfWidth, halfHeight, halfWidth, halfHeight);
|
|
||||||
try {
|
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) {
|
} catch (NotFoundException re) {
|
||||||
// continue
|
// continue
|
||||||
}
|
}
|
||||||
@ -89,7 +93,9 @@ public final class ByQuadrantReader implements Reader {
|
|||||||
int quarterWidth = halfWidth / 2;
|
int quarterWidth = halfWidth / 2;
|
||||||
int quarterHeight = halfHeight / 2;
|
int quarterHeight = halfHeight / 2;
|
||||||
BinaryBitmap center = image.crop(quarterWidth, quarterHeight, halfWidth, halfHeight);
|
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
|
@Override
|
||||||
@ -97,4 +103,13 @@ public final class ByQuadrantReader implements Reader {
|
|||||||
delegate.reset();
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -106,6 +106,9 @@ public final class GenericMultipleBarcodeReader implements MultipleBarcodeReader
|
|||||||
float maxX = 0.0f;
|
float maxX = 0.0f;
|
||||||
float maxY = 0.0f;
|
float maxY = 0.0f;
|
||||||
for (ResultPoint point : resultPoints) {
|
for (ResultPoint point : resultPoints) {
|
||||||
|
if (point == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
float x = point.getX();
|
float x = point.getX();
|
||||||
float y = point.getY();
|
float y = point.getY();
|
||||||
if (x < minX) {
|
if (x < minX) {
|
||||||
@ -160,7 +163,9 @@ public final class GenericMultipleBarcodeReader implements MultipleBarcodeReader
|
|||||||
ResultPoint[] newResultPoints = new ResultPoint[oldResultPoints.length];
|
ResultPoint[] newResultPoints = new ResultPoint[oldResultPoints.length];
|
||||||
for (int i = 0; i < oldResultPoints.length; i++) {
|
for (int i = 0; i < oldResultPoints.length; i++) {
|
||||||
ResultPoint oldPoint = oldResultPoints[i];
|
ResultPoint oldPoint = oldResultPoints[i];
|
||||||
newResultPoints[i] = new ResultPoint(oldPoint.getX() + xOffset, oldPoint.getY() + yOffset);
|
if (oldPoint != null) {
|
||||||
|
newResultPoints[i] = new ResultPoint(oldPoint.getX() + xOffset, oldPoint.getY() + yOffset);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Result newResult = new Result(result.getText(), result.getRawBytes(), newResultPoints, result.getBarcodeFormat());
|
Result newResult = new Result(result.getText(), result.getRawBytes(), newResultPoints, result.getBarcodeFormat());
|
||||||
newResult.putAllMetadata(result.getResultMetadata());
|
newResult.putAllMetadata(result.getResultMetadata());
|
||||||
|
@ -37,8 +37,8 @@ public final class CodaBarReader extends OneDReader {
|
|||||||
// These values are critical for determining how permissive the decoding
|
// These values are critical for determining how permissive the decoding
|
||||||
// will be. All stripe sizes must be within the window these define, as
|
// will be. All stripe sizes must be within the window these define, as
|
||||||
// compared to the average stripe size.
|
// compared to the average stripe size.
|
||||||
private static final int MAX_ACCEPTABLE = (int) (PATTERN_MATCH_RESULT_SCALE_FACTOR * 2.0f);
|
private static final float MAX_ACCEPTABLE = 2.0f;
|
||||||
private static final int PADDING = (int) (PATTERN_MATCH_RESULT_SCALE_FACTOR * 1.5f);
|
private static final float PADDING = 1.5f;
|
||||||
|
|
||||||
private static final String ALPHABET_STRING = "0123456789-$:/.+ABCD";
|
private static final String ALPHABET_STRING = "0123456789-$:/.+ABCD";
|
||||||
static final char[] ALPHABET = ALPHABET_STRING.toCharArray();
|
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.
|
// Calculate our allowable size thresholds using fixed-point math.
|
||||||
int[] maxes = new int[4];
|
float[] maxes = new float[4];
|
||||||
int[] mins = new int[4];
|
float[] mins = new float[4];
|
||||||
// Define the threshold of acceptability to be the midpoint between the
|
// Define the threshold of acceptability to be the midpoint between the
|
||||||
// average small stripe and the average large stripe. No stripe lengths
|
// average small stripe and the average large stripe. No stripe lengths
|
||||||
// should be on the "wrong" side of that line.
|
// should be on the "wrong" side of that line.
|
||||||
for (int i = 0; i < 2; i++) {
|
for (int i = 0; i < 2; i++) {
|
||||||
mins[i] = 0; // Accept arbitrarily small "short" stripes.
|
mins[i] = 0.0f; // Accept arbitrarily small "short" stripes.
|
||||||
mins[i + 2] = ((sizes[i] << INTEGER_MATH_SHIFT) / counts[i] +
|
mins[i + 2] = ((float) sizes[i] / counts[i] + (float) sizes[i + 2] / counts[i + 2]) / 2.0f;
|
||||||
(sizes[i + 2] << INTEGER_MATH_SHIFT) / counts[i + 2]) >> 1;
|
|
||||||
maxes[i] = mins[i + 2];
|
maxes[i] = mins[i + 2];
|
||||||
maxes[i + 2] = (sizes[i + 2] * MAX_ACCEPTABLE + PADDING) / counts[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
|
// Even j = bars, while odd j = spaces. Categories 2 and 3 are for
|
||||||
// long stripes, while 0 and 1 are for short stripes.
|
// long stripes, while 0 and 1 are for short stripes.
|
||||||
int category = (j & 1) + (pattern & 1) * 2;
|
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]) {
|
if (size < mins[category] || size > maxes[category]) {
|
||||||
throw NotFoundException.getNotFoundInstance();
|
throw NotFoundException.getNotFoundInstance();
|
||||||
}
|
}
|
||||||
|
@ -16,8 +16,6 @@
|
|||||||
|
|
||||||
package com.google.zxing.oned;
|
package com.google.zxing.oned;
|
||||||
|
|
||||||
import java.util.Arrays;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class renders CodaBar as {@code boolean[]}.
|
* 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[] START_END_CHARS = {'A', 'B', 'C', 'D'};
|
||||||
private static final char[] ALT_START_END_CHARS = {'T', 'N', '*', 'E'};
|
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[] CHARS_WHICH_ARE_TEN_LENGTH_EACH_AFTER_DECODED = {'/', ':', '+', '.'};
|
||||||
|
private static final char DEFAULT_GUARD = START_END_CHARS[0];
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean[] encode(String contents) {
|
public boolean[] encode(String contents) {
|
||||||
|
|
||||||
if (contents.length() < 2) {
|
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;
|
||||||
// Verify input and calculate decoded length.
|
} else {
|
||||||
char firstChar = Character.toUpperCase(contents.charAt(0));
|
// Verify input and calculate decoded length.
|
||||||
char lastChar = Character.toUpperCase(contents.charAt(contents.length() - 1));
|
char firstChar = Character.toUpperCase(contents.charAt(0));
|
||||||
boolean startsEndsNormal =
|
char lastChar = Character.toUpperCase(contents.charAt(contents.length() - 1));
|
||||||
CodaBarReader.arrayContains(START_END_CHARS, firstChar) &&
|
boolean startsNormal = CodaBarReader.arrayContains(START_END_CHARS, firstChar);
|
||||||
CodaBarReader.arrayContains(START_END_CHARS, lastChar);
|
boolean endsNormal = CodaBarReader.arrayContains(START_END_CHARS, lastChar);
|
||||||
boolean startsEndsAlt =
|
boolean startsAlt = CodaBarReader.arrayContains(ALT_START_END_CHARS, firstChar);
|
||||||
CodaBarReader.arrayContains(ALT_START_END_CHARS, firstChar) &&
|
boolean endsAlt = CodaBarReader.arrayContains(ALT_START_END_CHARS, lastChar);
|
||||||
CodaBarReader.arrayContains(ALT_START_END_CHARS, lastChar);
|
if (startsNormal) {
|
||||||
if (!(startsEndsNormal || startsEndsAlt)) {
|
if (!endsNormal) {
|
||||||
throw new IllegalArgumentException(
|
throw new IllegalArgumentException("Invalid start/end guards: " + contents);
|
||||||
"Codabar should start/end with " + Arrays.toString(START_END_CHARS) +
|
}
|
||||||
", or start/end with " + Arrays.toString(ALT_START_END_CHARS));
|
// 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.
|
// The start character and the end character are decoded to 10 length each.
|
||||||
|
@ -146,8 +146,8 @@ public final class Code128Reader extends OneDReader {
|
|||||||
{2, 3, 3, 1, 1, 1, 2}
|
{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 float MAX_AVG_VARIANCE = 0.25f;
|
||||||
private static final int MAX_INDIVIDUAL_VARIANCE = (int) (PATTERN_MATCH_RESULT_SCALE_FACTOR * 0.7f);
|
private static final float MAX_INDIVIDUAL_VARIANCE = 0.7f;
|
||||||
|
|
||||||
private static final int CODE_SHIFT = 98;
|
private static final int CODE_SHIFT = 98;
|
||||||
|
|
||||||
@ -181,10 +181,10 @@ public final class Code128Reader extends OneDReader {
|
|||||||
counters[counterPosition]++;
|
counters[counterPosition]++;
|
||||||
} else {
|
} else {
|
||||||
if (counterPosition == patternLength - 1) {
|
if (counterPosition == patternLength - 1) {
|
||||||
int bestVariance = MAX_AVG_VARIANCE;
|
float bestVariance = MAX_AVG_VARIANCE;
|
||||||
int bestMatch = -1;
|
int bestMatch = -1;
|
||||||
for (int startCode = CODE_START_A; startCode <= CODE_START_C; startCode++) {
|
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);
|
MAX_INDIVIDUAL_VARIANCE);
|
||||||
if (variance < bestVariance) {
|
if (variance < bestVariance) {
|
||||||
bestVariance = variance;
|
bestVariance = variance;
|
||||||
@ -214,11 +214,11 @@ public final class Code128Reader extends OneDReader {
|
|||||||
private static int decodeCode(BitArray row, int[] counters, int rowOffset)
|
private static int decodeCode(BitArray row, int[] counters, int rowOffset)
|
||||||
throws NotFoundException {
|
throws NotFoundException {
|
||||||
recordPattern(row, rowOffset, counters);
|
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 bestMatch = -1;
|
||||||
for (int d = 0; d < CODE_PATTERNS.length; d++) {
|
for (int d = 0; d < CODE_PATTERNS.length; d++) {
|
||||||
int[] pattern = CODE_PATTERNS[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) {
|
if (variance < bestVariance) {
|
||||||
bestVariance = variance;
|
bestVariance = variance;
|
||||||
bestMatch = d;
|
bestMatch = d;
|
||||||
|
@ -136,7 +136,7 @@ public final class Code39Reader extends OneDReader {
|
|||||||
int whiteSpaceAfterEnd = nextStart - lastStart - lastPatternSize;
|
int whiteSpaceAfterEnd = nextStart - lastStart - lastPatternSize;
|
||||||
// If 50% of last pattern size, following last pattern, is not whitespace, fail
|
// 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)
|
// (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();
|
throw NotFoundException.getNotFoundInstance();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -192,7 +192,7 @@ public final class Code39Reader extends OneDReader {
|
|||||||
if (counterPosition == patternLength - 1) {
|
if (counterPosition == patternLength - 1) {
|
||||||
// Look for whitespace before start pattern, >= 50% of width of start pattern
|
// Look for whitespace before start pattern, >= 50% of width of start pattern
|
||||||
if (toNarrowWidePattern(counters) == ASTERISK_ENCODING &&
|
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};
|
return new int[]{patternStart, i};
|
||||||
}
|
}
|
||||||
patternStart += counters[0] + counters[1];
|
patternStart += counters[0] + counters[1];
|
||||||
@ -244,7 +244,7 @@ public final class Code39Reader extends OneDReader {
|
|||||||
if (counter > maxNarrowCounter) {
|
if (counter > maxNarrowCounter) {
|
||||||
wideCounters--;
|
wideCounters--;
|
||||||
// totalWideCountersWidth = 3 * average, so this checks if counter >= 3/2 * average
|
// totalWideCountersWidth = 3 * average, so this checks if counter >= 3/2 * average
|
||||||
if ((counter << 1) >= totalWideCountersWidth) {
|
if ((counter * 2) >= totalWideCountersWidth) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -170,20 +170,16 @@ public final class Code93Reader extends OneDReader {
|
|||||||
}
|
}
|
||||||
int pattern = 0;
|
int pattern = 0;
|
||||||
for (int i = 0; i < max; i++) {
|
for (int i = 0; i < max; i++) {
|
||||||
int scaledShifted = (counters[i] << INTEGER_MATH_SHIFT) * 9 / sum;
|
int scaled = Math.round(counters[i] * 9.0f / sum);
|
||||||
int scaledUnshifted = scaledShifted >> INTEGER_MATH_SHIFT;
|
if (scaled < 1 || scaled > 4) {
|
||||||
if ((scaledShifted & 0xFF) > 0x7F) {
|
|
||||||
scaledUnshifted++;
|
|
||||||
}
|
|
||||||
if (scaledUnshifted < 1 || scaledUnshifted > 4) {
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if ((i & 0x01) == 0) {
|
if ((i & 0x01) == 0) {
|
||||||
for (int j = 0; j < scaledUnshifted; j++) {
|
for (int j = 0; j < scaled; j++) {
|
||||||
pattern = (pattern << 1) | 0x01;
|
pattern = (pattern << 1) | 0x01;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
pattern <<= scaledUnshifted;
|
pattern <<= scaled;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return pattern;
|
return pattern;
|
||||||
|
@ -44,8 +44,8 @@ import java.util.Map;
|
|||||||
*/
|
*/
|
||||||
public final class ITFReader extends OneDReader {
|
public final class ITFReader extends OneDReader {
|
||||||
|
|
||||||
private static final int MAX_AVG_VARIANCE = (int) (PATTERN_MATCH_RESULT_SCALE_FACTOR * 0.42f);
|
private static final float MAX_AVG_VARIANCE = 0.38f;
|
||||||
private static final int MAX_INDIVIDUAL_VARIANCE = (int) (PATTERN_MATCH_RESULT_SCALE_FACTOR * 0.78f);
|
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 W = 3; // Pixel width of a wide line
|
||||||
private static final int N = 1; // Pixed width of a narrow 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);
|
recordPattern(row, payloadStart, counterDigitPair);
|
||||||
// Split them into each array
|
// Split them into each array
|
||||||
for (int k = 0; k < 5; k++) {
|
for (int k = 0; k < 5; k++) {
|
||||||
int twoK = k << 1;
|
int twoK = 2 * k;
|
||||||
counterBlack[k] = counterDigitPair[twoK];
|
counterBlack[k] = counterDigitPair[twoK];
|
||||||
counterWhite[k] = counterDigitPair[twoK + 1];
|
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
|
// 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
|
// getting the width of the start pattern and dividing by 4 because its
|
||||||
// made up of 4 narrow lines.
|
// made up of 4 narrow lines.
|
||||||
this.narrowLineWidth = (startPattern[1] - startPattern[0]) >> 2;
|
this.narrowLineWidth = (startPattern[1] - startPattern[0]) / 4;
|
||||||
|
|
||||||
validateQuietZone(row, startPattern[0]);
|
validateQuietZone(row, startPattern[0]);
|
||||||
|
|
||||||
@ -336,13 +336,12 @@ public final class ITFReader extends OneDReader {
|
|||||||
* @throws NotFoundException if digit cannot be decoded
|
* @throws NotFoundException if digit cannot be decoded
|
||||||
*/
|
*/
|
||||||
private static int decodeDigit(int[] counters) throws NotFoundException {
|
private static int decodeDigit(int[] counters) throws NotFoundException {
|
||||||
|
float bestVariance = MAX_AVG_VARIANCE; // worst variance we'll accept
|
||||||
int bestVariance = MAX_AVG_VARIANCE; // worst variance we'll accept
|
|
||||||
int bestMatch = -1;
|
int bestMatch = -1;
|
||||||
int max = PATTERNS.length;
|
int max = PATTERNS.length;
|
||||||
for (int i = 0; i < max; i++) {
|
for (int i = 0; i < max; i++) {
|
||||||
int[] pattern = PATTERNS[i];
|
int[] pattern = PATTERNS[i];
|
||||||
int variance = patternMatchVariance(counters, pattern, MAX_INDIVIDUAL_VARIANCE);
|
float variance = patternMatchVariance(counters, pattern, MAX_INDIVIDUAL_VARIANCE);
|
||||||
if (variance < bestVariance) {
|
if (variance < bestVariance) {
|
||||||
bestVariance = variance;
|
bestVariance = variance;
|
||||||
bestMatch = i;
|
bestMatch = i;
|
||||||
|
@ -63,8 +63,8 @@ public final class ITFWriter extends OneDimensionalCodeWriter {
|
|||||||
int two = Character.digit(contents.charAt(i+1), 10);
|
int two = Character.digit(contents.charAt(i+1), 10);
|
||||||
int[] encoding = new int[18];
|
int[] encoding = new int[18];
|
||||||
for (int j = 0; j < 5; j++) {
|
for (int j = 0; j < 5; j++) {
|
||||||
encoding[j << 1] = ITFReader.PATTERNS[one][j];
|
encoding[2 * j] = ITFReader.PATTERNS[one][j];
|
||||||
encoding[(j << 1) + 1] = ITFReader.PATTERNS[two][j];
|
encoding[2 * j + 1] = ITFReader.PATTERNS[two][j];
|
||||||
}
|
}
|
||||||
pos += appendPattern(result, pos, encoding, true);
|
pos += appendPattern(result, pos, encoding, true);
|
||||||
}
|
}
|
||||||
|
@ -41,9 +41,6 @@ import java.util.Map;
|
|||||||
*/
|
*/
|
||||||
public abstract class OneDReader implements Reader {
|
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
|
@Override
|
||||||
public Result decode(BinaryBitmap image) throws NotFoundException, FormatException {
|
public Result decode(BinaryBitmap image) throws NotFoundException, FormatException {
|
||||||
return decode(image, null);
|
return decode(image, null);
|
||||||
@ -122,7 +119,7 @@ public abstract class OneDReader implements Reader {
|
|||||||
for (int x = 0; x < maxLines; x++) {
|
for (int x = 0; x < maxLines; x++) {
|
||||||
|
|
||||||
// Scanning from the middle out. Determine which row we're looking at next:
|
// 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?
|
boolean isAbove = (x & 0x01) == 0; // i.e. is x even?
|
||||||
int rowNumber = middle + rowStep * (isAbove ? rowStepsAboveOrBelow : -rowStepsAboveOrBelow);
|
int rowNumber = middle + rowStep * (isAbove ? rowStepsAboveOrBelow : -rowStepsAboveOrBelow);
|
||||||
if (rowNumber < 0 || rowNumber >= height) {
|
if (rowNumber < 0 || rowNumber >= height) {
|
||||||
@ -248,14 +245,11 @@ public abstract class OneDReader implements Reader {
|
|||||||
* @param counters observed counters
|
* @param counters observed counters
|
||||||
* @param pattern expected pattern
|
* @param pattern expected pattern
|
||||||
* @param maxIndividualVariance The most any counter can differ before we give up
|
* @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,
|
* @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
|
|
||||||
*/
|
*/
|
||||||
protected static int patternMatchVariance(int[] counters,
|
protected static float patternMatchVariance(int[] counters,
|
||||||
int[] pattern,
|
int[] pattern,
|
||||||
int maxIndividualVariance) {
|
float maxIndividualVariance) {
|
||||||
int numCounters = counters.length;
|
int numCounters = counters.length;
|
||||||
int total = 0;
|
int total = 0;
|
||||||
int patternLength = 0;
|
int patternLength = 0;
|
||||||
@ -266,21 +260,19 @@ public abstract class OneDReader implements Reader {
|
|||||||
if (total < patternLength) {
|
if (total < patternLength) {
|
||||||
// If we don't even have one pixel per unit of bar width, assume this is too small
|
// If we don't even have one pixel per unit of bar width, assume this is too small
|
||||||
// to reliably match, so fail:
|
// 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++) {
|
for (int x = 0; x < numCounters; x++) {
|
||||||
int counter = counters[x] << INTEGER_MATH_SHIFT;
|
int counter = counters[x];
|
||||||
int scaledPattern = pattern[x] * unitBarWidth;
|
float scaledPattern = pattern[x] * unitBarWidth;
|
||||||
int variance = counter > scaledPattern ? counter - scaledPattern : scaledPattern - counter;
|
float variance = counter > scaledPattern ? counter - scaledPattern : scaledPattern - counter;
|
||||||
if (variance > maxIndividualVariance) {
|
if (variance > maxIndividualVariance) {
|
||||||
return Integer.MAX_VALUE;
|
return Float.POSITIVE_INFINITY;
|
||||||
}
|
}
|
||||||
totalVariance += variance;
|
totalVariance += variance;
|
||||||
}
|
}
|
||||||
|
@ -44,8 +44,8 @@ public abstract class UPCEANReader extends OneDReader {
|
|||||||
// These two values are critical for determining how permissive the decoding will be.
|
// 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
|
// We've arrived at these values through a lot of trial and error. Setting them any higher
|
||||||
// lets false positives creep in quickly.
|
// lets false positives creep in quickly.
|
||||||
private static final int MAX_AVG_VARIANCE = (int) (PATTERN_MATCH_RESULT_SCALE_FACTOR * 0.48f);
|
private static final float MAX_AVG_VARIANCE = 0.48f;
|
||||||
private static final int MAX_INDIVIDUAL_VARIANCE = (int) (PATTERN_MATCH_RESULT_SCALE_FACTOR * 0.7f);
|
private static final float MAX_INDIVIDUAL_VARIANCE = 0.7f;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Start/end guard pattern.
|
* 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)
|
static int decodeDigit(BitArray row, int[] counters, int rowOffset, int[][] patterns)
|
||||||
throws NotFoundException {
|
throws NotFoundException {
|
||||||
recordPattern(row, rowOffset, counters);
|
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 bestMatch = -1;
|
||||||
int max = patterns.length;
|
int max = patterns.length;
|
||||||
for (int i = 0; i < max; i++) {
|
for (int i = 0; i < max; i++) {
|
||||||
int[] pattern = patterns[i];
|
int[] pattern = patterns[i];
|
||||||
int variance = patternMatchVariance(counters, pattern, MAX_INDIVIDUAL_VARIANCE);
|
float variance = patternMatchVariance(counters, pattern, MAX_INDIVIDUAL_VARIANCE);
|
||||||
if (variance < bestVariance) {
|
if (variance < bestVariance) {
|
||||||
bestVariance = variance;
|
bestVariance = variance;
|
||||||
bestMatch = i;
|
bestMatch = i;
|
||||||
|
@ -21,8 +21,8 @@ import com.google.zxing.oned.OneDReader;
|
|||||||
|
|
||||||
public abstract class AbstractRSSReader extends 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 float MAX_AVG_VARIANCE = 0.2f;
|
||||||
private static final int MAX_INDIVIDUAL_VARIANCE = (int) (PATTERN_MATCH_RESULT_SCALE_FACTOR * 0.45f);
|
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 MIN_FINDER_PATTERN_RATIO = 9.5f / 12.0f;
|
||||||
private static final float MAX_FINDER_PATTERN_RATIO = 12.5f / 14.0f;
|
private static final float MAX_FINDER_PATTERN_RATIO = 12.5f / 14.0f;
|
||||||
|
@ -228,7 +228,7 @@ public final class RSS14Reader extends AbstractRSSReader {
|
|||||||
} else if (count > 8) {
|
} else if (count > 8) {
|
||||||
count = 8;
|
count = 8;
|
||||||
}
|
}
|
||||||
int offset = i >> 1;
|
int offset = i / 2;
|
||||||
if ((i & 0x01) == 0) {
|
if ((i & 0x01) == 0) {
|
||||||
oddCounts[offset] = count;
|
oddCounts[offset] = count;
|
||||||
oddRoundingErrors[offset] = value - count;
|
oddRoundingErrors[offset] = value - count;
|
||||||
|
@ -129,7 +129,7 @@ public final class RSSUtils {
|
|||||||
/*
|
/*
|
||||||
static int[] elements(int[] eDist, int N, int K) {
|
static int[] elements(int[] eDist, int N, int K) {
|
||||||
int[] widths = new int[eDist.length + 2];
|
int[] widths = new int[eDist.length + 2];
|
||||||
int twoK = K << 1;
|
int twoK = 2 * K;
|
||||||
widths[0] = 1;
|
widths[0] = 1;
|
||||||
int i;
|
int i;
|
||||||
int minEven = 10;
|
int minEven = 10;
|
||||||
|
@ -40,7 +40,7 @@ final class BitArrayBuilder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static BitArray buildBitArray(List<ExpandedPair> pairs) {
|
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) {
|
if (pairs.get(pairs.size() - 1).getRightChar() == null) {
|
||||||
charNumber -= 1;
|
charNumber -= 1;
|
||||||
}
|
}
|
||||||
|
@ -639,7 +639,7 @@ public final class RSSExpandedReader extends AbstractRSSReader {
|
|||||||
}
|
}
|
||||||
count = 8;
|
count = 8;
|
||||||
}
|
}
|
||||||
int offset = i >> 1;
|
int offset = i / 2;
|
||||||
if ((i & 0x01) == 0) {
|
if ((i & 0x01) == 0) {
|
||||||
oddCounts[offset] = count;
|
oddCounts[offset] = count;
|
||||||
oddRoundingErrors[offset] = value - count;
|
oddRoundingErrors[offset] = value - count;
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
*/
|
*/
|
||||||
package com.google.zxing.pdf417;
|
package com.google.zxing.pdf417;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -63,38 +64,14 @@ public final class PDF417Common {
|
|||||||
* @param symbol encoded symbol to translate to a codeword
|
* @param symbol encoded symbol to translate to a codeword
|
||||||
* @return the codeword corresponding to the symbol.
|
* @return the codeword corresponding to the symbol.
|
||||||
*/
|
*/
|
||||||
public static int getCodeword(long symbol) {
|
public static int getCodeword(int symbol) {
|
||||||
long sym = symbol & 0x3FFFF;
|
int i = Arrays.binarySearch(SYMBOL_TABLE, symbol & 0x3FFFF);
|
||||||
int i = findCodewordIndex(sym);
|
if (i < 0) {
|
||||||
if (i == -1) {
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
return (CODEWORD_TABLE[i] - 1) % NUMBER_OF_CODEWORDS;
|
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
|
* The sorted table of all possible symbols. Extracted from the PDF417
|
||||||
* specification. The index of a symbol in this table corresponds to the
|
* specification. The index of a symbol in this table corresponds to the
|
||||||
|
@ -17,10 +17,13 @@
|
|||||||
package com.google.zxing.pdf417.decoder;
|
package com.google.zxing.pdf417.decoder;
|
||||||
|
|
||||||
import com.google.zxing.FormatException;
|
import com.google.zxing.FormatException;
|
||||||
|
import com.google.zxing.common.CharacterSetECI;
|
||||||
import com.google.zxing.common.DecoderResult;
|
import com.google.zxing.common.DecoderResult;
|
||||||
import com.google.zxing.pdf417.PDF417ResultMetadata;
|
import com.google.zxing.pdf417.PDF417ResultMetadata;
|
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.math.BigInteger;
|
import java.math.BigInteger;
|
||||||
|
import java.nio.charset.Charset;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -44,6 +47,9 @@ final class DecodedBitStreamParser {
|
|||||||
private static final int BYTE_COMPACTION_MODE_LATCH = 901;
|
private static final int BYTE_COMPACTION_MODE_LATCH = 901;
|
||||||
private static final int NUMERIC_COMPACTION_MODE_LATCH = 902;
|
private static final int NUMERIC_COMPACTION_MODE_LATCH = 902;
|
||||||
private static final int BYTE_COMPACTION_MODE_LATCH_6 = 924;
|
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_CONTROL_BLOCK = 928;
|
||||||
private static final int BEGIN_MACRO_PDF417_OPTIONAL_FIELD = 923;
|
private static final int BEGIN_MACRO_PDF417_OPTIONAL_FIELD = 923;
|
||||||
private static final int MACRO_PDF417_TERMINATOR = 922;
|
private static final int MACRO_PDF417_TERMINATOR = 922;
|
||||||
@ -59,7 +65,7 @@ final class DecodedBitStreamParser {
|
|||||||
private static final int PAL = 29;
|
private static final int PAL = 29;
|
||||||
|
|
||||||
private static final char[] PUNCT_CHARS = {
|
private static final char[] PUNCT_CHARS = {
|
||||||
';', '<', '>', '@', '[', '\\', '}', '_', '`', '~', '!',
|
';', '<', '>', '@', '[', '\\', ']', '_', '`', '~', '!',
|
||||||
'\r', '\t', ',', ':', '\n', '-', '.', '$', '/', '"', '|', '*',
|
'\r', '\t', ',', ':', '\n', '-', '.', '$', '/', '"', '|', '*',
|
||||||
'(', ')', '?', '{', '}', '\''};
|
'(', ')', '?', '{', '}', '\''};
|
||||||
|
|
||||||
@ -68,6 +74,8 @@ final class DecodedBitStreamParser {
|
|||||||
'\r', '\t', ',', ':', '#', '-', '.', '$', '/', '+', '%', '*',
|
'\r', '\t', ',', ':', '#', '-', '.', '$', '/', '+', '%', '*',
|
||||||
'=', '^'};
|
'=', '^'};
|
||||||
|
|
||||||
|
private static final Charset DEFAULT_ENCODING = Charset.forName("ISO-8859-1");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Table containing values for the exponent of 900.
|
* Table containing values for the exponent of 900.
|
||||||
* This is used in the numeric compaction decode algorithm.
|
* 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 {
|
static DecoderResult decode(int[] codewords, String ecLevel) throws FormatException {
|
||||||
StringBuilder result = new StringBuilder(codewords.length * 2);
|
StringBuilder result = new StringBuilder(codewords.length * 2);
|
||||||
|
Charset encoding = DEFAULT_ENCODING;
|
||||||
// Get compaction mode
|
// Get compaction mode
|
||||||
int codeIndex = 1;
|
int codeIndex = 1;
|
||||||
int code = codewords[codeIndex++];
|
int code = codewords[codeIndex++];
|
||||||
@ -101,12 +110,27 @@ final class DecodedBitStreamParser {
|
|||||||
break;
|
break;
|
||||||
case BYTE_COMPACTION_MODE_LATCH:
|
case BYTE_COMPACTION_MODE_LATCH:
|
||||||
case BYTE_COMPACTION_MODE_LATCH_6:
|
case BYTE_COMPACTION_MODE_LATCH_6:
|
||||||
|
codeIndex = byteCompaction(code, codewords, encoding, codeIndex, result);
|
||||||
|
break;
|
||||||
case MODE_SHIFT_TO_BYTE_COMPACTION_MODE:
|
case MODE_SHIFT_TO_BYTE_COMPACTION_MODE:
|
||||||
codeIndex = byteCompaction(code, codewords, codeIndex, result);
|
result.append((char) codewords[codeIndex++]);
|
||||||
break;
|
break;
|
||||||
case NUMERIC_COMPACTION_MODE_LATCH:
|
case NUMERIC_COMPACTION_MODE_LATCH:
|
||||||
codeIndex = numericCompaction(codewords, codeIndex, result);
|
codeIndex = numericCompaction(codewords, codeIndex, result);
|
||||||
break;
|
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:
|
case BEGIN_MACRO_PDF417_CONTROL_BLOCK:
|
||||||
codeIndex = decodeMacroBlock(codewords, codeIndex, resultMetadata);
|
codeIndex = decodeMacroBlock(codewords, codeIndex, resultMetadata);
|
||||||
break;
|
break;
|
||||||
@ -197,9 +221,9 @@ final class DecodedBitStreamParser {
|
|||||||
*/
|
*/
|
||||||
private static int textCompaction(int[] codewords, int codeIndex, StringBuilder result) {
|
private static int textCompaction(int[] codewords, int codeIndex, StringBuilder result) {
|
||||||
// 2 character per codeword
|
// 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
|
// 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;
|
int index = 0;
|
||||||
boolean end = false;
|
boolean end = false;
|
||||||
@ -316,6 +340,7 @@ final class DecodedBitStreamParser {
|
|||||||
priorToShiftMode = subMode;
|
priorToShiftMode = subMode;
|
||||||
subMode = Mode.PUNCT_SHIFT;
|
subMode = Mode.PUNCT_SHIFT;
|
||||||
} else if (subModeCh == MODE_SHIFT_TO_BYTE_COMPACTION_MODE) {
|
} 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]);
|
result.append((char) byteCompactionData[i]);
|
||||||
} else if (subModeCh == TEXT_COMPACTION_MODE_LATCH) {
|
} else if (subModeCh == TEXT_COMPACTION_MODE_LATCH) {
|
||||||
subMode = Mode.ALPHA;
|
subMode = Mode.ALPHA;
|
||||||
@ -410,17 +435,22 @@ final class DecodedBitStreamParser {
|
|||||||
*
|
*
|
||||||
* @param mode The byte compaction mode i.e. 901 or 924
|
* @param mode The byte compaction mode i.e. 901 or 924
|
||||||
* @param codewords The array of codewords (data + error)
|
* @param codewords The array of codewords (data + error)
|
||||||
|
* @param encoding Currently active character encoding
|
||||||
* @param codeIndex The current index into the codeword array.
|
* @param codeIndex The current index into the codeword array.
|
||||||
* @param result The decoded data is appended to the result.
|
* @param result The decoded data is appended to the result.
|
||||||
* @return The next index into the codeword array.
|
* @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) {
|
if (mode == BYTE_COMPACTION_MODE_LATCH) {
|
||||||
// Total number of Byte Compaction characters to be encoded
|
// Total number of Byte Compaction characters to be encoded
|
||||||
// is not a multiple of 6
|
// is not a multiple of 6
|
||||||
int count = 0;
|
int count = 0;
|
||||||
long value = 0;
|
long value = 0;
|
||||||
char[] decodedData = new char[6];
|
|
||||||
int[] byteCompactedCodewords = new int[6];
|
int[] byteCompactedCodewords = new int[6];
|
||||||
boolean end = false;
|
boolean end = false;
|
||||||
int nextCode = codewords[codeIndex++];
|
int nextCode = codewords[codeIndex++];
|
||||||
@ -444,10 +474,9 @@ final class DecodedBitStreamParser {
|
|||||||
// Decode every 5 codewords
|
// Decode every 5 codewords
|
||||||
// Convert to Base 256
|
// Convert to Base 256
|
||||||
for (int j = 0; j < 6; ++j) {
|
for (int j = 0; j < 6; ++j) {
|
||||||
decodedData[5 - j] = (char) (value % 256);
|
decodedBytes.write((byte) (value >> (8 * (5 - j))));
|
||||||
value >>= 8;
|
|
||||||
}
|
}
|
||||||
result.append(decodedData);
|
value = 0;
|
||||||
count = 0;
|
count = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -462,7 +491,7 @@ final class DecodedBitStreamParser {
|
|||||||
// the last group of codewords is interpreted directly
|
// the last group of codewords is interpreted directly
|
||||||
// as one byte per codeword, without compaction.
|
// as one byte per codeword, without compaction.
|
||||||
for (int i = 0; i < count; i++) {
|
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) {
|
} else if (mode == BYTE_COMPACTION_MODE_LATCH_6) {
|
||||||
@ -492,16 +521,15 @@ final class DecodedBitStreamParser {
|
|||||||
if ((count % 5 == 0) && (count > 0)) {
|
if ((count % 5 == 0) && (count > 0)) {
|
||||||
// Decode every 5 codewords
|
// Decode every 5 codewords
|
||||||
// Convert to Base 256
|
// Convert to Base 256
|
||||||
char[] decodedData = new char[6];
|
|
||||||
for (int j = 0; j < 6; ++j) {
|
for (int j = 0; j < 6; ++j) {
|
||||||
decodedData[5 - j] = (char) (value & 0xFF);
|
decodedBytes.write((byte) (value >> (8 * (5 - j))));
|
||||||
value >>= 8;
|
|
||||||
}
|
}
|
||||||
result.append(decodedData);
|
value = 0;
|
||||||
count = 0;
|
count = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
result.append(new String(decodedBytes.toByteArray(), encoding));
|
||||||
return codeIndex;
|
return codeIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -545,9 +573,11 @@ final class DecodedBitStreamParser {
|
|||||||
// while in Numeric Compaction mode) serves to terminate the
|
// while in Numeric Compaction mode) serves to terminate the
|
||||||
// current Numeric Compaction mode grouping as described in 5.4.4.2,
|
// current Numeric Compaction mode grouping as described in 5.4.4.2,
|
||||||
// and then to start a new one grouping.
|
// and then to start a new one grouping.
|
||||||
String s = decodeBase900toBase10(numericCodewords, count);
|
if (count > 0) {
|
||||||
result.append(s);
|
String s = decodeBase900toBase10(numericCodewords, count);
|
||||||
count = 0;
|
result.append(s);
|
||||||
|
count = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return codeIndex;
|
return codeIndex;
|
||||||
|
@ -326,27 +326,31 @@ public final class PDF417ScanningDecoder {
|
|||||||
throw ChecksumException.getChecksumInstance();
|
throw ChecksumException.getChecksumInstance();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static BarcodeValue[][] createBarcodeMatrix(DetectionResult detectionResult) {
|
private static BarcodeValue[][] createBarcodeMatrix(DetectionResult detectionResult) throws FormatException {
|
||||||
BarcodeValue[][] barcodeMatrix = new BarcodeValue[detectionResult.getBarcodeRowCount()][detectionResult
|
BarcodeValue[][] barcodeMatrix =
|
||||||
.getBarcodeColumnCount() + 2];
|
new BarcodeValue[detectionResult.getBarcodeRowCount()][detectionResult.getBarcodeColumnCount() + 2];
|
||||||
for (int row = 0; row < barcodeMatrix.length; row++) {
|
for (int row = 0; row < barcodeMatrix.length; row++) {
|
||||||
for (int column = 0; column < barcodeMatrix[row].length; column++) {
|
for (int column = 0; column < barcodeMatrix[row].length; column++) {
|
||||||
barcodeMatrix[row][column] = new BarcodeValue();
|
barcodeMatrix[row][column] = new BarcodeValue();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int column = -1;
|
int column = 0;
|
||||||
for (DetectionResultColumn detectionResultColumn : detectionResult.getDetectionResultColumns()) {
|
for (DetectionResultColumn detectionResultColumn : detectionResult.getDetectionResultColumns()) {
|
||||||
column++;
|
if (detectionResultColumn != null) {
|
||||||
if (detectionResultColumn == null) {
|
for (Codeword codeword : detectionResultColumn.getCodewords()) {
|
||||||
continue;
|
if (codeword != null) {
|
||||||
}
|
int rowNumber = codeword.getRowNumber();
|
||||||
for (Codeword codeword : detectionResultColumn.getCodewords()) {
|
if (rowNumber >= 0) {
|
||||||
if (codeword == null || codeword.getRowNumber() == -1) {
|
if (rowNumber >= barcodeMatrix.length) {
|
||||||
continue;
|
throw FormatException.getFormatInstance();
|
||||||
|
}
|
||||||
|
barcodeMatrix[rowNumber][column].setValue(codeword.getValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
barcodeMatrix[codeword.getRowNumber()][column].setValue(codeword.getValue());
|
|
||||||
}
|
}
|
||||||
|
column++;
|
||||||
}
|
}
|
||||||
return barcodeMatrix;
|
return barcodeMatrix;
|
||||||
}
|
}
|
||||||
@ -416,7 +420,7 @@ public final class PDF417ScanningDecoder {
|
|||||||
if (leftToRight) {
|
if (leftToRight) {
|
||||||
endColumn = startColumn + codewordBitCount;
|
endColumn = startColumn + codewordBitCount;
|
||||||
} else {
|
} else {
|
||||||
for (int i = 0; i < moduleBitCount.length >> 1; i++) {
|
for (int i = 0; i < moduleBitCount.length / 2; i++) {
|
||||||
int tmpCount = moduleBitCount[i];
|
int tmpCount = moduleBitCount[i];
|
||||||
moduleBitCount[i] = moduleBitCount[moduleBitCount.length - 1 - i];
|
moduleBitCount[i] = moduleBitCount[moduleBitCount.length - 1 - i];
|
||||||
moduleBitCount[moduleBitCount.length - 1 - i] = tmpCount;
|
moduleBitCount[moduleBitCount.length - 1 - i] = tmpCount;
|
||||||
|
@ -62,11 +62,13 @@ public final class ErrorCorrection {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ModulusPoly knownErrors = field.getOne();
|
ModulusPoly knownErrors = field.getOne();
|
||||||
for (int erasure : erasures) {
|
if (erasures != null) {
|
||||||
int b = field.exp(received.length - 1 - erasure);
|
for (int erasure : erasures) {
|
||||||
// Add (1 - bx) term:
|
int b = field.exp(received.length - 1 - erasure);
|
||||||
ModulusPoly term = new ModulusPoly(field, new int[] { field.subtract(0, b), 1 });
|
// Add (1 - bx) term:
|
||||||
knownErrors = knownErrors.multiply(term);
|
ModulusPoly term = new ModulusPoly(field, new int[]{field.subtract(0, b), 1});
|
||||||
|
knownErrors = knownErrors.multiply(term);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ModulusPoly syndrome = new ModulusPoly(field, S);
|
ModulusPoly syndrome = new ModulusPoly(field, S);
|
||||||
|
@ -38,7 +38,7 @@ final class ModulusPoly {
|
|||||||
firstNonZero++;
|
firstNonZero++;
|
||||||
}
|
}
|
||||||
if (firstNonZero == coefficientsLength) {
|
if (firstNonZero == coefficientsLength) {
|
||||||
this.coefficients = field.getZero().coefficients;
|
this.coefficients = new int[]{0};
|
||||||
} else {
|
} else {
|
||||||
this.coefficients = new int[coefficientsLength - firstNonZero];
|
this.coefficients = new int[coefficientsLength - firstNonZero];
|
||||||
System.arraycopy(coefficients,
|
System.arraycopy(coefficients,
|
||||||
|
@ -39,10 +39,8 @@ public final class Detector {
|
|||||||
|
|
||||||
private static final int[] INDEXES_START_PATTERN = {0, 4, 1, 5};
|
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[] INDEXES_STOP_PATTERN = {6, 2, 7, 3};
|
||||||
private static final int INTEGER_MATH_SHIFT = 8;
|
private static final float MAX_AVG_VARIANCE = 0.42f;
|
||||||
private static final int PATTERN_MATCH_RESULT_SCALE_FACTOR = 1 << INTEGER_MATH_SHIFT;
|
private static final float MAX_INDIVIDUAL_VARIANCE = 0.8f;
|
||||||
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);
|
|
||||||
|
|
||||||
// B S B S B S B S Bar/Space pattern
|
// B S B S B S B S Bar/Space pattern
|
||||||
// 11111111 0 1 0 1 0 1 000
|
// 11111111 0 1 0 1 0 1 000
|
||||||
@ -310,13 +308,9 @@ public final class Detector {
|
|||||||
* @param counters observed counters
|
* @param counters observed counters
|
||||||
* @param pattern expected pattern
|
* @param pattern expected pattern
|
||||||
* @param maxIndividualVariance The most any counter can differ before we give up
|
* @param maxIndividualVariance The most any counter can differ before we give up
|
||||||
* @return ratio of total variance between counters and pattern compared to
|
* @return ratio of total variance between counters and pattern compared to total pattern size
|
||||||
* 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
|
|
||||||
*/
|
*/
|
||||||
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 numCounters = counters.length;
|
||||||
int total = 0;
|
int total = 0;
|
||||||
int patternLength = 0;
|
int patternLength = 0;
|
||||||
@ -327,21 +321,21 @@ public final class Detector {
|
|||||||
if (total < patternLength) {
|
if (total < patternLength) {
|
||||||
// If we don't even have one pixel per unit of bar width, assume this
|
// If we don't even have one pixel per unit of bar width, assume this
|
||||||
// is too small to reliably match, so fail:
|
// 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.
|
// 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
|
// Scale up patternLength so that intermediate values below like scaledCounter will have
|
||||||
// more "significant digits".
|
// more "significant digits".
|
||||||
int unitBarWidth = (total << INTEGER_MATH_SHIFT) / patternLength;
|
float unitBarWidth = (float) total / patternLength;
|
||||||
maxIndividualVariance = (maxIndividualVariance * unitBarWidth) >> INTEGER_MATH_SHIFT;
|
maxIndividualVariance *= unitBarWidth;
|
||||||
|
|
||||||
int totalVariance = 0;
|
float totalVariance = 0.0f;
|
||||||
for (int x = 0; x < numCounters; x++) {
|
for (int x = 0; x < numCounters; x++) {
|
||||||
int counter = counters[x] << INTEGER_MATH_SHIFT;
|
int counter = counters[x];
|
||||||
int scaledPattern = pattern[x] * unitBarWidth;
|
float scaledPattern = pattern[x] * unitBarWidth;
|
||||||
int variance = counter > scaledPattern ? counter - scaledPattern : scaledPattern - counter;
|
float variance = counter > scaledPattern ? counter - scaledPattern : scaledPattern - counter;
|
||||||
if (variance > maxIndividualVariance) {
|
if (variance > maxIndividualVariance) {
|
||||||
return Integer.MAX_VALUE;
|
return Float.POSITIVE_INFINITY;
|
||||||
}
|
}
|
||||||
totalVariance += variance;
|
totalVariance += variance;
|
||||||
}
|
}
|
||||||
|
@ -25,9 +25,7 @@ import com.google.zxing.common.CharacterSetECI;
|
|||||||
|
|
||||||
import java.math.BigInteger;
|
import java.math.BigInteger;
|
||||||
import java.nio.charset.Charset;
|
import java.nio.charset.Charset;
|
||||||
import java.nio.charset.UnsupportedCharsetException;
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* PDF417 high-level encoder following the algorithm described in ISO/IEC 15438:2001(E) in
|
* 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[] MIXED = new byte[128];
|
||||||
private static final byte[] PUNCTUATION = 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() {
|
private PDF417HighLevelEncoder() {
|
||||||
}
|
}
|
||||||
@ -166,7 +164,9 @@ final class PDF417HighLevelEncoder {
|
|||||||
//the codewords 0..928 are encoded as Unicode characters
|
//the codewords 0..928 are encoded as Unicode characters
|
||||||
StringBuilder sb = new StringBuilder(msg.length());
|
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());
|
CharacterSetECI eci = CharacterSetECI.getCharacterSetECIByName(encoding.name());
|
||||||
if (eci != null) {
|
if (eci != null) {
|
||||||
encodingECI(eci.getValue(), sb);
|
encodingECI(eci.getValue(), sb);
|
||||||
@ -183,7 +183,7 @@ final class PDF417HighLevelEncoder {
|
|||||||
encodeText(msg, p, len, sb, textSubMode);
|
encodeText(msg, p, len, sb, textSubMode);
|
||||||
|
|
||||||
} else if (compaction == Compaction.BYTE) {
|
} else if (compaction == Compaction.BYTE) {
|
||||||
bytes = toBytes(msg, encoding);
|
bytes = msg.getBytes(encoding);
|
||||||
encodeBinary(bytes, p, bytes.length, BYTE_COMPACTION, sb);
|
encodeBinary(bytes, p, bytes.length, BYTE_COMPACTION, sb);
|
||||||
|
|
||||||
} else if (compaction == Compaction.NUMERIC) {
|
} else if (compaction == Compaction.NUMERIC) {
|
||||||
@ -212,7 +212,7 @@ final class PDF417HighLevelEncoder {
|
|||||||
p += t;
|
p += t;
|
||||||
} else {
|
} else {
|
||||||
if (bytes == null) {
|
if (bytes == null) {
|
||||||
bytes = toBytes(msg, encoding);
|
bytes = msg.getBytes(encoding);
|
||||||
}
|
}
|
||||||
int b = determineConsecutiveBinaryCount(msg, bytes, p);
|
int b = determineConsecutiveBinaryCount(msg, bytes, p);
|
||||||
if (b == 0) {
|
if (b == 0) {
|
||||||
@ -236,24 +236,6 @@ final class PDF417HighLevelEncoder {
|
|||||||
return sb.toString();
|
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),
|
* Encode parts of the message using Text Compaction as described in ISO/IEC 15438:2001(E),
|
||||||
* chapter 4.4.2.
|
* chapter 4.4.2.
|
||||||
@ -439,7 +421,7 @@ final class PDF417HighLevelEncoder {
|
|||||||
StringBuilder tmp = new StringBuilder(count / 3 + 1);
|
StringBuilder tmp = new StringBuilder(count / 3 + 1);
|
||||||
BigInteger num900 = BigInteger.valueOf(900);
|
BigInteger num900 = BigInteger.valueOf(900);
|
||||||
BigInteger num0 = BigInteger.valueOf(0);
|
BigInteger num0 = BigInteger.valueOf(0);
|
||||||
while (idx < count - 1) {
|
while (idx < count) {
|
||||||
tmp.setLength(0);
|
tmp.setLength(0);
|
||||||
int len = Math.min(44, count - idx);
|
int len = Math.min(44, count - idx);
|
||||||
String part = '1' + msg.substring(startpos + idx, startpos + idx + len);
|
String part = '1' + msg.substring(startpos + idx, startpos + idx + len);
|
||||||
@ -572,18 +554,6 @@ final class PDF417HighLevelEncoder {
|
|||||||
if (numericCount >= 13) {
|
if (numericCount >= 13) {
|
||||||
return idx - startpos;
|
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);
|
ch = msg.charAt(idx);
|
||||||
|
|
||||||
//Check if character is encodable
|
//Check if character is encodable
|
||||||
|
@ -159,7 +159,9 @@ public class QRCodeReader implements Reader {
|
|||||||
left += nudge;
|
left += nudge;
|
||||||
|
|
||||||
// But careful that this does not sample off the edge
|
// 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 > 0) {
|
||||||
if (nudgedTooFarRight > nudge) {
|
if (nudgedTooFarRight > nudge) {
|
||||||
// Neither way fits; abort
|
// Neither way fits; abort
|
||||||
@ -167,7 +169,8 @@ public class QRCodeReader implements Reader {
|
|||||||
}
|
}
|
||||||
left -= nudgedTooFarRight;
|
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 > 0) {
|
||||||
if (nudgedTooFarDown > nudge) {
|
if (nudgedTooFarDown > nudge) {
|
||||||
// Neither way fits; abort
|
// Neither way fits; abort
|
||||||
|
@ -90,8 +90,8 @@ public final class QRCodeWriter implements Writer {
|
|||||||
}
|
}
|
||||||
int inputWidth = input.getWidth();
|
int inputWidth = input.getWidth();
|
||||||
int inputHeight = input.getHeight();
|
int inputHeight = input.getHeight();
|
||||||
int qrWidth = inputWidth + (quietZone << 1);
|
int qrWidth = inputWidth + (quietZone * 2);
|
||||||
int qrHeight = inputHeight + (quietZone << 1);
|
int qrHeight = inputHeight + (quietZone * 2);
|
||||||
int outputWidth = Math.max(width, qrWidth);
|
int outputWidth = Math.max(width, qrWidth);
|
||||||
int outputHeight = Math.max(height, qrHeight);
|
int outputHeight = Math.max(height, qrHeight);
|
||||||
|
|
||||||
|
@ -101,7 +101,7 @@ final class BitMatrixParser {
|
|||||||
|
|
||||||
int dimension = bitMatrix.getHeight();
|
int dimension = bitMatrix.getHeight();
|
||||||
|
|
||||||
int provisionalVersion = (dimension - 17) >> 2;
|
int provisionalVersion = (dimension - 17) / 4;
|
||||||
if (provisionalVersion <= 6) {
|
if (provisionalVersion <= 6) {
|
||||||
return Version.getVersionForNumber(provisionalVersion);
|
return Version.getVersionForNumber(provisionalVersion);
|
||||||
}
|
}
|
||||||
|
@ -125,7 +125,7 @@ abstract class DataMask {
|
|||||||
private static final class DataMask100 extends DataMask {
|
private static final class DataMask100 extends DataMask {
|
||||||
@Override
|
@Override
|
||||||
boolean isMasked(int i, int j) {
|
boolean isMasked(int i, int j) {
|
||||||
return (((i >>> 1) + (j /3)) & 0x01) == 0;
|
return (((i / 2) + (j /3)) & 0x01) == 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -217,7 +217,7 @@ final class DecodedBitStreamParser {
|
|||||||
Collection<byte[]> byteSegments,
|
Collection<byte[]> byteSegments,
|
||||||
Map<DecodeHintType,?> hints) throws FormatException {
|
Map<DecodeHintType,?> hints) throws FormatException {
|
||||||
// Don't crash trying to read more bits than we have available.
|
// 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();
|
throw FormatException.getFormatInstance();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -94,7 +94,7 @@ public final class Version {
|
|||||||
throw FormatException.getFormatInstance();
|
throw FormatException.getFormatInstance();
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
return getVersionForNumber((dimension - 17) >> 2);
|
return getVersionForNumber((dimension - 17) / 4);
|
||||||
} catch (IllegalArgumentException ignored) {
|
} catch (IllegalArgumentException ignored) {
|
||||||
throw FormatException.getFormatInstance();
|
throw FormatException.getFormatInstance();
|
||||||
}
|
}
|
||||||
|
@ -88,13 +88,13 @@ final class AlignmentPatternFinder {
|
|||||||
int startX = this.startX;
|
int startX = this.startX;
|
||||||
int height = this.height;
|
int height = this.height;
|
||||||
int maxJ = startX + width;
|
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;
|
// 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
|
// this tracks the number of black/white/black modules seen so far
|
||||||
int[] stateCount = new int[3];
|
int[] stateCount = new int[3];
|
||||||
for (int iGen = 0; iGen < height; iGen++) {
|
for (int iGen = 0; iGen < height; iGen++) {
|
||||||
// Search from middle outwards
|
// 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[0] = 0;
|
||||||
stateCount[1] = 0;
|
stateCount[1] = 0;
|
||||||
stateCount[2] = 0;
|
stateCount[2] = 0;
|
||||||
|
@ -201,7 +201,7 @@ public class Detector {
|
|||||||
float moduleSize) throws NotFoundException {
|
float moduleSize) throws NotFoundException {
|
||||||
int tltrCentersDimension = MathUtils.round(ResultPoint.distance(topLeft, topRight) / moduleSize);
|
int tltrCentersDimension = MathUtils.round(ResultPoint.distance(topLeft, topRight) / moduleSize);
|
||||||
int tlblCentersDimension = MathUtils.round(ResultPoint.distance(topLeft, bottomLeft) / 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
|
switch (dimension & 0x03) { // mod 4
|
||||||
case 0:
|
case 0:
|
||||||
dimension++;
|
dimension++;
|
||||||
@ -318,7 +318,7 @@ public class Detector {
|
|||||||
|
|
||||||
int dx = Math.abs(toX - fromX);
|
int dx = Math.abs(toX - fromX);
|
||||||
int dy = Math.abs(toY - fromY);
|
int dy = Math.abs(toY - fromY);
|
||||||
int error = -dx >> 1;
|
int error = -dx / 2;
|
||||||
int xstep = fromX < toX ? 1 : -1;
|
int xstep = fromX < toX ? 1 : -1;
|
||||||
int ystep = fromY < toY ? 1 : -1;
|
int ystep = fromY < toY ? 1 : -1;
|
||||||
|
|
||||||
|
@ -42,7 +42,6 @@ public class FinderPatternFinder {
|
|||||||
private static final int CENTER_QUORUM = 2;
|
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 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
|
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 BitMatrix image;
|
||||||
private final List<FinderPattern> possibleCenters;
|
private final List<FinderPattern> possibleCenters;
|
||||||
@ -209,14 +208,15 @@ public class FinderPatternFinder {
|
|||||||
if (totalModuleSize < 7) {
|
if (totalModuleSize < 7) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
int moduleSize = (totalModuleSize << INTEGER_MATH_SHIFT) / 7;
|
float moduleSize = totalModuleSize / 7.0f;
|
||||||
int maxVariance = moduleSize / 2;
|
float maxVariance = moduleSize / 2.0f;
|
||||||
// Allow less than 50% variance from 1-1-3-1-1 proportions
|
// Allow less than 50% variance from 1-1-3-1-1 proportions
|
||||||
return Math.abs(moduleSize - (stateCount[0] << INTEGER_MATH_SHIFT)) < maxVariance &&
|
return
|
||||||
Math.abs(moduleSize - (stateCount[1] << INTEGER_MATH_SHIFT)) < maxVariance &&
|
Math.abs(moduleSize - stateCount[0]) < maxVariance &&
|
||||||
Math.abs(3 * moduleSize - (stateCount[2] << INTEGER_MATH_SHIFT)) < 3 * maxVariance &&
|
Math.abs(moduleSize - stateCount[1]) < maxVariance &&
|
||||||
Math.abs(moduleSize - (stateCount[3] << INTEGER_MATH_SHIFT)) < maxVariance &&
|
Math.abs(3.0f * moduleSize - stateCount[2]) < 3 * maxVariance &&
|
||||||
Math.abs(moduleSize - (stateCount[4] << INTEGER_MATH_SHIFT)) < maxVariance;
|
Math.abs(moduleSize - stateCount[3]) < maxVariance &&
|
||||||
|
Math.abs(moduleSize - stateCount[4]) < maxVariance;
|
||||||
}
|
}
|
||||||
|
|
||||||
private int[] getCrossCheckStateCount() {
|
private int[] getCrossCheckStateCount() {
|
||||||
|
@ -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).
|
* 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 {
|
static void terminateBits(int numDataBytes, BitArray bits) throws WriterException {
|
||||||
int capacity = numDataBytes << 3;
|
int capacity = numDataBytes * 8;
|
||||||
if (bits.getSize() > capacity) {
|
if (bits.getSize() > capacity) {
|
||||||
throw new WriterException("data bits cannot fit in the QR Code" + bits.getSize() + " > " +
|
throw new WriterException("data bits cannot fit in the QR Code" + bits.getSize() + " > " +
|
||||||
capacity);
|
capacity);
|
||||||
|
@ -163,7 +163,7 @@ final class MaskUtil {
|
|||||||
intermediate = (y + x) % 3;
|
intermediate = (y + x) % 3;
|
||||||
break;
|
break;
|
||||||
case 4:
|
case 4:
|
||||||
intermediate = ((y >>> 1) + (x / 3)) & 0x1;
|
intermediate = ((y / 2) + (x / 3)) & 0x1;
|
||||||
break;
|
break;
|
||||||
case 5:
|
case 5:
|
||||||
temp = y * x;
|
temp = y * x;
|
||||||
|
@ -305,6 +305,9 @@ final class MatrixUtil {
|
|||||||
// Since all coefficients in the polynomials are 1 or 0, we can do the calculation by bit
|
// 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.
|
// operations. We don't care if cofficients are positive or negative.
|
||||||
static int calculateBCHCode(int value, int poly) {
|
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
|
// If poly is "1 1111 0010 0101" (version info poly), msbSetInPoly is 13. We'll subtract 1
|
||||||
// from 13 to make it 12.
|
// from 13 to make it 12.
|
||||||
int msbSetInPoly = findMSBSet(poly);
|
int msbSetInPoly = findMSBSet(poly);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user