* of one-dimensional barcodes.</p>
*
* @author dswitkin@google.com (Daniel Switkin)
- * @author srowen@google.com (Sean Owen)
+ * @author Sean Owen
* @author alasdair@google.com (Alasdair Mackintosh)
*/
public abstract class AbstractUPCEANReader extends AbstractOneDReader implements UPCEANReader {
- private static final int MAX_AVG_VARIANCE = (int) (PATTERN_MATCH_RESULT_SCALE_FACTOR * 0.40625f);
+ 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.7f);
/**
}
}
+ private final StringBuffer decodeRowStringBuffer;
+
+ protected AbstractUPCEANReader() {
+ decodeRowStringBuffer = new StringBuffer(20);
+ }
+
static int[] findStartGuardPattern(BitArray row) throws ReaderException {
boolean foundStart = false;
int[] startRange = null;
startRange = findGuardPattern(row, nextStart, false, START_END_PATTERN);
int start = startRange[0];
nextStart = startRange[1];
- // As a check, we want to see some white in front of this "start pattern",
- // maybe as wide as the 150% of the start pattern itself?
- foundStart = row.isRange(Math.max(0, start - (3 * (nextStart - start)) / 2), start, false);
+ // Make sure there is a quiet zone at least as big as the start pattern before the barcode. If
+ // this check would run off the left edge of the image, do not accept this barcode, as it is
+ // very likely to be a false positive.
+ int quietStart = start - (nextStart - start);
+ if (quietStart >= 0) {
+ foundStart = row.isRange(quietStart, start, false);
+ }
}
return startRange;
}
}
public final Result decodeRow(int rowNumber, BitArray row, int[] startGuardRange) throws ReaderException {
- StringBuffer result = new StringBuffer(20);
+ StringBuffer result = decodeRowStringBuffer;
+ result.setLength(0);
int endStart = decodeMiddle(row, startGuardRange, result);
int[] endRange = decodeEnd(row, endStart);
- // Check for whitespace after the pattern -- 150% of size of end pattern
+ // Make sure there is a quiet zone at least as big as the end pattern after the barcode. The
+ // spec might want more whitespace, but in practice this is the maximum we can count on.
int end = endRange[1];
- if (!row.isRange(end, Math.min(row.getSize(), end + (3 * (end - endRange[0])) / 2), false)) {
- throw new ReaderException("Pattern not followed by whitespace");
+ int quietEnd = end + (end - endRange[0]);
+ if (quietEnd >= row.getSize() || !row.isRange(end, quietEnd, false)) {
+ throw ReaderException.getInstance();
}
String resultString = result.toString();
if (!checkChecksum(resultString)) {
- throw new ReaderException("Checksum failed");
+ throw ReaderException.getInstance();
}
float left = (float) (startGuardRange[1] + startGuardRange[0]) / 2.0f;
abstract BarcodeFormat getBarcodeFormat();
+ /**
+ * @return {@link #checkStandardUPCEANChecksum(String)}
+ */
+ boolean checkChecksum(String s) throws ReaderException {
+ return checkStandardUPCEANChecksum(s);
+ }
+
/**
* Computes the UPC/EAN checksum on a string of digits, and reports
* whether the checksum is correct or not.
* @return true iff string of digits passes the UPC/EAN checksum algorithm
* @throws ReaderException if the string does not contain only digits
*/
- boolean checkChecksum(String s) throws ReaderException {
+ public static boolean checkStandardUPCEANChecksum(String s) throws ReaderException {
int length = s.length();
if (length == 0) {
return false;
for (int i = length - 2; i >= 0; i -= 2) {
int digit = (int) s.charAt(i) - (int) '0';
if (digit < 0 || digit > 9) {
- throw new ReaderException("Illegal character during checksum");
+ throw ReaderException.getInstance();
}
sum += digit;
}
for (int i = length - 1; i >= 0; i -= 2) {
int digit = (int) s.charAt(i) - (int) '0';
if (digit < 0 || digit > 9) {
- throw new ReaderException("Illegal character during checksum");
+ throw ReaderException.getInstance();
}
sum += digit;
}
isWhite = !isWhite;
}
}
- throw new ReaderException("Can't find pattern");
+ throw ReaderException.getInstance();
}
/**
if (bestMatch >= 0) {
return bestMatch;
} else {
- throw new ReaderException("Could not match any digit in pattern");
+ throw ReaderException.getInstance();
}
}