From 1f442884aa1454bf8f5d18c9429d6a3ae20ae349 Mon Sep 17 00:00:00 2001 From: srowen Date: Mon, 25 Feb 2008 23:02:50 +0000 Subject: [PATCH] Added BarcodeFormat to Result, indicating what type of barcode was detected. Added TRY_HARDER hint. Improved logicalness of results when reading UPC-A code / EAN-13 code starting with 0. git-svn-id: https://zxing.googlecode.com/svn/trunk@230 59b500cc-1b3d-0410-9834-0bbf25fbcc57 --- core/src/com/google/zxing/BarcodeFormat.java | 44 ++++++++--- core/src/com/google/zxing/DecodeHintType.java | 15 ++-- .../com/google/zxing/MultiFormatReader.java | 47 ++++++----- core/src/com/google/zxing/Result.java | 11 ++- .../google/zxing/oned/AbstractOneDReader.java | 25 +++--- .../zxing/oned/AbstractUPCEANReader.java | 16 +++- .../com/google/zxing/oned/Code128Reader.java | 16 ++-- .../com/google/zxing/oned/Code39Reader.java | 14 +++- .../com/google/zxing/oned/EAN13Reader.java | 12 +-- .../src/com/google/zxing/oned/EAN8Reader.java | 5 ++ .../zxing/oned/MultiFormatOneDReader.java | 47 ++++++++--- .../zxing/oned/MultiFormatUPCEANReader.java | 74 +++++++++++++----- .../src/com/google/zxing/oned/OneDReader.java | 5 +- .../src/com/google/zxing/oned/UPCAReader.java | 5 ++ .../src/com/google/zxing/oned/UPCEReader.java | 5 ++ .../com/google/zxing/qrcode/QRCodeReader.java | 3 +- .../{upca-1/14.jpg => ean13-1/33.jpg} | Bin .../{upca-1/14.txt => ean13-1/33.txt} | 0 .../{upca-1/15.jpg => ean13-1/34.jpg} | Bin .../{upca-1/15.txt => ean13-1/34.txt} | 0 .../{ean13-1/16.JPG => upca-1/35.jpg} | Bin .../{ean13-1/16.txt => upca-1/35.txt} | 0 .../common/AbstractBlackBoxTestCase.java | 10 ++- .../zxing/oned/Code128BlackBox1TestCase.java | 3 +- .../zxing/oned/Code39BlackBox1TestCase.java | 3 +- .../oned/Code39ExtendedBlackBox2TestCase.java | 3 +- .../zxing/oned/EAN13BlackBox1TestCase.java | 3 +- .../zxing/oned/UPCABlackBox1TestCase.java | 3 +- .../zxing/qrcode/QRCodeBlackBox1TestCase.java | 3 +- .../zxing/qrcode/QRCodeBlackBox2TestCase.java | 3 +- 30 files changed, 260 insertions(+), 115 deletions(-) rename core/test/data/blackbox/{upca-1/14.jpg => ean13-1/33.jpg} (100%) rename core/test/data/blackbox/{upca-1/14.txt => ean13-1/33.txt} (100%) rename core/test/data/blackbox/{upca-1/15.jpg => ean13-1/34.jpg} (100%) rename core/test/data/blackbox/{upca-1/15.txt => ean13-1/34.txt} (100%) rename core/test/data/blackbox/{ean13-1/16.JPG => upca-1/35.jpg} (100%) rename core/test/data/blackbox/{ean13-1/16.txt => upca-1/35.txt} (100%) diff --git a/core/src/com/google/zxing/BarcodeFormat.java b/core/src/com/google/zxing/BarcodeFormat.java index b0ffae85b..90cbf731f 100644 --- a/core/src/com/google/zxing/BarcodeFormat.java +++ b/core/src/com/google/zxing/BarcodeFormat.java @@ -25,20 +25,38 @@ public final class BarcodeFormat { // No, we can't use an enum here. J2ME doesn't support it. - /** - * 1D barcode format family. - */ - public static final BarcodeFormat ONED = new BarcodeFormat(); - /** - * QR Code 2D barcode format - */ - public static final BarcodeFormat QR_CODE = new BarcodeFormat(); - /** - * DataMatrix 2D barcode format - */ - public static final BarcodeFormat DATAMATRIX = new BarcodeFormat(); + /** QR Code 2D barcode format. */ + public static final BarcodeFormat QR_CODE = new BarcodeFormat("QR_CODE"); - private BarcodeFormat() { + /** DataMatrix 2D barcode format. */ + public static final BarcodeFormat DATAMATRIX = new BarcodeFormat("DATAMATRIX"); + + /** UPC-E 1D format. */ + public static final BarcodeFormat UPC_E = new BarcodeFormat("UPC_E"); + + /** UPC-A 1D format. */ + public static final BarcodeFormat UPC_A = new BarcodeFormat("UPC_A"); + + /** EAN-8 1D format. */ + public static final BarcodeFormat EAN_8 = new BarcodeFormat("EAN_8"); + + /** EAN-13 1D format. */ + public static final BarcodeFormat EAN_13 = new BarcodeFormat("EAN_13"); + + /** Code 128 1D format. */ + public static final BarcodeFormat CODE_128 = new BarcodeFormat("CODE_128"); + + /** Code 39 1D format. */ + public static final BarcodeFormat CODE_39 = new BarcodeFormat("CODE_39"); + + private final String name; + + private BarcodeFormat(String name) { + this.name = name; + } + + public String toString() { + return name; } } \ No newline at end of file diff --git a/core/src/com/google/zxing/DecodeHintType.java b/core/src/com/google/zxing/DecodeHintType.java index 3a9e7eae5..8ab4bac1c 100644 --- a/core/src/com/google/zxing/DecodeHintType.java +++ b/core/src/com/google/zxing/DecodeHintType.java @@ -28,20 +28,21 @@ public final class DecodeHintType { // No, we can't use an enum here. J2ME doesn't support it. - /** - * Unspecified, application-specific hint. - */ + /** Unspecified, application-specific hint. */ public static final DecodeHintType OTHER = new DecodeHintType(); - /** - * Image is a pure monochrome image of a barcode. - */ + + /** Image is a pure monochrome image of a barcode. */ public static final DecodeHintType PURE_BARCODE = new DecodeHintType(); + /** * Image is known to be of one of a few possible formats. - * Maps to {@link java.util.Collection} of {@link BarcodeFormat}s. + * Maps to a collection of {@link BarcodeFormat}s. */ public static final DecodeHintType POSSIBLE_FORMATS = new DecodeHintType(); + /** Spend more time to try to find a barcode; optimize for accuracy, not speed. */ + public static final DecodeHintType TRY_HARDER = new DecodeHintType(); + private DecodeHintType() { } diff --git a/core/src/com/google/zxing/MultiFormatReader.java b/core/src/com/google/zxing/MultiFormatReader.java index 815c78609..9d1fc0213 100644 --- a/core/src/com/google/zxing/MultiFormatReader.java +++ b/core/src/com/google/zxing/MultiFormatReader.java @@ -20,6 +20,7 @@ import com.google.zxing.oned.MultiFormatOneDReader; import com.google.zxing.qrcode.QRCodeReader; import java.util.Hashtable; +import java.util.Vector; /** *

This implementation can detect barcodes in one of several formats within @@ -34,36 +35,34 @@ public final class MultiFormatReader implements Reader { return decode(image, null); } - public Result decode(MonochromeBitmapSource image, Hashtable hints) - throws ReaderException { + public Result decode(MonochromeBitmapSource image, Hashtable hints) throws ReaderException { + Hashtable possibleFormats = hints == null ? null : (Hashtable) hints.get(DecodeHintType.POSSIBLE_FORMATS); - - boolean tryOneD; - boolean tryQR; - if (possibleFormats == null) { - tryOneD = true; - tryQR = true; - } else { - tryOneD = possibleFormats.contains(BarcodeFormat.ONED); - tryQR = possibleFormats.contains(BarcodeFormat.QR_CODE); - } - if (!(tryOneD || tryQR)) { - throw new ReaderException("POSSIBLE_FORMATS specifies no supported types"); - } - - // UPC is much faster to decode, so try it first. - if (tryOneD) { - try { - return new MultiFormatOneDReader().decode(image, hints); - } catch (ReaderException re) { + Vector readers = new Vector(); + if (possibleFormats != null) { + if (possibleFormats.contains(BarcodeFormat.UPC_A) || + possibleFormats.contains(BarcodeFormat.UPC_E) || + possibleFormats.contains(BarcodeFormat.EAN_13) || + possibleFormats.contains(BarcodeFormat.EAN_8) || + possibleFormats.contains(BarcodeFormat.CODE_39) || + possibleFormats.contains(BarcodeFormat.CODE_128)) { + readers.addElement(new MultiFormatOneDReader()); + } + if (possibleFormats.contains(BarcodeFormat.QR_CODE)) { + readers.addElement(new QRCodeReader()); } } + if (readers.isEmpty()) { + readers.addElement(new MultiFormatOneDReader()); + readers.addElement(new QRCodeReader()); + } - // Then fall through to QR codes. - if (tryQR) { + for (int i = 0; i < readers.size(); i++) { + Reader reader = (Reader) readers.elementAt(i); try { - return new QRCodeReader().decode(image, hints); + return reader.decode(image, hints); } catch (ReaderException re) { + // continue } } diff --git a/core/src/com/google/zxing/Result.java b/core/src/com/google/zxing/Result.java index 42f194714..d63743fbb 100644 --- a/core/src/com/google/zxing/Result.java +++ b/core/src/com/google/zxing/Result.java @@ -25,10 +25,12 @@ public final class Result { private final String text; private final ResultPoint[] resultPoints; + private final BarcodeFormat format; - public Result(String text, ResultPoint[] resultPoints) { + public Result(String text, ResultPoint[] resultPoints, BarcodeFormat format) { this.text = text; this.resultPoints = resultPoints; + this.format = format; } /** @@ -47,4 +49,11 @@ public final class Result { return resultPoints; } + /** + * @return {@link BarcodeFormat} representing the format of the barcode that was recognized and decoded + */ + public BarcodeFormat getBarcodeFormat() { + return format; + } + } diff --git a/core/src/com/google/zxing/oned/AbstractOneDReader.java b/core/src/com/google/zxing/oned/AbstractOneDReader.java index 226ea91a6..756d28a7f 100644 --- a/core/src/com/google/zxing/oned/AbstractOneDReader.java +++ b/core/src/com/google/zxing/oned/AbstractOneDReader.java @@ -17,6 +17,7 @@ package com.google.zxing.oned; import com.google.zxing.BlackPointEstimationMethod; +import com.google.zxing.DecodeHintType; import com.google.zxing.MonochromeBitmapSource; import com.google.zxing.ReaderException; import com.google.zxing.Result; @@ -65,15 +66,16 @@ public abstract class AbstractOneDReader implements OneDReader { image.getBlackRow(rowNumber, row, 0, width); try { - return decodeRow(rowNumber, row); + return decodeRow(rowNumber, row, hints); } catch (ReaderException re) { - // TODO re-enable this in a "try harder" mode? - //row.reverse(); // try scanning the row backwards - //try { - // return decodeRow(rowNumber, row); - //} catch (ReaderException re2) { - // continue - //} + if (hints != null && hints.contains(DecodeHintType.TRY_HARDER)) { + row.reverse(); // try scanning the row backwards + try { + return decodeRow(rowNumber, row, hints); + } catch (ReaderException re2) { + // continue + } + } } } @@ -82,7 +84,8 @@ public abstract class AbstractOneDReader implements OneDReader { } protected static void recordPattern(BitArray row, int start, int[] counters) throws ReaderException { - for (int i = 0; i < counters.length; i++) { + int numCounters = counters.length; + for (int i = 0; i < numCounters; i++) { counters[i] = 0; } int end = row.getSize(); @@ -98,7 +101,7 @@ public abstract class AbstractOneDReader implements OneDReader { counters[counterPosition]++; } else { counterPosition++; - if (counterPosition == counters.length) { + if (counterPosition == numCounters) { break; } else { counters[counterPosition] = 1; @@ -109,7 +112,7 @@ public abstract class AbstractOneDReader implements OneDReader { } // If we read fully the last section of pixels and filled up our counters -- or filled // the last counter but ran off the side of the image, OK. Otherwise, a problem. - if (!(counterPosition == counters.length || (counterPosition == counters.length - 1 && i == end))) { + if (!(counterPosition == numCounters || (counterPosition == numCounters - 1 && i == end))) { throw new ReaderException("Couldn't fully read a pattern"); } } diff --git a/core/src/com/google/zxing/oned/AbstractUPCEANReader.java b/core/src/com/google/zxing/oned/AbstractUPCEANReader.java index 9b4191348..81cdb312b 100644 --- a/core/src/com/google/zxing/oned/AbstractUPCEANReader.java +++ b/core/src/com/google/zxing/oned/AbstractUPCEANReader.java @@ -16,12 +16,15 @@ package com.google.zxing.oned; +import com.google.zxing.BarcodeFormat; import com.google.zxing.ReaderException; import com.google.zxing.Result; import com.google.zxing.ResultPoint; import com.google.zxing.common.BitArray; import com.google.zxing.common.GenericResultPoint; +import java.util.Hashtable; + /** *

Encapsulates functionality and implementation that is common to UPC and EAN families * of one-dimensional barcodes.

@@ -95,7 +98,7 @@ public abstract class AbstractUPCEANReader extends AbstractOneDReader implements return startRange; } - public final Result decodeRow(int rowNumber, BitArray row) throws ReaderException { + public final Result decodeRow(int rowNumber, BitArray row, Hashtable hints) throws ReaderException { return decodeRow(rowNumber, row, findStartGuardPattern(row)); } @@ -118,11 +121,16 @@ public abstract class AbstractUPCEANReader extends AbstractOneDReader implements throw new ReaderException("Checksum failed"); } - return new Result(resultString, new ResultPoint[]{ - new GenericResultPoint((float) (startGuardRange[1] - startGuardRange[0]) / 2.0f, (float) rowNumber), - new GenericResultPoint((float) (endRange[1] - endRange[0]) / 2.0f, (float) rowNumber)}); + return new Result( + resultString, + new ResultPoint[]{ + new GenericResultPoint((float) (startGuardRange[1] - startGuardRange[0]) / 2.0f, (float) rowNumber), + new GenericResultPoint((float) (endRange[1] - endRange[0]) / 2.0f, (float) rowNumber)}, + getBarcodeFormat()); } + abstract BarcodeFormat getBarcodeFormat(); + /** * Computes the UPC/EAN checksum on a string of digits, and reports * whether the checksum is correct or not. diff --git a/core/src/com/google/zxing/oned/Code128Reader.java b/core/src/com/google/zxing/oned/Code128Reader.java index a46c7cee3..96bf2c957 100644 --- a/core/src/com/google/zxing/oned/Code128Reader.java +++ b/core/src/com/google/zxing/oned/Code128Reader.java @@ -16,12 +16,15 @@ package com.google.zxing.oned; +import com.google.zxing.BarcodeFormat; import com.google.zxing.ReaderException; import com.google.zxing.Result; import com.google.zxing.ResultPoint; import com.google.zxing.common.BitArray; import com.google.zxing.common.GenericResultPoint; +import java.util.Hashtable; + /** *

Decodes Code 128 barcodes.

* @@ -229,7 +232,7 @@ public final class Code128Reader extends AbstractOneDReader { } } - public Result decodeRow(final int rowNumber, final BitArray row) throws ReaderException { + public Result decodeRow(int rowNumber, BitArray row, Hashtable hints) throws ReaderException { int[] startPatternInfo = findStartPattern(row); int startCode = startPatternInfo[2]; @@ -402,11 +405,12 @@ public final class Code128Reader extends AbstractOneDReader { } String resultString = result.toString(); - return new Result(resultString, - new ResultPoint[]{new GenericResultPoint((float) (startPatternInfo[1] - startPatternInfo[0]) / 2.0f, - (float) rowNumber), - new GenericResultPoint((float) (nextStart - lastStart) / 2.0f, - (float) rowNumber)}); + return new Result( + resultString, + new ResultPoint[]{ + new GenericResultPoint((float) (startPatternInfo[1] - startPatternInfo[0]) / 2.0f, (float) rowNumber), + new GenericResultPoint((float) (nextStart - lastStart) / 2.0f, (float) rowNumber)}, + BarcodeFormat.CODE_128); } diff --git a/core/src/com/google/zxing/oned/Code39Reader.java b/core/src/com/google/zxing/oned/Code39Reader.java index 1d910283b..57f1009c6 100644 --- a/core/src/com/google/zxing/oned/Code39Reader.java +++ b/core/src/com/google/zxing/oned/Code39Reader.java @@ -16,12 +16,15 @@ package com.google.zxing.oned; +import com.google.zxing.BarcodeFormat; import com.google.zxing.ReaderException; import com.google.zxing.Result; import com.google.zxing.ResultPoint; import com.google.zxing.common.BitArray; import com.google.zxing.common.GenericResultPoint; +import java.util.Hashtable; + /** *

Decodes Code 39 barcodes. This does not supported "Full ASCII Code 39" yet.

* @@ -86,7 +89,7 @@ public final class Code39Reader extends AbstractOneDReader { this.extendedMode = extendedMode; } - public Result decodeRow(final int rowNumber, final BitArray row) throws ReaderException { + public Result decodeRow(int rowNumber, BitArray row, Hashtable hints) throws ReaderException { int[] start = findAsteriskPattern(row); @@ -135,9 +138,12 @@ public final class Code39Reader extends AbstractOneDReader { if (extendedMode) { resultString = decodeExtended(resultString); } - return new Result(resultString, - new ResultPoint[]{new GenericResultPoint((float) (start[1] - start[0]) / 2.0f, (float) rowNumber), - new GenericResultPoint((float) (nextStart - lastStart) / 2.0f, (float) rowNumber)}); + return new Result( + resultString, + new ResultPoint[]{ + new GenericResultPoint((float) (start[1] - start[0]) / 2.0f, (float) rowNumber), + new GenericResultPoint((float) (nextStart - lastStart) / 2.0f, (float) rowNumber)}, + BarcodeFormat.CODE_39); } diff --git a/core/src/com/google/zxing/oned/EAN13Reader.java b/core/src/com/google/zxing/oned/EAN13Reader.java index 19debf5eb..525664357 100644 --- a/core/src/com/google/zxing/oned/EAN13Reader.java +++ b/core/src/com/google/zxing/oned/EAN13Reader.java @@ -17,6 +17,7 @@ package com.google.zxing.oned; import com.google.zxing.ReaderException; +import com.google.zxing.BarcodeFormat; import com.google.zxing.common.BitArray; /** @@ -96,6 +97,10 @@ public final class EAN13Reader extends AbstractUPCEANReader { return rowOffset; } + BarcodeFormat getBarcodeFormat() { + return BarcodeFormat.EAN_13; + } + /** * Based on pattern of odd-even ('L' and 'G') patterns used to encoded the explicitly-encoded digits * in a barcode, determines the implicitly encoded first digit and adds it to the result string. @@ -108,12 +113,7 @@ public final class EAN13Reader extends AbstractUPCEANReader { private static void determineFirstDigit(StringBuffer resultString, int lgPatternFound) throws ReaderException { for (int d = 0; d < 10; d++) { if (lgPatternFound == FIRST_DIGIT_ENCODINGS[d]) { - // OK, if the first digit is a 0, then this is effectively also a UPC-A code. - // I think it's best (?) to go ahead and treat it as if it had matched as UPC-A, and return a result - // *without* the leading 0 - if (d != 0) { - resultString.insert(0, (char) ('0' + d)); - } + resultString.insert(0, (char) ('0' + d)); return; } } diff --git a/core/src/com/google/zxing/oned/EAN8Reader.java b/core/src/com/google/zxing/oned/EAN8Reader.java index 57780e8b3..08983c884 100644 --- a/core/src/com/google/zxing/oned/EAN8Reader.java +++ b/core/src/com/google/zxing/oned/EAN8Reader.java @@ -17,6 +17,7 @@ package com.google.zxing.oned; import com.google.zxing.ReaderException; +import com.google.zxing.BarcodeFormat; import com.google.zxing.common.BitArray; /** @@ -54,4 +55,8 @@ public final class EAN8Reader extends AbstractUPCEANReader { return rowOffset; } + BarcodeFormat getBarcodeFormat() { + return BarcodeFormat.EAN_8; + } + } \ No newline at end of file diff --git a/core/src/com/google/zxing/oned/MultiFormatOneDReader.java b/core/src/com/google/zxing/oned/MultiFormatOneDReader.java index 20076debe..096374556 100644 --- a/core/src/com/google/zxing/oned/MultiFormatOneDReader.java +++ b/core/src/com/google/zxing/oned/MultiFormatOneDReader.java @@ -16,30 +16,55 @@ package com.google.zxing.oned; +import com.google.zxing.DecodeHintType; import com.google.zxing.ReaderException; import com.google.zxing.Result; +import com.google.zxing.BarcodeFormat; import com.google.zxing.common.BitArray; +import java.util.Hashtable; +import java.util.Vector; + /** * @author dswitkin@google.com (Daniel Switkin) * @author srowen@google.com (Sean Owen) */ public final class MultiFormatOneDReader extends AbstractOneDReader { - private final OneDReader[] readers = new OneDReader[]{ - new MultiFormatUPCEANReader(), new Code39Reader(), new Code128Reader() - }; + public Result decodeRow(int rowNumber, BitArray row, Hashtable hints) throws ReaderException { - public Result decodeRow(int rowNumber, BitArray row) throws ReaderException { - ReaderException saved = null; - for (int i = 0; i < readers.length; i++) { - try { - return readers[i].decodeRow(rowNumber, row); - } catch (ReaderException re) { - saved = re; + Hashtable possibleFormats = hints == null ? null : (Hashtable) hints.get(DecodeHintType.POSSIBLE_FORMATS); + Vector readers = new Vector(); + if (possibleFormats != null) { + if (possibleFormats.contains(BarcodeFormat.EAN_13) || + possibleFormats.contains(BarcodeFormat.UPC_A) || + possibleFormats.contains(BarcodeFormat.EAN_8) || + possibleFormats.contains(BarcodeFormat.UPC_E)) { + readers.addElement(new MultiFormatUPCEANReader()); + } + if (possibleFormats.contains(BarcodeFormat.CODE_39)) { + readers.addElement(new Code39Reader()); + } + if (possibleFormats.contains(BarcodeFormat.CODE_128)) { + readers.addElement(new Code128Reader()); } } - throw saved; + if (readers.isEmpty()) { + readers.addElement(new MultiFormatUPCEANReader()); + readers.addElement(new Code39Reader()); + readers.addElement(new Code128Reader()); + } + + for (int i = 0; i < readers.size(); i++) { + OneDReader reader = (OneDReader) readers.elementAt(i); + try { + return reader.decodeRow(rowNumber, row, hints); + } catch (ReaderException re) { + // continue + } + } + + throw new ReaderException("No barcode was detected in this image."); } } \ No newline at end of file diff --git a/core/src/com/google/zxing/oned/MultiFormatUPCEANReader.java b/core/src/com/google/zxing/oned/MultiFormatUPCEANReader.java index e7d1949c8..dff4ad53d 100644 --- a/core/src/com/google/zxing/oned/MultiFormatUPCEANReader.java +++ b/core/src/com/google/zxing/oned/MultiFormatUPCEANReader.java @@ -16,10 +16,15 @@ package com.google.zxing.oned; +import com.google.zxing.BarcodeFormat; +import com.google.zxing.DecodeHintType; import com.google.zxing.ReaderException; import com.google.zxing.Result; import com.google.zxing.common.BitArray; +import java.util.Hashtable; +import java.util.Vector; + /** *

A reader that can read all available UPC/EAN formats. If a caller wants to try to * read all such formats, it is most efficent to use this implementation rather than invoke @@ -29,26 +34,59 @@ import com.google.zxing.common.BitArray; */ public final class MultiFormatUPCEANReader extends AbstractOneDReader { - /** - * Reader implementations to which this implementation delegates, in the order - * they will be attempted. Order is important. - */ - private final UPCEANReader[] readers = new UPCEANReader[]{ - new EAN13Reader(), new UPCAReader(), new EAN8Reader(), new UPCEReader() - }; - - public Result decodeRow(int rowNumber, BitArray row) throws ReaderException { - // Compute this location once and reuse it on multiple implementations - int[] startGuardPattern = AbstractUPCEANReader.findStartGuardPattern(row); - ReaderException saved = null; - for (int i = 0; i < readers.length; i++) { - try { - return readers[i].decodeRow(rowNumber, row, startGuardPattern); - } catch (ReaderException re) { - saved = re; + public Result decodeRow(int rowNumber, BitArray row, Hashtable hints) throws ReaderException { + Hashtable possibleFormats = hints == null ? null : (Hashtable) hints.get(DecodeHintType.POSSIBLE_FORMATS); + Vector readers = new Vector(); + if (possibleFormats != null) { + if (possibleFormats.contains(BarcodeFormat.EAN_13)) { + readers.addElement(new EAN13Reader()); + } + if (possibleFormats.contains(BarcodeFormat.UPC_A)) { + readers.addElement(new UPCAReader()); + } + if (possibleFormats.contains(BarcodeFormat.EAN_8)) { + readers.addElement(new EAN8Reader()); + } + if (possibleFormats.contains(BarcodeFormat.UPC_E)) { + readers.addElement(new UPCEReader()); } } - throw saved; + if (readers.isEmpty()) { + readers.addElement(new EAN13Reader()); + readers.addElement(new UPCAReader()); + readers.addElement(new EAN8Reader()); + readers.addElement(new UPCEReader()); + } + + // Compute this location once and reuse it on multiple implementations + int[] startGuardPattern = AbstractUPCEANReader.findStartGuardPattern(row); + for (int i = 0; i < readers.size(); i++) { + UPCEANReader reader = (UPCEANReader) readers.elementAt(i); + Result result; + try { + result = reader.decodeRow(rowNumber, row, startGuardPattern); + } catch (ReaderException re) { + continue; + } + // Special case: a 12-digit code encoded in UPC-A is identical to a "0" + // followed by those 12 digits encoded as EAN-13. Each will recognize such a code, + // UPC-A as a 12-digit string and EAN-13 as a 13-digit string starting with "0". + // Individually these are correct. + // + // These cases can't be distinguished, so we defer to the UPC-A decoder and + // treat this case as a UPC-A code. But if we let the UPC-A decoder look at + // symbols first, it will recognize any EAN-13 code as a 12-digit string, + // which is wrong. So EAN-13 has to try first. + // + // Here is, therefore, where we implement this logic: + if (result.getBarcodeFormat().equals(BarcodeFormat.EAN_13) && + result.getText().charAt(0) == '0') { + return new Result(result.getText().substring(1), result.getResultPoints(), BarcodeFormat.UPC_A); + } + return result; + } + + throw new ReaderException("No barcode was detected in this image."); } } \ No newline at end of file diff --git a/core/src/com/google/zxing/oned/OneDReader.java b/core/src/com/google/zxing/oned/OneDReader.java index 8667c28c9..ab44bbc4e 100644 --- a/core/src/com/google/zxing/oned/OneDReader.java +++ b/core/src/com/google/zxing/oned/OneDReader.java @@ -21,6 +21,8 @@ import com.google.zxing.ReaderException; import com.google.zxing.Result; import com.google.zxing.common.BitArray; +import java.util.Hashtable; + /** *

{@link Reader}s which also implement this interface read one-dimensional barcode * formats, and expose additional functionality that is specific to this type of barcode.

@@ -35,9 +37,10 @@ public interface OneDReader extends Reader { * * @param rowNumber row number from top of the row * @param row the black/white pixel data of the row + * @param hints decode hints * @return {@link Result} containing encoded string and start/end of barcode * @throws ReaderException if an error occurs or barcode cannot be found */ - Result decodeRow(int rowNumber, BitArray row) throws ReaderException; + Result decodeRow(int rowNumber, BitArray row, Hashtable hints) throws ReaderException; } \ No newline at end of file diff --git a/core/src/com/google/zxing/oned/UPCAReader.java b/core/src/com/google/zxing/oned/UPCAReader.java index f4dfdc607..14b9044d5 100644 --- a/core/src/com/google/zxing/oned/UPCAReader.java +++ b/core/src/com/google/zxing/oned/UPCAReader.java @@ -17,6 +17,7 @@ package com.google.zxing.oned; import com.google.zxing.ReaderException; +import com.google.zxing.BarcodeFormat; import com.google.zxing.common.BitArray; /** @@ -54,4 +55,8 @@ public final class UPCAReader extends AbstractUPCEANReader { return rowOffset; } + BarcodeFormat getBarcodeFormat() { + return BarcodeFormat.UPC_A; + } + } \ No newline at end of file diff --git a/core/src/com/google/zxing/oned/UPCEReader.java b/core/src/com/google/zxing/oned/UPCEReader.java index 13fcfd5b3..2b689778b 100644 --- a/core/src/com/google/zxing/oned/UPCEReader.java +++ b/core/src/com/google/zxing/oned/UPCEReader.java @@ -17,6 +17,7 @@ package com.google.zxing.oned; import com.google.zxing.ReaderException; +import com.google.zxing.BarcodeFormat; import com.google.zxing.common.BitArray; /** @@ -92,6 +93,10 @@ public final class UPCEReader extends AbstractUPCEANReader { throw new ReaderException("Unable to determine number system and check digit"); } + BarcodeFormat getBarcodeFormat() { + return BarcodeFormat.UPC_E; + } + /** * Expands a UPC-E value back into its full, equivalent UPC-A code value. * diff --git a/core/src/com/google/zxing/qrcode/QRCodeReader.java b/core/src/com/google/zxing/qrcode/QRCodeReader.java index 7edea20c3..7001576a2 100644 --- a/core/src/com/google/zxing/qrcode/QRCodeReader.java +++ b/core/src/com/google/zxing/qrcode/QRCodeReader.java @@ -16,6 +16,7 @@ package com.google.zxing.qrcode; +import com.google.zxing.BarcodeFormat; import com.google.zxing.DecodeHintType; import com.google.zxing.MonochromeBitmapSource; import com.google.zxing.Reader; @@ -63,7 +64,7 @@ public final class QRCodeReader implements Reader { text = decoder.decode(result.getBits()); points = result.getPoints(); } - return new Result(text, points); + return new Result(text, points, BarcodeFormat.QR_CODE); } /** diff --git a/core/test/data/blackbox/upca-1/14.jpg b/core/test/data/blackbox/ean13-1/33.jpg similarity index 100% rename from core/test/data/blackbox/upca-1/14.jpg rename to core/test/data/blackbox/ean13-1/33.jpg diff --git a/core/test/data/blackbox/upca-1/14.txt b/core/test/data/blackbox/ean13-1/33.txt similarity index 100% rename from core/test/data/blackbox/upca-1/14.txt rename to core/test/data/blackbox/ean13-1/33.txt diff --git a/core/test/data/blackbox/upca-1/15.jpg b/core/test/data/blackbox/ean13-1/34.jpg similarity index 100% rename from core/test/data/blackbox/upca-1/15.jpg rename to core/test/data/blackbox/ean13-1/34.jpg diff --git a/core/test/data/blackbox/upca-1/15.txt b/core/test/data/blackbox/ean13-1/34.txt similarity index 100% rename from core/test/data/blackbox/upca-1/15.txt rename to core/test/data/blackbox/ean13-1/34.txt diff --git a/core/test/data/blackbox/ean13-1/16.JPG b/core/test/data/blackbox/upca-1/35.jpg similarity index 100% rename from core/test/data/blackbox/ean13-1/16.JPG rename to core/test/data/blackbox/upca-1/35.jpg diff --git a/core/test/data/blackbox/ean13-1/16.txt b/core/test/data/blackbox/upca-1/35.txt similarity index 100% rename from core/test/data/blackbox/ean13-1/16.txt rename to core/test/data/blackbox/upca-1/35.txt diff --git a/core/test/src/com/google/zxing/common/AbstractBlackBoxTestCase.java b/core/test/src/com/google/zxing/common/AbstractBlackBoxTestCase.java index c2f935774..9bf121fd2 100644 --- a/core/test/src/com/google/zxing/common/AbstractBlackBoxTestCase.java +++ b/core/test/src/com/google/zxing/common/AbstractBlackBoxTestCase.java @@ -16,6 +16,7 @@ package com.google.zxing.common; +import com.google.zxing.BarcodeFormat; import com.google.zxing.MonochromeBitmapSource; import com.google.zxing.Reader; import com.google.zxing.ReaderException; @@ -50,11 +51,16 @@ public abstract class AbstractBlackBoxTestCase extends TestCase { private final File testBase; private final Reader barcodeReader; private final double passPercent; + private final BarcodeFormat expectedFormat; - protected AbstractBlackBoxTestCase(File testBase, Reader barcodeReader, double passPercent) { + protected AbstractBlackBoxTestCase(File testBase, + Reader barcodeReader, + double passPercent, + BarcodeFormat expectedFormat) { this.testBase = testBase; this.barcodeReader = barcodeReader; this.passPercent = passPercent; + this.expectedFormat = expectedFormat; } public void testBlackBox() throws IOException { @@ -82,6 +88,8 @@ public abstract class AbstractBlackBoxTestCase extends TestCase { continue; } + assertEquals(expectedFormat, result.getBarcodeFormat()); + String testImageFileName = testImage.getName(); File expectedTextFile = new File(testBase, testImageFileName.substring(0, testImageFileName.indexOf('.')) + ".txt"); diff --git a/core/test/src/com/google/zxing/oned/Code128BlackBox1TestCase.java b/core/test/src/com/google/zxing/oned/Code128BlackBox1TestCase.java index 52800a93f..5922e733e 100644 --- a/core/test/src/com/google/zxing/oned/Code128BlackBox1TestCase.java +++ b/core/test/src/com/google/zxing/oned/Code128BlackBox1TestCase.java @@ -16,6 +16,7 @@ package com.google.zxing.oned; +import com.google.zxing.BarcodeFormat; import com.google.zxing.MultiFormatReader; import com.google.zxing.common.AbstractBlackBoxTestCase; @@ -27,7 +28,7 @@ import java.io.File; public final class Code128BlackBox1TestCase extends AbstractBlackBoxTestCase { public Code128BlackBox1TestCase() { - super(new File("test/data/blackbox/code128-1"), new MultiFormatReader(), 1.0); + super(new File("test/data/blackbox/code128-1"), new MultiFormatReader(), 1.0, BarcodeFormat.CODE_128); } } \ No newline at end of file diff --git a/core/test/src/com/google/zxing/oned/Code39BlackBox1TestCase.java b/core/test/src/com/google/zxing/oned/Code39BlackBox1TestCase.java index 9b6bfff24..204c976e0 100644 --- a/core/test/src/com/google/zxing/oned/Code39BlackBox1TestCase.java +++ b/core/test/src/com/google/zxing/oned/Code39BlackBox1TestCase.java @@ -17,6 +17,7 @@ package com.google.zxing.oned; import com.google.zxing.MultiFormatReader; +import com.google.zxing.BarcodeFormat; import com.google.zxing.common.AbstractBlackBoxTestCase; import java.io.File; @@ -27,7 +28,7 @@ import java.io.File; public final class Code39BlackBox1TestCase extends AbstractBlackBoxTestCase { public Code39BlackBox1TestCase() { - super(new File("test/data/blackbox/code39-1"), new MultiFormatReader(), 1.0); + super(new File("test/data/blackbox/code39-1"), new MultiFormatReader(), 1.0, BarcodeFormat.CODE_39); } } \ No newline at end of file diff --git a/core/test/src/com/google/zxing/oned/Code39ExtendedBlackBox2TestCase.java b/core/test/src/com/google/zxing/oned/Code39ExtendedBlackBox2TestCase.java index b449ce8bf..55cbf59b5 100644 --- a/core/test/src/com/google/zxing/oned/Code39ExtendedBlackBox2TestCase.java +++ b/core/test/src/com/google/zxing/oned/Code39ExtendedBlackBox2TestCase.java @@ -17,6 +17,7 @@ package com.google.zxing.oned; import com.google.zxing.common.AbstractBlackBoxTestCase; +import com.google.zxing.BarcodeFormat; import java.io.File; @@ -26,7 +27,7 @@ import java.io.File; public final class Code39ExtendedBlackBox2TestCase extends AbstractBlackBoxTestCase { public Code39ExtendedBlackBox2TestCase() { - super(new File("test/data/blackbox/code39-2"), new Code39Reader(false, true), 1.0); + super(new File("test/data/blackbox/code39-2"), new Code39Reader(false, true), 1.0, BarcodeFormat.CODE_39); } } \ No newline at end of file diff --git a/core/test/src/com/google/zxing/oned/EAN13BlackBox1TestCase.java b/core/test/src/com/google/zxing/oned/EAN13BlackBox1TestCase.java index 4023d6949..d98db59ad 100644 --- a/core/test/src/com/google/zxing/oned/EAN13BlackBox1TestCase.java +++ b/core/test/src/com/google/zxing/oned/EAN13BlackBox1TestCase.java @@ -17,6 +17,7 @@ package com.google.zxing.oned; import com.google.zxing.MultiFormatReader; +import com.google.zxing.BarcodeFormat; import com.google.zxing.common.AbstractBlackBoxTestCase; import java.io.File; @@ -27,7 +28,7 @@ import java.io.File; public final class EAN13BlackBox1TestCase extends AbstractBlackBoxTestCase { public EAN13BlackBox1TestCase() { - super(new File("test/data/blackbox/ean13-1"), new MultiFormatReader(), 0.66); + super(new File("test/data/blackbox/ean13-1"), new MultiFormatReader(), 0.66, BarcodeFormat.EAN_13); } } \ No newline at end of file diff --git a/core/test/src/com/google/zxing/oned/UPCABlackBox1TestCase.java b/core/test/src/com/google/zxing/oned/UPCABlackBox1TestCase.java index 49c68ce87..7d099d433 100644 --- a/core/test/src/com/google/zxing/oned/UPCABlackBox1TestCase.java +++ b/core/test/src/com/google/zxing/oned/UPCABlackBox1TestCase.java @@ -17,6 +17,7 @@ package com.google.zxing.oned; import com.google.zxing.MultiFormatReader; +import com.google.zxing.BarcodeFormat; import com.google.zxing.common.AbstractBlackBoxTestCase; import java.io.File; @@ -27,7 +28,7 @@ import java.io.File; public final class UPCABlackBox1TestCase extends AbstractBlackBoxTestCase { public UPCABlackBox1TestCase() { - super(new File("test/data/blackbox/upca-1"), new MultiFormatReader(), 0.5); + super(new File("test/data/blackbox/upca-1"), new MultiFormatReader(), 0.5, BarcodeFormat.UPC_A); } } \ No newline at end of file diff --git a/core/test/src/com/google/zxing/qrcode/QRCodeBlackBox1TestCase.java b/core/test/src/com/google/zxing/qrcode/QRCodeBlackBox1TestCase.java index 4eab70e81..801f626eb 100644 --- a/core/test/src/com/google/zxing/qrcode/QRCodeBlackBox1TestCase.java +++ b/core/test/src/com/google/zxing/qrcode/QRCodeBlackBox1TestCase.java @@ -17,6 +17,7 @@ package com.google.zxing.qrcode; import com.google.zxing.MultiFormatReader; +import com.google.zxing.BarcodeFormat; import com.google.zxing.common.AbstractBlackBoxTestCase; import java.io.File; @@ -27,7 +28,7 @@ import java.io.File; public final class QRCodeBlackBox1TestCase extends AbstractBlackBoxTestCase { public QRCodeBlackBox1TestCase() { - super(new File("test/data/blackbox/qrcode-1"), new MultiFormatReader(), 0.5); + super(new File("test/data/blackbox/qrcode-1"), new MultiFormatReader(), 0.5, BarcodeFormat.QR_CODE); } } \ No newline at end of file diff --git a/core/test/src/com/google/zxing/qrcode/QRCodeBlackBox2TestCase.java b/core/test/src/com/google/zxing/qrcode/QRCodeBlackBox2TestCase.java index 6630fff7f..f1ecdd5ae 100644 --- a/core/test/src/com/google/zxing/qrcode/QRCodeBlackBox2TestCase.java +++ b/core/test/src/com/google/zxing/qrcode/QRCodeBlackBox2TestCase.java @@ -17,6 +17,7 @@ package com.google.zxing.qrcode; import com.google.zxing.MultiFormatReader; +import com.google.zxing.BarcodeFormat; import com.google.zxing.common.AbstractBlackBoxTestCase; import java.io.File; @@ -27,7 +28,7 @@ import java.io.File; public final class QRCodeBlackBox2TestCase extends AbstractBlackBoxTestCase { public QRCodeBlackBox2TestCase() { - super(new File("test/data/blackbox/qrcode-2"), new MultiFormatReader(), 1.0); + super(new File("test/data/blackbox/qrcode-2"), new MultiFormatReader(), 1.0, BarcodeFormat.QR_CODE); } } \ No newline at end of file