Style changes mostly

git-svn-id: https://zxing.googlecode.com/svn/trunk@985 59b500cc-1b3d-0410-9834-0bbf25fbcc57
This commit is contained in:
srowen 2009-06-24 13:19:53 +00:00
parent 372dfa1145
commit 969088fa82
6 changed files with 2353 additions and 2481 deletions

View file

@ -1,3 +1,19 @@
/*
* Copyright 2009 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.pdf417; package com.google.zxing.pdf417;
import com.google.zxing.BarcodeFormat; import com.google.zxing.BarcodeFormat;
@ -21,107 +37,107 @@ import java.util.Hashtable;
* @author SITA Lab (kevin.osullivan@sita.aero) * @author SITA Lab (kevin.osullivan@sita.aero)
*/ */
public final class PDF417Reader implements Reader { public final class PDF417Reader implements Reader {
private static final ResultPoint[] NO_POINTS = new ResultPoint[0];
private final Decoder decoder = new Decoder(); private static final ResultPoint[] NO_POINTS = new ResultPoint[0];
/** private final Decoder decoder = new Decoder();
* Locates and decodes a PDF417 code in an image.
*
* @return a String representing the content encoded by the PDF417 code
* @throws ReaderException if a PDF417 code cannot be found, or cannot be decoded
*/
public Result decode(MonochromeBitmapSource image) throws ReaderException {
return decode(image, null);
}
public Result decode(MonochromeBitmapSource image, Hashtable hints) /**
throws ReaderException { * Locates and decodes a PDF417 code in an image.
DecoderResult decoderResult; *
ResultPoint[] points; * @return a String representing the content encoded by the PDF417 code
if (hints != null && hints.containsKey(DecodeHintType.PURE_BARCODE)) { * @throws ReaderException if a PDF417 code cannot be found, or cannot be decoded
BitMatrix bits = extractPureBits(image); */
decoderResult = decoder.decode(bits); public Result decode(MonochromeBitmapSource image) throws ReaderException {
points = NO_POINTS; return decode(image, null);
} else { }
DetectorResult detectorResult = new Detector(image).detect();
decoderResult = decoder.decode(detectorResult.getBits());
points = detectorResult.getPoints();
}
Result result = new Result(decoderResult.getText(), decoderResult.getRawBytes(), points, BarcodeFormat.PDF417);
return result;
}
/** public Result decode(MonochromeBitmapSource image, Hashtable hints)
* This method detects a barcode in a "pure" image -- that is, pure monochrome image throws ReaderException {
* which contains only an unrotated, unskewed, image of a barcode, with some white border DecoderResult decoderResult;
* around it. This is a specialized method that works exceptionally fast in this special ResultPoint[] points;
* case. if (hints != null && hints.containsKey(DecodeHintType.PURE_BARCODE)) {
*/ BitMatrix bits = extractPureBits(image);
private static BitMatrix extractPureBits(MonochromeBitmapSource image) throws ReaderException { decoderResult = decoder.decode(bits);
// Now need to determine module size in pixels points = NO_POINTS;
} else {
DetectorResult detectorResult = new Detector(image).detect();
decoderResult = decoder.decode(detectorResult.getBits());
points = detectorResult.getPoints();
}
return new Result(decoderResult.getText(), decoderResult.getRawBytes(), points, BarcodeFormat.PDF417);
}
int height = image.getHeight(); /**
int width = image.getWidth(); * This method detects a barcode in a "pure" image -- that is, pure monochrome image
int minDimension = Math.min(height, width); * which contains only an unrotated, unskewed, image of a barcode, with some white border
* around it. This is a specialized method that works exceptionally fast in this special
* case.
*/
private static BitMatrix extractPureBits(MonochromeBitmapSource image) throws ReaderException {
// Now need to determine module size in pixels
// First, skip white border by tracking diagonally from the top left down and to the right: int height = image.getHeight();
int borderWidth = 0; int width = image.getWidth();
while (borderWidth < minDimension && !image.isBlack(borderWidth, borderWidth)) { int minDimension = Math.min(height, width);
borderWidth++;
}
if (borderWidth == minDimension) {
throw ReaderException.getInstance();
}
// And then keep tracking across the top-left black module to determine module size // First, skip white border by tracking diagonally from the top left down and to the right:
int moduleEnd = borderWidth; int borderWidth = 0;
while (moduleEnd < minDimension && image.isBlack(moduleEnd, moduleEnd)) { while (borderWidth < minDimension && !image.isBlack(borderWidth, borderWidth)) {
moduleEnd++; borderWidth++;
} }
if (moduleEnd == minDimension) { if (borderWidth == minDimension) {
throw ReaderException.getInstance(); throw ReaderException.getInstance();
} }
int moduleSize = moduleEnd - borderWidth; // And then keep tracking across the top-left black module to determine module size
int moduleEnd = borderWidth;
while (moduleEnd < minDimension && image.isBlack(moduleEnd, moduleEnd)) {
moduleEnd++;
}
if (moduleEnd == minDimension) {
throw ReaderException.getInstance();
}
// And now find where the rightmost black module on the first row ends int moduleSize = moduleEnd - borderWidth;
int rowEndOfSymbol = width - 1;
while (rowEndOfSymbol >= 0 && !image.isBlack(rowEndOfSymbol, borderWidth)) {
rowEndOfSymbol--;
}
if (rowEndOfSymbol < 0) {
throw ReaderException.getInstance();
}
rowEndOfSymbol++;
// Make sure width of barcode is a multiple of module size // And now find where the rightmost black module on the first row ends
if ((rowEndOfSymbol - borderWidth) % moduleSize != 0) { int rowEndOfSymbol = width - 1;
throw ReaderException.getInstance(); while (rowEndOfSymbol >= 0 && !image.isBlack(rowEndOfSymbol, borderWidth)) {
} rowEndOfSymbol--;
int dimension = (rowEndOfSymbol - borderWidth) / moduleSize; }
if (rowEndOfSymbol < 0) {
throw ReaderException.getInstance();
}
rowEndOfSymbol++;
// Push in the "border" by half the module width so that we start // Make sure width of barcode is a multiple of module size
// sampling in the middle of the module. Just in case the image is a if ((rowEndOfSymbol - borderWidth) % moduleSize != 0) {
// little off, this will help recover. throw ReaderException.getInstance();
borderWidth += moduleSize >> 1; }
int dimension = (rowEndOfSymbol - borderWidth) / moduleSize;
int sampleDimension = borderWidth + (dimension - 1) * moduleSize; // Push in the "border" by half the module width so that we start
if (sampleDimension >= width || sampleDimension >= height) { // sampling in the middle of the module. Just in case the image is a
throw ReaderException.getInstance(); // little off, this will help recover.
} borderWidth += moduleSize >> 1;
// Now just read off the bits int sampleDimension = borderWidth + (dimension - 1) * moduleSize;
BitMatrix bits = new BitMatrix(dimension); if (sampleDimension >= width || sampleDimension >= height) {
for (int i = 0; i < dimension; i++) { throw ReaderException.getInstance();
int iOffset = borderWidth + i * moduleSize; }
for (int j = 0; j < dimension; j++) {
if (image.isBlack(borderWidth + j * moduleSize, iOffset)) { // Now just read off the bits
bits.set(i, j); BitMatrix bits = new BitMatrix(dimension);
} for (int i = 0; i < dimension; i++) {
} int iOffset = borderWidth + i * moduleSize;
} for (int j = 0; j < dimension; j++) {
return bits; if (image.isBlack(borderWidth + j * moduleSize, iOffset)) {
} bits.set(i, j);
}
}
}
return bits;
}
} }

File diff suppressed because it is too large Load diff

View file

@ -1,5 +1,5 @@
/* /*
* Copyright 2007 ZXing authors * Copyright 2009 ZXing authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package com.google.zxing.pdf417.decoder; package com.google.zxing.pdf417.decoder;
import com.google.zxing.ReaderException; import com.google.zxing.ReaderException;
@ -27,146 +28,120 @@ import com.google.zxing.common.DecoderResult;
* @author SITA Lab (kevin.osullivan@sita.aero) * @author SITA Lab (kevin.osullivan@sita.aero)
*/ */
public final class Decoder { public final class Decoder {
public static final boolean debug = false;
private static final int MAX_ERRORS = 3;
private static final int MAX_EC_CODEWORDS = 512;
//private final ReedSolomonDecoder rsDecoder;
public Decoder() { private static final int MAX_ERRORS = 3;
// TODO MGMG private static final int MAX_EC_CODEWORDS = 512;
//rsDecoder = new ReedSolomonDecoder(); //private final ReedSolomonDecoder rsDecoder;
}
/** public Decoder() {
* <p>Convenience method that can decode a PDF417 Code represented as a 2D array of booleans. // TODO MGMG
* "true" is taken to mean a black module.</p> //rsDecoder = new ReedSolomonDecoder();
* }
* @param image booleans representing white/black PDF417 modules
* @return text and bytes encoded within the PDF417 Code
* @throws ReaderException if the PDF417 Code cannot be decoded
*/
public DecoderResult decode(boolean[][] image) throws ReaderException {
int dimension = image.length;
BitMatrix bits = new BitMatrix(dimension);
for (int i = 0; i < dimension; i++) {
for (int j = 0; j < dimension; j++) {
if (image[i][j]) {
bits.set(i, j);
}
}
}
return decode(bits);
}
/** /**
* <p>Decodes a PDF417 Code represented as a {@link BitMatrix}. * <p>Convenience method that can decode a PDF417 Code represented as a 2D array of booleans.
* A 1 or "true" is taken to mean a black module.</p> * "true" is taken to mean a black module.</p>
* *
* @param bits booleans representing white/black PDF417 Code modules * @param image booleans representing white/black PDF417 modules
* @return text and bytes encoded within the PDF417 Code * @return text and bytes encoded within the PDF417 Code
* @throws ReaderException if the PDF417 Code cannot be decoded * @throws ReaderException if the PDF417 Code cannot be decoded
*/ */
public DecoderResult decode(BitMatrix bits) throws ReaderException { public DecoderResult decode(boolean[][] image) throws ReaderException {
// Construct a parser to read the data codewords and error-correction level int dimension = image.length;
long t2; BitMatrix bits = new BitMatrix(dimension);
long t1 = System.currentTimeMillis(); for (int i = 0; i < dimension; i++) {
BitMatrixParser parser = new BitMatrixParser(bits); for (int j = 0; j < dimension; j++) {
int[] codewords = parser.readCodewords(); if (image[i][j]) {
if (codewords == null || codewords.length == 0) { bits.set(i, j);
if (debug) System.out.println("No codewords read"); }
throw ReaderException.getInstance(); }
} }
if (debug) { return decode(bits);
t2 = System.currentTimeMillis(); }
System.out.println("Elapsed time in ms - BitMatrixParser " +(t2-t1));
}
int ecLevel = parser.getECLevel(); /**
int numECCodewords = 1 << (ecLevel+1); * <p>Decodes a PDF417 Code represented as a {@link BitMatrix}.
int erasures[] = parser.getErasures(); * A 1 or "true" is taken to mean a black module.</p>
*
* @param bits booleans representing white/black PDF417 Code modules
* @return text and bytes encoded within the PDF417 Code
* @throws ReaderException if the PDF417 Code cannot be decoded
*/
public DecoderResult decode(BitMatrix bits) throws ReaderException {
// Construct a parser to read the data codewords and error-correction level
BitMatrixParser parser = new BitMatrixParser(bits);
int[] codewords = parser.readCodewords();
if (codewords == null || codewords.length == 0) {
throw ReaderException.getInstance();
}
t1 = System.currentTimeMillis(); int ecLevel = parser.getECLevel();
correctErrors(codewords, erasures, numECCodewords); int numECCodewords = 1 << (ecLevel + 1);
if (debug) { int[] erasures = parser.getErasures();
t2 = System.currentTimeMillis();
System.out.println("Elapsed time in ms - Reed Solomon " +(t2-t1));
}
verifyCodewordCount(codewords, numECCodewords);
t1 = System.currentTimeMillis(); correctErrors(codewords, erasures, numECCodewords);
DecoderResult dr = DecodedBitStreamParser.decode(codewords); verifyCodewordCount(codewords, numECCodewords);
if (debug) {
t2 = System.currentTimeMillis();
System.out.println("Elapsed time in ms - DecodeBitStreamParser " +(t2-t1));
}
// Decode the codewords
return dr;
}
/** // Decode the codewords
* Verify that all is OK with the codeword array. return DecodedBitStreamParser.decode(codewords);
* @param codewords }
* @return an index to the first data codeword.
* @throws ReaderException
*/
private int verifyCodewordCount(int codewords[], int numECCodewords) throws ReaderException {
int numberOfCodewords = 0;
if (codewords.length < 4) {
// Codeword array size should be at least 4 allowing for
// Count CW, At least one Data CW, Error Correction CW, Error Correction CW
if (debug) System.out.println("Not enough codewords " + codewords.length);
throw ReaderException.getInstance();
}
// The first codeword, the Symbol Length Descriptor, shall always encode the total number of data
// codewords in the symbol, including the Symbol Length Descriptor itself, data codewords and pad
// codewords, but excluding the number of error correction codewords.
numberOfCodewords = codewords[0];
if (numberOfCodewords > codewords.length) {
if (debug) System.out.println("Invalid number of codewords[0]=" + numberOfCodewords + " codewords.length=" + codewords.length);
throw ReaderException.getInstance();
}
if (numberOfCodewords == 0) {
// Reset to the length of the array - 8 (Allow for at least level 3 Error Correction (8 Error Codewords)
if (numECCodewords < codewords.length) {
codewords[0] = codewords.length - numECCodewords;
if (debug) System.out.println("Codewords[0] is zero, resetting to " +(codewords[0]));
} else {
if (debug) System.out.println("Codewords[0] is zero, no data codewords");
throw ReaderException.getInstance();
}
}
return 1; // Index to first data codeword
}
/** /**
* <p>Given data and error-correction codewords received, possibly corrupted by errors, attempts to * Verify that all is OK with the codeword array.
* correct the errors in-place using Reed-Solomon error correction.</p> *
* * @param codewords
* @param codewordBytes data and error correction codewords * @return an index to the first data codeword.
* @param numDataCodewords number of codewords that are data bytes * @throws ReaderException
* @throws ReaderException if error correction fails */
*/ private static int verifyCodewordCount(int[] codewords, int numECCodewords) throws ReaderException {
private int correctErrors(int[] codewords, int[] erasures, int numECCodewords) throws ReaderException { if (codewords.length < 4) {
if ((erasures != null && erasures.length > numECCodewords/2 + MAX_ERRORS) || // Codeword array size should be at least 4 allowing for
(numECCodewords < 0 || numECCodewords > MAX_EC_CODEWORDS)) { // Count CW, At least one Data CW, Error Correction CW, Error Correction CW
// Too many errors or EC Codewords is corrupted throw ReaderException.getInstance();
throw ReaderException.getInstance(); }
} // The first codeword, the Symbol Length Descriptor, shall always encode the total number of data
// Try to correct the errors // codewords in the symbol, including the Symbol Length Descriptor itself, data codewords and pad
int result = 0; // rsDecoder.correctErrors(codewords, numECCodewords); // codewords, but excluding the number of error correction codewords.
if (debug) { int numberOfCodewords = codewords[0];
System.out.println("Corrected errors: " + result); if (numberOfCodewords > codewords.length) {
} throw ReaderException.getInstance();
if (erasures != null) { }
int numErasures = erasures.length; if (numberOfCodewords == 0) {
if (result > 0) { // Reset to the length of the array - 8 (Allow for at least level 3 Error Correction (8 Error Codewords)
numErasures = numErasures - result; if (numECCodewords < codewords.length) {
} codewords[0] = codewords.length - numECCodewords;
if (numErasures > MAX_ERRORS) { } else {
// Still too many errors throw ReaderException.getInstance();
throw ReaderException.getInstance(); }
} }
} return 1; // Index to first data codeword
return result; }
/**
* <p>Given data and error-correction codewords received, possibly corrupted by errors, attempts to
* correct the errors in-place using Reed-Solomon error correction.</p>
*
* @param codewords data and error correction codewords
* @throws ReaderException if error correction fails
*/
private static int correctErrors(int[] codewords, int[] erasures, int numECCodewords) throws ReaderException {
if ((erasures != null && erasures.length > numECCodewords / 2 + MAX_ERRORS) ||
(numECCodewords < 0 || numECCodewords > MAX_EC_CODEWORDS)) {
// Too many errors or EC Codewords is corrupted
throw ReaderException.getInstance();
}
// Try to correct the errors
int result = 0; // rsDecoder.correctErrors(codewords, numECCodewords);
if (erasures != null) {
int numErasures = erasures.length;
if (result > 0) {
numErasures -= result;
}
if (numErasures > MAX_ERRORS) {
// Still too many errors
throw ReaderException.getInstance();
}
}
return result;
} }
} }

View file

@ -1,5 +1,5 @@
/* /*
* Copyright 2007 ZXing authors * Copyright 2009 ZXing authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -16,8 +16,6 @@
package com.google.zxing.pdf417.detector; package com.google.zxing.pdf417.detector;
import java.util.Hashtable;
import com.google.zxing.BlackPointEstimationMethod; import com.google.zxing.BlackPointEstimationMethod;
import com.google.zxing.MonochromeBitmapSource; import com.google.zxing.MonochromeBitmapSource;
import com.google.zxing.ReaderException; import com.google.zxing.ReaderException;
@ -27,6 +25,8 @@ import com.google.zxing.common.BitMatrix;
import com.google.zxing.common.DetectorResult; import com.google.zxing.common.DetectorResult;
import com.google.zxing.common.GridSampler; import com.google.zxing.common.GridSampler;
import java.util.Hashtable;
/** /**
* <p> * <p>
* Encapsulates logic that can detect a PDF417 Code in an image, even if the * Encapsulates logic that can detect a PDF417 Code in an image, even if the
@ -36,518 +36,435 @@ import com.google.zxing.common.GridSampler;
* @author SITA Lab (kevin.osullivan@sita.aero) * @author SITA Lab (kevin.osullivan@sita.aero)
*/ */
public final class Detector { public final class Detector {
public static final boolean debug = false;
public static final int MAX_AVG_VARIANCE = (int) ((1 << 8) * 0.42f);
public static final int MAX_INDIVIDUAL_VARIANCE = (int) ((1 << 8) * 0.8f);
// B S B S B S B S Bar/Space pattern
private static final int[] START_PATTERN = { 8, 1, 1, 1, 1, 1, 1, 3 }; // 11111111
// 0 1
// 0 1
// 0 1
// 000
// B S B S B S B S B Bar/Space pattern public static final int MAX_AVG_VARIANCE = (int) ((1 << 8) * 0.42f);
private static final int[] STOP_PATTERN_REVERSE = { 1, 2, 1, 1, 1, 3, 1, 1, public static final int MAX_INDIVIDUAL_VARIANCE = (int) ((1 << 8) * 0.8f);
7 }; // 1111111 0 1 000 1 0 1 00 1 // B S B S B S B S Bar/Space pattern
private static final int[] START_PATTERN = {8, 1, 1, 1, 1, 1, 1, 3}; // 11111111
// 0 1
// 0 1
// 0 1
// 000
private final MonochromeBitmapSource image; // B S B S B S B S B Bar/Space pattern
private static final int[] STOP_PATTERN_REVERSE = {1, 2, 1, 1, 1, 3, 1, 1,
7}; // 1111111 0 1 000 1 0 1 00 1
public Detector(MonochromeBitmapSource image) { private final MonochromeBitmapSource image;
this.image = image;
}
/** public Detector(MonochromeBitmapSource image) {
* <p> this.image = image;
* Detects a PDF417 Code in an image, simply. }
* </p>
*
* @return {@link DetectorResult} encapsulating results of detecting a PDF417
* Code
* @throws ReaderException
* if no QR Code can be found
*/
public DetectorResult detect() throws ReaderException {
return detect(null);
}
/** /**
* <p> * <p>
* Detects a PDF417 Code in an image, simply. * Detects a PDF417 Code in an image, simply.
* </p> * </p>
* *
* @param hints * @return {@link DetectorResult} encapsulating results of detecting a PDF417
* optional hints to detector * Code
* @return {@link DetectorResult} encapsulating results of detecting a PDF417 * @throws ReaderException if no QR Code can be found
* Code */
* @throws ReaderException public DetectorResult detect() throws ReaderException {
* if no PDF417 Code can be found return detect(null);
*/ }
public DetectorResult detect(Hashtable hints) throws ReaderException {
if (!BlackPointEstimationMethod.TWO_D_SAMPLING.equals(image
.getLastEstimationMethod())) {
image.estimateBlackPoint(BlackPointEstimationMethod.TWO_D_SAMPLING, 0);
}
int width = image.getWidth();
int height = image.getHeight();
if (debug)
System.out.println("Width= " + width);
if (debug)
System.out.println("Height= " + height);
long t2; /**
long t1 = System.currentTimeMillis(); * <p>
ResultPoint[] vertices = findVertices(image); * Detects a PDF417 Code in an image, simply.
if (vertices == null) { // Couldn't find the vertices * </p>
// Maybe the image is rotated 180 degrees? *
vertices = findVertices180(image); * @param hints optional hints to detector
/* * @return {@link DetectorResult} encapsulating results of detecting a PDF417
* // Don't need this because the PDF417 code won't fit into // the * Code
* camera view finder when it is rotated. if (vertices == null) { // * @throws ReaderException if no PDF417 Code can be found
* Couldn't find the vertices // Maybe the image is rotated 90 degrees? */
* vertices = findVertices90(image); if (vertices == null) { // public DetectorResult detect(Hashtable hints) throws ReaderException {
* Couldn't find the vertices // Maybe the image is rotated 270 if (!BlackPointEstimationMethod.TWO_D_SAMPLING.equals(image
* degrees? vertices = findVertices270(image); } } .getLastEstimationMethod())) {
*/ image.estimateBlackPoint(BlackPointEstimationMethod.TWO_D_SAMPLING, 0);
} }
if (vertices != null) {
if (debug) {
t2 = System.currentTimeMillis();
System.out.println("Elapsed time in ms - Find Vertices "
+ (t2 - t1));
}
float moduleWidth = computeModuleWidth(vertices); ResultPoint[] vertices = findVertices(image);
if (moduleWidth < 1.0f) { if (vertices == null) { // Couldn't find the vertices
if (debug) // Maybe the image is rotated 180 degrees?
System.out.println("Module Size is less than 1.0f=" vertices = findVertices180(image);
+ moduleWidth);
throw ReaderException.getInstance();
}
if (debug)
System.out.println("Module Size=" + moduleWidth);
int dimension = computeDimension(vertices[4], vertices[6],
vertices[5], vertices[7], moduleWidth);
if (debug)
System.out.println("Dimension=" + dimension);
// Deskew and sample image
t1 = System.currentTimeMillis();
BitMatrix bits = sampleGrid(image, vertices[4], vertices[5],
vertices[6], vertices[7], dimension);
//bits.setModuleWidth(moduleWidth);
if (debug) {
t2 = System.currentTimeMillis();
System.out
.println("Elapsed time in ms - Sampled Grid " + (t2 - t1));
}
return new DetectorResult(bits, new ResultPoint[] { vertices[4],
vertices[5], vertices[6], vertices[7] });
} else {
if (debug) {
System.out.println("Unable to locate vertices");
}
throw ReaderException.getInstance();
}
}
/**
* Locate the vertices and the codewords area of a black blob using the Start
* and Stop patterns as locators.
*
* @param image
* the scanned barcode image.
* @return the an array containing the vertices. vertices[0] x, y top left
* barcode vertices[1] x, y bottom left barcode vertices[2] x, y top
* right barcode vertices[3] x, y bottom right barcode vertices[4] x,
* y top left codeword area vertices[5] x, y bottom left codeword
* area vertices[6] x, y top right codeword area vertices[7] x, y
* bottom right codeword area
*/
private ResultPoint[] findVertices(MonochromeBitmapSource image) {
int height = image.getHeight();
int width = image.getWidth();
ResultPoint[] result = new ResultPoint[8];
BitArray row = null;
boolean found = false;
int[] loc = null;
// Top Left
for (int i = 0; i < height; i++) {
row = image.getBlackRow(i, null, 0, width / 4);
loc = findGuardPattern(row, 0, START_PATTERN);
if (loc != null) {
if (debug)
System.out.println("Found START pattern at X=" + loc[0]
+ " End X=" + loc[1] + ", Y=" + i);
result[0] = new ResultPoint(loc[0], i);
result[4] = new ResultPoint(loc[1], i);
found = true;
break;
}
}
// Bottom left
if (found) { // Found the Top Left vertex
found = false;
for (int i = height - 1; i > 0; i--) {
row = image.getBlackRow(i, null, 0, width / 4);
loc = findGuardPattern(row, 0, START_PATTERN);
if (loc != null) {
if (debug)
System.out.println("Found START pattern at X=" + loc[0]
+ " End X=" + loc[1] + ", Y=" + i);
result[1] = new ResultPoint(loc[0], i);
result[5] = new ResultPoint(loc[1], i);
found = true;
break;
}
}
}
// Top right
if (found) { // Found the Bottom Left vertex
found = false;
for (int i = 0; i < height; i++) {
row = image.getBlackRow(i, null, (width * 3) / 4, width / 4);
row.reverse();
loc = findGuardPattern(row, 0, STOP_PATTERN_REVERSE);
if (loc != null) {
if (debug)
System.out.println("Found STOP pattern at X="
+ (width - loc[0]) + " End X=" + (width - loc[1])
+ ", Y=" + i);
result[2] = new ResultPoint(width - loc[0], i);
result[6] = new ResultPoint(width - loc[1], i);
found = true;
break;
}
}
}
// Bottom right
if (found) { // Found the Top right vertex
found = false;
for (int i = height - 1; i > 0; i--) {
row = image.getBlackRow(i, null, (width * 3) / 4, width / 4);
row.reverse();
loc = findGuardPattern(row, 0, STOP_PATTERN_REVERSE);
if (loc != null) {
if (debug)
System.out.println("Found STOP pattern at X="
+ (width - loc[0]) + " End X=" + (width - loc[1])
+ ", Y=" + i);
result[3] = new ResultPoint(width - loc[0], i);
result[7] = new ResultPoint(width - loc[1], i);
found = true;
break;
}
}
}
if (found) {
return result;
} else {
return null;
}
}
/**
* Locate the vertices and the codewords area of a black blob using the Start
* and Stop patterns as locators. This assumes that the image is rotated 180
* degrees and if it locates the start and stop patterns at it will re-map
* the vertices for a 0 degree rotation.
*
* @param image
* the scanned barcode image.
* @return the an array containing the vertices. vertices[0] x, y top left
* barcode vertices[1] x, y bottom left barcode vertices[2] x, y top
* right barcode vertices[3] x, y bottom right barcode vertices[4] x,
* y top left codeword area vertices[5] x, y bottom left codeword
* area vertices[6] x, y top right codeword area vertices[7] x, y
* bottom right codeword area
*/
private ResultPoint[] findVertices180(MonochromeBitmapSource image) {
int height = image.getHeight();
int width = image.getWidth();
ResultPoint[] result = new ResultPoint[8];
BitArray row = null;
boolean found = false;
int[] loc = null;
// Top Left
for (int i = height - 1; i > 0; i--) {
row = image.getBlackRow(i, null, 0, width / 4);
row.reverse();
loc = findGuardPattern(row, 0, START_PATTERN);
if (loc != null) {
if (debug)
System.out.println("Found START pattern at X="
+ (width - loc[0]) + " End X=" + (width - loc[1]) + ", Y="
+ i);
result[0] = new ResultPoint(width - loc[0], i);
result[4] = new ResultPoint(width - loc[1], i);
found = true;
break;
}
}
// Bottom Left
if (found) { // Found the Top Left vertex
found = false;
for (int i = 0; i < height; i++) {
row = image.getBlackRow(i, null, 0, width / 4);
row.reverse();
loc = findGuardPattern(row, 0, START_PATTERN);
if (loc != null) {
if (debug)
System.out.println("Found START pattern at X="
+ (width - loc[0]) + " End X=" + (width - loc[1])
+ ", Y=" + i);
result[1] = new ResultPoint(width - loc[0], i);
result[5] = new ResultPoint(width - loc[1], i);
found = true;
break;
}
}
}
// Top Right
if (found) { // Found the Bottom Left vertex
found = false;
for (int i = height - 1; i > 0; i--) {
row = image.getBlackRow(i, null, (width * 3) / 4, width / 4);
loc = findGuardPattern(row, 0, STOP_PATTERN_REVERSE);
if (loc != null) {
if (debug)
System.out.println("Found STOP pattern at X=" + loc[0]
+ " End X=" + loc[1] + ", Y=" + i);
result[2] = new ResultPoint(loc[0], i);
result[6] = new ResultPoint(loc[1], i);
found = true;
break;
}
}
}
// Bottom Right
if (found) { // Found the Top Right vertex
found = false;
for (int i = 0; i < height; i++) {
row = image.getBlackRow(i, null, (width * 3) / 4, width / 4);
loc = findGuardPattern(row, 0, STOP_PATTERN_REVERSE);
if (loc != null) {
if (debug)
System.out.println("Found STOP pattern at X=" + loc[0]
+ " End X=" + loc[1] + ", Y=" + i);
result[3] = new ResultPoint(loc[0], i);
result[7] = new ResultPoint(loc[1], i);
found = true;
break;
}
}
}
if (found) {
return result;
} else {
return null;
}
}
/**
* <p>
* Estimates module size (pixels in a module) based on the Start and End
* finder patterns -- it uses
* {@link #sizeOfBlackWhiteBlackRun(int, int, int, int)} to figure the width
* of each.
*
* @param vertices
* [] vertices[0] x, y top left barcode vertices[1] x, y bottom
* left barcode vertices[2] x, y top right barcode vertices[3] x, y
* bottom right barcode vertices[4] x, y top left Codeword area
* vertices[5] x, y bottom left Codeword area vertices[6] x, y top
* right Codeword area vertices[7] x, y bottom right Codeword area
* @return the module size.
*/
private float computeModuleWidth(ResultPoint[] vertices) {
float pixels1 = ResultPoint.distance(vertices[0], vertices[4]);
float pixels2 = ResultPoint.distance(vertices[1], vertices[5]);
float moduleWidth1 = (pixels1 + pixels2) / (17 * 2.0f);
float pixels3 = ResultPoint.distance(vertices[6], vertices[2]);
float pixels4 = ResultPoint.distance(vertices[7], vertices[3]);
float moduleWidth2 = (pixels3 + pixels4) / (18 * 2.0f);
return (moduleWidth1 + moduleWidth2) / 2.0f;
}
/**
*
* Computes the dimension (number of modules in a row) of the PDF417 Code
* based on vertices of the codeword area and estimated module size.
*
* @param topLeft
* of codeword area
* @param topRight
* of codeword area
* @param bottomLeft
* of codeword area
* @param bottomRight
* of codeword are
* @param moduleWidth
* estimated module size
* @return the number of modules in a row.
*/
private static int computeDimension(ResultPoint topLeft,
ResultPoint topRight, ResultPoint bottomLeft, ResultPoint bottomRight,
float moduleWidth) {
int topRowDimension = round(ResultPoint
.distance(topLeft, topRight)
/ moduleWidth);
int bottomRowDimension = round(ResultPoint.distance(bottomLeft,
bottomRight)
/ moduleWidth);
int dimension = ((((topRowDimension + bottomRowDimension) >> 1) + 8) / 17) * 17;
return dimension;
/* /*
* int topRowDimension = round(ResultPoint.distance(topLeft, * // Don't need this because the PDF417 code won't fit into // the
* topRight)); //moduleWidth); int bottomRowDimension = * camera view finder when it is rotated. if (vertices == null) { //
* round(ResultPoint.distance(bottomLeft, bottomRight)); // * Couldn't find the vertices // Maybe the image is rotated 90 degrees?
* moduleWidth); int dimension = ((topRowDimension + bottomRowDimension) * vertices = findVertices90(image); if (vertices == null) { //
* >> 1); // Round up to nearest 17 modules i.e. there are 17 modules per * Couldn't find the vertices // Maybe the image is rotated 270
* codeword //int dimension = ((((topRowDimension + bottomRowDimension) >> * degrees? vertices = findVertices270(image); } }
* 1) + 8) / 17) * 17; return dimension; */
*/ }
} if (vertices != null) {
float moduleWidth = computeModuleWidth(vertices);
private static BitMatrix sampleGrid(MonochromeBitmapSource image, if (moduleWidth < 1.0f) {
ResultPoint topLeft, ResultPoint bottomLeft, ResultPoint topRight, throw ReaderException.getInstance();
ResultPoint bottomRight, int dimension) throws ReaderException {
// Note that unlike in the QR Code sampler, we didn't find the center of
// modules, but the
// very corners. So there is no 0.5f here; 0.0f is right.
GridSampler sampler = GridSampler.getInstance();
return sampler.sampleGrid(image, dimension, 0.0f, // p1ToX
0.0f, // p1ToY
dimension, // p2ToX
0.0f, // p2ToY
dimension, // p3ToX
dimension, // p3ToY
0.0f, // p4ToX
dimension, // p4ToY
topLeft.getX(), // p1FromX
topLeft.getY(), // p1FromY
topRight.getX(), // p2FromX
topRight.getY(), // p2FromY
bottomRight.getX(), // p3FromX
bottomRight.getY(), // p3FromY
bottomLeft.getX(), // p4FromX
bottomLeft.getY()); // p4FromY
}
/**
* Ends up being a bit faster than Math.round(). This merely rounds its
* argument to the nearest int, where x.5 rounds up.
*/
private static int round(float d) {
return (int) (d + 0.5f);
}
/**
* @param row
* row of black/white values to search
* @param rowOffset
* position to start search
* @param pattern
* pattern of counts of number of black and white pixels that are
* being searched for as a pattern
* @return start/end horizontal offset of guard pattern, as an array of two
* ints.
*/
int[] findGuardPattern(BitArray row, int rowOffset, int[] pattern) {
int patternLength = pattern.length;
int[] counters = new int[patternLength];
int width = row.getSize();
boolean isWhite = false;
int counterPosition = 0;
int patternStart = rowOffset;
for (int x = rowOffset; x < width; x++) {
boolean pixel = row.get(x);
if ((!pixel && isWhite) || (pixel && !isWhite)) {
counters[counterPosition]++;
} else {
if (counterPosition == patternLength - 1) {
if (patternMatchVariance(counters, pattern,
MAX_INDIVIDUAL_VARIANCE) < MAX_AVG_VARIANCE) {
return new int[] { patternStart, x };
}
patternStart += counters[0] + counters[1];
for (int y = 2; y < patternLength; y++) {
counters[y - 2] = counters[y];
}
counters[patternLength - 2] = 0;
counters[patternLength - 1] = 0;
counterPosition--;
} else {
counterPosition++;
}
counters[counterPosition] = 1;
isWhite = !isWhite;
}
} }
int dimension = computeDimension(vertices[4], vertices[6],
vertices[5], vertices[7], moduleWidth);
// Deskew and sample image
BitMatrix bits = sampleGrid(image, vertices[4], vertices[5],
vertices[6], vertices[7], dimension);
//bits.setModuleWidth(moduleWidth);
return new DetectorResult(bits, new ResultPoint[]{vertices[4],
vertices[5], vertices[6], vertices[7]});
} else {
throw ReaderException.getInstance();
}
}
/**
* Locate the vertices and the codewords area of a black blob using the Start
* and Stop patterns as locators.
*
* @param image the scanned barcode image.
* @return the an array containing the vertices. vertices[0] x, y top left
* barcode vertices[1] x, y bottom left barcode vertices[2] x, y top
* right barcode vertices[3] x, y bottom right barcode vertices[4] x,
* y top left codeword area vertices[5] x, y bottom left codeword
* area vertices[6] x, y top right codeword area vertices[7] x, y
* bottom right codeword area
*/
private static ResultPoint[] findVertices(MonochromeBitmapSource image) {
int height = image.getHeight();
int width = image.getWidth();
ResultPoint[] result = new ResultPoint[8];
BitArray row = null;
boolean found = false;
int[] loc = null;
// Top Left
for (int i = 0; i < height; i++) {
row = image.getBlackRow(i, null, 0, width / 4);
loc = findGuardPattern(row, 0, START_PATTERN);
if (loc != null) {
result[0] = new ResultPoint(loc[0], i);
result[4] = new ResultPoint(loc[1], i);
found = true;
break;
}
}
// Bottom left
if (found) { // Found the Top Left vertex
found = false;
for (int i = height - 1; i > 0; i--) {
row = image.getBlackRow(i, null, 0, width / 4);
loc = findGuardPattern(row, 0, START_PATTERN);
if (loc != null) {
result[1] = new ResultPoint(loc[0], i);
result[5] = new ResultPoint(loc[1], i);
found = true;
break;
}
}
}
// Top right
if (found) { // Found the Bottom Left vertex
found = false;
for (int i = 0; i < height; i++) {
row = image.getBlackRow(i, null, (width * 3) / 4, width / 4);
row.reverse();
loc = findGuardPattern(row, 0, STOP_PATTERN_REVERSE);
if (loc != null) {
result[2] = new ResultPoint(width - loc[0], i);
result[6] = new ResultPoint(width - loc[1], i);
found = true;
break;
}
}
}
// Bottom right
if (found) { // Found the Top right vertex
found = false;
for (int i = height - 1; i > 0; i--) {
row = image.getBlackRow(i, null, (width * 3) / 4, width / 4);
row.reverse();
loc = findGuardPattern(row, 0, STOP_PATTERN_REVERSE);
if (loc != null) {
result[3] = new ResultPoint(width - loc[0], i);
result[7] = new ResultPoint(width - loc[1], i);
found = true;
break;
}
}
}
return found ? result : null;
}
/**
* Locate the vertices and the codewords area of a black blob using the Start
* and Stop patterns as locators. This assumes that the image is rotated 180
* degrees and if it locates the start and stop patterns at it will re-map
* the vertices for a 0 degree rotation.
*
* @param image the scanned barcode image.
* @return the an array containing the vertices. vertices[0] x, y top left
* barcode vertices[1] x, y bottom left barcode vertices[2] x, y top
* right barcode vertices[3] x, y bottom right barcode vertices[4] x,
* y top left codeword area vertices[5] x, y bottom left codeword
* area vertices[6] x, y top right codeword area vertices[7] x, y
* bottom right codeword area
*/
private static ResultPoint[] findVertices180(MonochromeBitmapSource image) {
int height = image.getHeight();
int width = image.getWidth();
ResultPoint[] result = new ResultPoint[8];
BitArray row = null;
boolean found = false;
int[] loc = null;
// Top Left
for (int i = height - 1; i > 0; i--) {
row = image.getBlackRow(i, null, 0, width / 4);
row.reverse();
loc = findGuardPattern(row, 0, START_PATTERN);
if (loc != null) {
result[0] = new ResultPoint(width - loc[0], i);
result[4] = new ResultPoint(width - loc[1], i);
found = true;
break;
}
}
// Bottom Left
if (found) { // Found the Top Left vertex
found = false;
for (int i = 0; i < height; i++) {
row = image.getBlackRow(i, null, 0, width / 4);
row.reverse();
loc = findGuardPattern(row, 0, START_PATTERN);
if (loc != null) {
result[1] = new ResultPoint(width - loc[0], i);
result[5] = new ResultPoint(width - loc[1], i);
found = true;
break;
}
}
}
// Top Right
if (found) { // Found the Bottom Left vertex
found = false;
for (int i = height - 1; i > 0; i--) {
row = image.getBlackRow(i, null, (width * 3) / 4, width / 4);
loc = findGuardPattern(row, 0, STOP_PATTERN_REVERSE);
if (loc != null) {
result[2] = new ResultPoint(loc[0], i);
result[6] = new ResultPoint(loc[1], i);
found = true;
break;
}
}
}
// Bottom Right
if (found) { // Found the Top Right vertex
found = false;
for (int i = 0; i < height; i++) {
row = image.getBlackRow(i, null, (width * 3) / 4, width / 4);
loc = findGuardPattern(row, 0, STOP_PATTERN_REVERSE);
if (loc != null) {
result[3] = new ResultPoint(loc[0], i);
result[7] = new ResultPoint(loc[1], i);
found = true;
break;
}
}
}
if (found) {
return result;
} else {
return null; return null;
} }
}
/** /**
* Determines how closely a set of observed counts of runs of black/white * <p>
* values matches a given target pattern. This is reported as the ratio of * Estimates module size (pixels in a module) based on the Start and End
* the total variance from the expected pattern proportions across all * finder patterns.</p>
* pattern elements, to the length of the pattern. *
* * @param vertices [] vertices[0] x, y top left barcode vertices[1] x, y bottom
* @param counters * left barcode vertices[2] x, y top right barcode vertices[3] x, y
* observed counters * bottom right barcode vertices[4] x, y top left Codeword area
* @param pattern * vertices[5] x, y bottom left Codeword area vertices[6] x, y top
* expected pattern * right Codeword area vertices[7] x, y bottom right Codeword area
* @param maxIndividualVariance * @return the module size.
* The most any counter can differ before we give up */
* @return ratio of total variance between counters and pattern compared to private static float computeModuleWidth(ResultPoint[] vertices) {
* total pattern size, where the ratio has been multiplied by 256. float pixels1 = ResultPoint.distance(vertices[0], vertices[4]);
* So, 0 means no variance (perfect match); 256 means the total float pixels2 = ResultPoint.distance(vertices[1], vertices[5]);
* variance between counters and patterns equals the pattern length, float moduleWidth1 = (pixels1 + pixels2) / (17 * 2.0f);
* higher values mean even more variance float pixels3 = ResultPoint.distance(vertices[6], vertices[2]);
float pixels4 = ResultPoint.distance(vertices[7], vertices[3]);
float moduleWidth2 = (pixels3 + pixels4) / (18 * 2.0f);
return (moduleWidth1 + moduleWidth2) / 2.0f;
}
/**
* Computes the dimension (number of modules in a row) of the PDF417 Code
* based on vertices of the codeword area and estimated module size.
*
* @param topLeft of codeword area
* @param topRight of codeword area
* @param bottomLeft of codeword area
* @param bottomRight of codeword are
* @param moduleWidth estimated module size
* @return the number of modules in a row.
*/
private static int computeDimension(ResultPoint topLeft,
ResultPoint topRight, ResultPoint bottomLeft, ResultPoint bottomRight,
float moduleWidth) {
int topRowDimension = round(ResultPoint
.distance(topLeft, topRight)
/ moduleWidth);
int bottomRowDimension = round(ResultPoint.distance(bottomLeft,
bottomRight)
/ moduleWidth);
return ((((topRowDimension + bottomRowDimension) >> 1) + 8) / 17) * 17;
/*
* int topRowDimension = round(ResultPoint.distance(topLeft,
* topRight)); //moduleWidth); int bottomRowDimension =
* round(ResultPoint.distance(bottomLeft, bottomRight)); //
* moduleWidth); int dimension = ((topRowDimension + bottomRowDimension)
* >> 1); // Round up to nearest 17 modules i.e. there are 17 modules per
* codeword //int dimension = ((((topRowDimension + bottomRowDimension) >>
* 1) + 8) / 17) * 17; return dimension;
*/ */
public static int patternMatchVariance(int[] counters, int[] pattern, }
int maxIndividualVariance) {
int numCounters = counters.length;
int total = 0;
int patternLength = 0;
for (int i = 0; i < numCounters; i++) {
total += counters[i];
patternLength += pattern[i];
}
if (total < patternLength) {
// If we don't even have one pixel per unit of bar width, assume this
// is too small
// to reliably match, so fail:
return Integer.MAX_VALUE;
}
// 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 << 8) / patternLength;
maxIndividualVariance = (maxIndividualVariance * unitBarWidth) >> 8;
int totalVariance = 0; private static BitMatrix sampleGrid(MonochromeBitmapSource image,
for (int x = 0; x < numCounters; x++) { ResultPoint topLeft, ResultPoint bottomLeft, ResultPoint topRight,
int counter = counters[x] << 8; ResultPoint bottomRight, int dimension) throws ReaderException {
int scaledPattern = pattern[x] * unitBarWidth;
int variance = counter > scaledPattern ? counter - scaledPattern // Note that unlike in the QR Code sampler, we didn't find the center of
: scaledPattern - counter; // modules, but the
if (variance > maxIndividualVariance) { // very corners. So there is no 0.5f here; 0.0f is right.
return Integer.MAX_VALUE; GridSampler sampler = GridSampler.getInstance();
} return sampler.sampleGrid(image, dimension, 0.0f, // p1ToX
totalVariance += variance; 0.0f, // p1ToY
dimension, // p2ToX
0.0f, // p2ToY
dimension, // p3ToX
dimension, // p3ToY
0.0f, // p4ToX
dimension, // p4ToY
topLeft.getX(), // p1FromX
topLeft.getY(), // p1FromY
topRight.getX(), // p2FromX
topRight.getY(), // p2FromY
bottomRight.getX(), // p3FromX
bottomRight.getY(), // p3FromY
bottomLeft.getX(), // p4FromX
bottomLeft.getY()); // p4FromY
}
/**
* Ends up being a bit faster than Math.round(). This merely rounds its
* argument to the nearest int, where x.5 rounds up.
*/
private static int round(float d) {
return (int) (d + 0.5f);
}
/**
* @param row row of black/white values to search
* @param rowOffset position to start search
* @param pattern pattern of counts of number of black and white pixels that are
* being searched for as a pattern
* @return start/end horizontal offset of guard pattern, as an array of two
* ints.
*/
static int[] findGuardPattern(BitArray row, int rowOffset, int[] pattern) {
int patternLength = pattern.length;
int[] counters = new int[patternLength];
int width = row.getSize();
boolean isWhite = false;
int counterPosition = 0;
int patternStart = rowOffset;
for (int x = rowOffset; x < width; x++) {
boolean pixel = row.get(x);
if (pixel ^ isWhite) {
counters[counterPosition]++;
} else {
if (counterPosition == patternLength - 1) {
if (patternMatchVariance(counters, pattern,
MAX_INDIVIDUAL_VARIANCE) < MAX_AVG_VARIANCE) {
return new int[]{patternStart, x};
}
patternStart += counters[0] + counters[1];
for (int y = 2; y < patternLength; y++) {
counters[y - 2] = counters[y];
}
counters[patternLength - 2] = 0;
counters[patternLength - 1] = 0;
counterPosition--;
} else {
counterPosition++;
}
counters[counterPosition] = 1;
isWhite = !isWhite;
} }
return totalVariance / total; }
} return null;
}
/**
* Determines how closely a set of observed counts of runs of black/white
* values matches a given target pattern. This is reported as the ratio of
* the total variance from the expected pattern proportions across all
* pattern elements, to the length of the pattern.
*
* @param counters observed counters
* @param pattern expected pattern
* @param maxIndividualVariance The most any counter can differ before we give up
* @return ratio of total variance between counters and pattern compared to
* total pattern size, where the ratio has been multiplied by 256.
* So, 0 means no variance (perfect match); 256 means the total
* variance between counters and patterns equals the pattern length,
* higher values mean even more variance
*/
public static int patternMatchVariance(int[] counters, int[] pattern,
int maxIndividualVariance) {
int numCounters = counters.length;
int total = 0;
int patternLength = 0;
for (int i = 0; i < numCounters; i++) {
total += counters[i];
patternLength += pattern[i];
}
if (total < patternLength) {
// If we don't even have one pixel per unit of bar width, assume this
// is too small
// to reliably match, so fail:
return Integer.MAX_VALUE;
}
// 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 << 8) / patternLength;
maxIndividualVariance = (maxIndividualVariance * unitBarWidth) >> 8;
int totalVariance = 0;
for (int x = 0; x < numCounters; x++) {
int counter = counters[x] << 8;
int scaledPattern = pattern[x] * unitBarWidth;
int variance = counter > scaledPattern ? counter - scaledPattern
: scaledPattern - counter;
if (variance > maxIndividualVariance) {
return Integer.MAX_VALUE;
}
totalVariance += variance;
}
return totalVariance / total;
}
} }

View file

@ -37,12 +37,12 @@ public final class PDF417BlackBox1TestCase extends AbstractBlackBoxTestCase {
//addTest(1, 1, 270.0f); //addTest(1, 1, 270.0f);
} }
@Override
protected Hashtable<DecodeHintType, Object> getHints() { protected Hashtable<DecodeHintType, Object> getHints() {
Hashtable<DecodeHintType, Object> table = new Hashtable<DecodeHintType, Object>(); Hashtable<DecodeHintType, Object> table = new Hashtable<DecodeHintType, Object>(3);
Vector v = new Vector(); Vector<BarcodeFormat> v = new Vector<BarcodeFormat>(1);
v.add(BarcodeFormat.PDF417); v.add(BarcodeFormat.PDF417);
table.put(DecodeHintType.POSSIBLE_FORMATS, v); table.put(DecodeHintType.POSSIBLE_FORMATS, v);
return table; return table;
} }