mirror of
https://github.com/zxing/zxing.git
synced 2025-03-05 20:48:51 -08:00
Style changes mostly
git-svn-id: https://zxing.googlecode.com/svn/trunk@985 59b500cc-1b3d-0410-9834-0bbf25fbcc57
This commit is contained in:
parent
372dfa1145
commit
969088fa82
|
@ -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 {
|
||||||
int height = image.getHeight();
|
DetectorResult detectorResult = new Detector(image).detect();
|
||||||
int width = image.getWidth();
|
decoderResult = decoder.decode(detectorResult.getBits());
|
||||||
int minDimension = Math.min(height, width);
|
points = detectorResult.getPoints();
|
||||||
|
}
|
||||||
|
return new Result(decoderResult.getText(), decoderResult.getRawBytes(), points, BarcodeFormat.PDF417);
|
||||||
|
}
|
||||||
|
|
||||||
// First, skip white border by tracking diagonally from the top left down and to the right:
|
/**
|
||||||
int borderWidth = 0;
|
* This method detects a barcode in a "pure" image -- that is, pure monochrome image
|
||||||
while (borderWidth < minDimension && !image.isBlack(borderWidth, borderWidth)) {
|
* which contains only an unrotated, unskewed, image of a barcode, with some white border
|
||||||
borderWidth++;
|
* around it. This is a specialized method that works exceptionally fast in this special
|
||||||
}
|
* case.
|
||||||
if (borderWidth == minDimension) {
|
*/
|
||||||
throw ReaderException.getInstance();
|
private static BitMatrix extractPureBits(MonochromeBitmapSource image) throws ReaderException {
|
||||||
}
|
// Now need to determine module size in pixels
|
||||||
|
|
||||||
// And then keep tracking across the top-left black module to determine module size
|
int height = image.getHeight();
|
||||||
int moduleEnd = borderWidth;
|
int width = image.getWidth();
|
||||||
while (moduleEnd < minDimension && image.isBlack(moduleEnd, moduleEnd)) {
|
int minDimension = Math.min(height, width);
|
||||||
moduleEnd++;
|
|
||||||
}
|
|
||||||
if (moduleEnd == minDimension) {
|
|
||||||
throw ReaderException.getInstance();
|
|
||||||
}
|
|
||||||
|
|
||||||
int moduleSize = moduleEnd - borderWidth;
|
// First, skip white border by tracking diagonally from the top left down and to the right:
|
||||||
|
int borderWidth = 0;
|
||||||
|
while (borderWidth < minDimension && !image.isBlack(borderWidth, borderWidth)) {
|
||||||
|
borderWidth++;
|
||||||
|
}
|
||||||
|
if (borderWidth == minDimension) {
|
||||||
|
throw ReaderException.getInstance();
|
||||||
|
}
|
||||||
|
|
||||||
// And now find where the rightmost black module on the first row ends
|
// And then keep tracking across the top-left black module to determine module size
|
||||||
int rowEndOfSymbol = width - 1;
|
int moduleEnd = borderWidth;
|
||||||
while (rowEndOfSymbol >= 0 && !image.isBlack(rowEndOfSymbol, borderWidth)) {
|
while (moduleEnd < minDimension && image.isBlack(moduleEnd, moduleEnd)) {
|
||||||
rowEndOfSymbol--;
|
moduleEnd++;
|
||||||
}
|
}
|
||||||
if (rowEndOfSymbol < 0) {
|
if (moduleEnd == minDimension) {
|
||||||
throw ReaderException.getInstance();
|
throw ReaderException.getInstance();
|
||||||
}
|
}
|
||||||
rowEndOfSymbol++;
|
|
||||||
|
|
||||||
// Make sure width of barcode is a multiple of module size
|
int moduleSize = moduleEnd - borderWidth;
|
||||||
if ((rowEndOfSymbol - borderWidth) % moduleSize != 0) {
|
|
||||||
throw ReaderException.getInstance();
|
|
||||||
}
|
|
||||||
int dimension = (rowEndOfSymbol - borderWidth) / moduleSize;
|
|
||||||
|
|
||||||
// Push in the "border" by half the module width so that we start
|
// And now find where the rightmost black module on the first row ends
|
||||||
// sampling in the middle of the module. Just in case the image is a
|
int rowEndOfSymbol = width - 1;
|
||||||
// little off, this will help recover.
|
while (rowEndOfSymbol >= 0 && !image.isBlack(rowEndOfSymbol, borderWidth)) {
|
||||||
borderWidth += moduleSize >> 1;
|
rowEndOfSymbol--;
|
||||||
|
}
|
||||||
|
if (rowEndOfSymbol < 0) {
|
||||||
|
throw ReaderException.getInstance();
|
||||||
|
}
|
||||||
|
rowEndOfSymbol++;
|
||||||
|
|
||||||
int sampleDimension = borderWidth + (dimension - 1) * moduleSize;
|
// Make sure width of barcode is a multiple of module size
|
||||||
if (sampleDimension >= width || sampleDimension >= height) {
|
if ((rowEndOfSymbol - borderWidth) % moduleSize != 0) {
|
||||||
throw ReaderException.getInstance();
|
throw ReaderException.getInstance();
|
||||||
}
|
}
|
||||||
|
int dimension = (rowEndOfSymbol - borderWidth) / moduleSize;
|
||||||
|
|
||||||
// Now just read off the bits
|
// Push in the "border" by half the module width so that we start
|
||||||
BitMatrix bits = new BitMatrix(dimension);
|
// sampling in the middle of the module. Just in case the image is a
|
||||||
for (int i = 0; i < dimension; i++) {
|
// little off, this will help recover.
|
||||||
int iOffset = borderWidth + i * moduleSize;
|
borderWidth += moduleSize >> 1;
|
||||||
for (int j = 0; j < dimension; j++) {
|
|
||||||
if (image.isBlack(borderWidth + j * moduleSize, iOffset)) {
|
int sampleDimension = borderWidth + (dimension - 1) * moduleSize;
|
||||||
bits.set(i, j);
|
if (sampleDimension >= width || sampleDimension >= height) {
|
||||||
}
|
throw ReaderException.getInstance();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return bits;
|
// Now just read off the bits
|
||||||
}
|
BitMatrix bits = new BitMatrix(dimension);
|
||||||
|
for (int i = 0; i < dimension; i++) {
|
||||||
|
int iOffset = borderWidth + i * moduleSize;
|
||||||
|
for (int j = 0; j < dimension; j++) {
|
||||||
|
if (image.isBlack(borderWidth + j * moduleSize, iOffset)) {
|
||||||
|
bits.set(i, j);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return bits;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
@ -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;
|
||||||
|
@ -21,152 +22,126 @@ import com.google.zxing.common.DecoderResult;
|
||||||
//import com.google.zxing.pdf417.reedsolomon.ReedSolomonDecoder;
|
//import com.google.zxing.pdf417.reedsolomon.ReedSolomonDecoder;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>The main class which implements PDF417 Code decoding -- as
|
* <p>The main class which implements PDF417 Code decoding -- as
|
||||||
* opposed to locating and extracting the PDF417 Code from an image.</p>
|
* opposed to locating and extracting the PDF417 Code from an image.</p>
|
||||||
*
|
*
|
||||||
* @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>
|
||||||
|
*
|
||||||
t1 = System.currentTimeMillis();
|
* @param bits booleans representing white/black PDF417 Code modules
|
||||||
correctErrors(codewords, erasures, numECCodewords);
|
* @return text and bytes encoded within the PDF417 Code
|
||||||
if (debug) {
|
* @throws ReaderException if the PDF417 Code cannot be decoded
|
||||||
t2 = System.currentTimeMillis();
|
*/
|
||||||
System.out.println("Elapsed time in ms - Reed Solomon " +(t2-t1));
|
public DecoderResult decode(BitMatrix bits) throws ReaderException {
|
||||||
}
|
// Construct a parser to read the data codewords and error-correction level
|
||||||
verifyCodewordCount(codewords, numECCodewords);
|
BitMatrixParser parser = new BitMatrixParser(bits);
|
||||||
|
int[] codewords = parser.readCodewords();
|
||||||
t1 = System.currentTimeMillis();
|
if (codewords == null || codewords.length == 0) {
|
||||||
DecoderResult dr = DecodedBitStreamParser.decode(codewords);
|
throw ReaderException.getInstance();
|
||||||
if (debug) {
|
}
|
||||||
t2 = System.currentTimeMillis();
|
|
||||||
System.out.println("Elapsed time in ms - DecodeBitStreamParser " +(t2-t1));
|
|
||||||
}
|
|
||||||
// Decode the codewords
|
|
||||||
return dr;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
int ecLevel = parser.getECLevel();
|
||||||
* Verify that all is OK with the codeword array.
|
int numECCodewords = 1 << (ecLevel + 1);
|
||||||
* @param codewords
|
int[] erasures = parser.getErasures();
|
||||||
* @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
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
correctErrors(codewords, erasures, numECCodewords);
|
||||||
* <p>Given data and error-correction codewords received, possibly corrupted by errors, attempts to
|
verifyCodewordCount(codewords, numECCodewords);
|
||||||
* correct the errors in-place using Reed-Solomon error correction.</p>
|
|
||||||
*
|
// Decode the codewords
|
||||||
* @param codewordBytes data and error correction codewords
|
return DecodedBitStreamParser.decode(codewords);
|
||||||
* @param numDataCodewords number of codewords that are data bytes
|
}
|
||||||
* @throws ReaderException if error correction fails
|
|
||||||
*/
|
/**
|
||||||
private int correctErrors(int[] codewords, int[] erasures, int numECCodewords) throws ReaderException {
|
* Verify that all is OK with the codeword array.
|
||||||
if ((erasures != null && erasures.length > numECCodewords/2 + MAX_ERRORS) ||
|
*
|
||||||
(numECCodewords < 0 || numECCodewords > MAX_EC_CODEWORDS)) {
|
* @param codewords
|
||||||
// Too many errors or EC Codewords is corrupted
|
* @return an index to the first data codeword.
|
||||||
throw ReaderException.getInstance();
|
* @throws ReaderException
|
||||||
}
|
*/
|
||||||
// Try to correct the errors
|
private static int verifyCodewordCount(int[] codewords, int numECCodewords) throws ReaderException {
|
||||||
int result = 0; // rsDecoder.correctErrors(codewords, numECCodewords);
|
if (codewords.length < 4) {
|
||||||
if (debug) {
|
// Codeword array size should be at least 4 allowing for
|
||||||
System.out.println("Corrected errors: " + result);
|
// Count CW, At least one Data CW, Error Correction CW, Error Correction CW
|
||||||
}
|
throw ReaderException.getInstance();
|
||||||
if (erasures != null) {
|
}
|
||||||
int numErasures = erasures.length;
|
// The first codeword, the Symbol Length Descriptor, shall always encode the total number of data
|
||||||
if (result > 0) {
|
// codewords in the symbol, including the Symbol Length Descriptor itself, data codewords and pad
|
||||||
numErasures = numErasures - result;
|
// codewords, but excluding the number of error correction codewords.
|
||||||
}
|
int numberOfCodewords = codewords[0];
|
||||||
if (numErasures > MAX_ERRORS) {
|
if (numberOfCodewords > codewords.length) {
|
||||||
// Still too many errors
|
throw ReaderException.getInstance();
|
||||||
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)
|
||||||
return result;
|
if (numECCodewords < codewords.length) {
|
||||||
|
codewords[0] = codewords.length - numECCodewords;
|
||||||
|
} else {
|
||||||
|
throw ReaderException.getInstance();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 1; // Index to first data codeword
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,527 +25,446 @@ 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
|
||||||
* PDF417 Code is rotated or skewed, or partially obscured.
|
* PDF417 Code is rotated or skewed, or partially obscured.
|
||||||
* </p>
|
* </p>
|
||||||
*
|
*
|
||||||
* @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;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue