diff --git a/core/src/main/java/com/google/zxing/DecodeHintType.java b/core/src/main/java/com/google/zxing/DecodeHintType.java index 11f579e62..a53275003 100644 --- a/core/src/main/java/com/google/zxing/DecodeHintType.java +++ b/core/src/main/java/com/google/zxing/DecodeHintType.java @@ -98,6 +98,12 @@ public enum DecodeHintType { */ ALLOWED_EAN_EXTENSIONS(int[].class), + /** + * If true, also tries to decode as inverted image. All configured decoders are simply called a + * second time with an inverted image. Doesn't matter what it maps to; use {@link Boolean#TRUE}. + */ + ALSO_INVERTED(Void.class), + // End of enumeration values. ; diff --git a/core/src/main/java/com/google/zxing/MultiFormatReader.java b/core/src/main/java/com/google/zxing/MultiFormatReader.java index 44cef6d17..c7a566f40 100644 --- a/core/src/main/java/com/google/zxing/MultiFormatReader.java +++ b/core/src/main/java/com/google/zxing/MultiFormatReader.java @@ -175,6 +175,17 @@ public final class MultiFormatReader implements Reader { // continue } } + if (hints != null && hints.containsKey(DecodeHintType.ALSO_INVERTED)) { + // Calling all readers again with inverted image + image.getBlackMatrix().flip(); + for (Reader reader : readers) { + try { + return reader.decode(image, hints); + } catch (ReaderException re) { + // continue + } + } + } } throw NotFoundException.getNotFoundInstance(); } diff --git a/core/src/main/java/com/google/zxing/common/BitMatrix.java b/core/src/main/java/com/google/zxing/common/BitMatrix.java index 6eea3b618..7438306f6 100755 --- a/core/src/main/java/com/google/zxing/common/BitMatrix.java +++ b/core/src/main/java/com/google/zxing/common/BitMatrix.java @@ -189,6 +189,16 @@ public final class BitMatrix implements Cloneable { bits[offset] ^= 1 << (x & 0x1f); } + /** + *

Flips every bit in the matrix.

+ */ + public void flip() { + int max = bits.length; + for (int i = 0; i < max; i++) { + bits[i] = ~bits[i]; + } + } + /** * Exclusive-or (XOR): Flip the bit in this {@code BitMatrix} if the corresponding * mask bit is set. diff --git a/core/src/test/java/com/google/zxing/common/AbstractBlackBoxTestCase.java b/core/src/test/java/com/google/zxing/common/AbstractBlackBoxTestCase.java index cc2374371..f295f31dc 100644 --- a/core/src/test/java/com/google/zxing/common/AbstractBlackBoxTestCase.java +++ b/core/src/test/java/com/google/zxing/common/AbstractBlackBoxTestCase.java @@ -62,6 +62,7 @@ public abstract class AbstractBlackBoxTestCase extends Assert { private final Reader barcodeReader; private final BarcodeFormat expectedFormat; private final List testResults; + private final EnumMap hints = new EnumMap<>(DecodeHintType.class); public static Path buildTestBase(String testBasePathSuffix) { // A little workaround to prevent aggravation in my IDE @@ -92,6 +93,10 @@ public abstract class AbstractBlackBoxTestCase extends Assert { addTest(mustPassCount, tryHarderCount, 0, 0, rotation); } + protected void addHint(DecodeHintType hint) { + hints.put(hint, Boolean.TRUE); + } + /** * Adds a new test for the current directory of images. * @@ -252,7 +257,7 @@ public abstract class AbstractBlackBoxTestCase extends Assert { String suffix = String.format(" (%srotation: %d)", tryHarder ? "try harder, " : "", (int) rotation); - Map hints = new EnumMap<>(DecodeHintType.class); + Map hints = this.hints.clone(); if (tryHarder) { hints.put(DecodeHintType.TRY_HARDER, Boolean.TRUE); } diff --git a/core/src/test/java/com/google/zxing/inverted/InvertedDataMatrixBlackBoxTestCase.java b/core/src/test/java/com/google/zxing/inverted/InvertedDataMatrixBlackBoxTestCase.java new file mode 100644 index 000000000..c2c942e44 --- /dev/null +++ b/core/src/test/java/com/google/zxing/inverted/InvertedDataMatrixBlackBoxTestCase.java @@ -0,0 +1,38 @@ +/* + * Copyright 2008 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.zxing.inverted; + +import com.google.zxing.BarcodeFormat; +import com.google.zxing.DecodeHintType; +import com.google.zxing.MultiFormatReader; +import com.google.zxing.common.AbstractBlackBoxTestCase; + +/** + * Inverted barcodes + */ +public final class InvertedDataMatrixBlackBoxTestCase extends AbstractBlackBoxTestCase { + + public InvertedDataMatrixBlackBoxTestCase() { + super("src/test/resources/blackbox/inverted", new MultiFormatReader(), BarcodeFormat.DATA_MATRIX); + addHint(DecodeHintType.ALSO_INVERTED); + addTest(1, 1, 0.0f); + addTest(1, 1, 90.0f); + addTest(1, 1, 180.0f); + addTest(1, 1, 270.0f); + } + +} diff --git a/core/src/test/java/com/google/zxing/inverted/NoHintInvertedDataMatrixBlackBoxTestCase.java b/core/src/test/java/com/google/zxing/inverted/NoHintInvertedDataMatrixBlackBoxTestCase.java new file mode 100644 index 000000000..ca3a6b2c2 --- /dev/null +++ b/core/src/test/java/com/google/zxing/inverted/NoHintInvertedDataMatrixBlackBoxTestCase.java @@ -0,0 +1,34 @@ +/* + * Copyright 2008 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.zxing.inverted; + +import com.google.zxing.common.AbstractNegativeBlackBoxTestCase; + +/** + * Without hint inverted barcodes should not be found. + */ +public final class NoHintInvertedDataMatrixBlackBoxTestCase extends AbstractNegativeBlackBoxTestCase { + + public NoHintInvertedDataMatrixBlackBoxTestCase() { + super("src/test/resources/blackbox/inverted"); + addTest(0, 0.0f); + addTest(0, 90.0f); + addTest(0, 180.0f); + addTest(0, 270.0f); + } + +} diff --git a/core/src/test/resources/blackbox/inverted/datamatrix-0123456789.png b/core/src/test/resources/blackbox/inverted/datamatrix-0123456789.png new file mode 100644 index 000000000..72e7de88e Binary files /dev/null and b/core/src/test/resources/blackbox/inverted/datamatrix-0123456789.png differ diff --git a/core/src/test/resources/blackbox/inverted/datamatrix-0123456789.txt b/core/src/test/resources/blackbox/inverted/datamatrix-0123456789.txt new file mode 100644 index 000000000..ad471007b --- /dev/null +++ b/core/src/test/resources/blackbox/inverted/datamatrix-0123456789.txt @@ -0,0 +1 @@ +0123456789 \ No newline at end of file