import android.graphics.Bitmap;
import com.google.zxing.BlackPointEstimationMethod;
import com.google.zxing.MonochromeBitmapSource;
+import com.google.zxing.ReaderException;
import com.google.zxing.common.BitArray;
import com.google.zxing.common.BlackPointEstimator;
return image.width();
}
- public void estimateBlackPoint(BlackPointEstimationMethod method, int argument) {
+ public void estimateBlackPoint(BlackPointEstimationMethod method, int argument) throws ReaderException {
if (!method.equals(lastMethod) || argument != lastArgument) {
int width = image.width();
int height = image.height();
import android.graphics.Bitmap;
import com.google.zxing.BlackPointEstimationMethod;
import com.google.zxing.MonochromeBitmapSource;
+import com.google.zxing.ReaderException;
import com.google.zxing.common.BitArray;
import com.google.zxing.common.BlackPointEstimator;
return image.width();
}
- public void estimateBlackPoint(BlackPointEstimationMethod method, int argument) {
+ public void estimateBlackPoint(BlackPointEstimationMethod method, int argument) throws ReaderException {
if (!method.equals(lastMethod) || argument != lastArgument) {
int width = image.width();
int height = image.height();
\r
package com.google.zxing.common;\r
\r
+import com.google.zxing.ReaderException;\r
+\r
/**\r
* <p>Encapsulates logic that estimates the optimal "black point", the luminance value\r
* which is the best line between "white" and "black" in a grayscale image.</p>\r
* than 0.0; 1.0 is a good "default"\r
* @return index within argument of bucket corresponding to brightest values which should be\r
* considered "black"\r
+ * @throws ReaderException if "black" and "white" appear to be very close in luminance in the image\r
*/\r
- public static int estimate(int[] histogram, float biasTowardsWhite) {\r
+ public static int estimate(int[] histogram, float biasTowardsWhite) throws ReaderException{\r
\r
if (Float.isNaN(biasTowardsWhite) || biasTowardsWhite <= 0.0f) {\r
throw new IllegalArgumentException("Illegal biasTowardsWhite: " + biasTowardsWhite);\r
secondPeak = temp;\r
}\r
\r
+ // Kind of aribtrary; if the two peaks are very close, then we figure there is so little\r
+ // dynamic range in the image, that discriminating black and white is too error-prone.\r
+ // Decoding the image/line is either pointless, or may in some cases lead to a false positive\r
+ // for 1D formats, which are relatively lenient.\r
+ // We arbitrarily say "close" is "fewer than 1/8 of the total histogram buckets apart"\r
+ if (secondPeak - firstPeak < histogram.length >> 3) {\r
+ throw new ReaderException("Too little dynamic range in luminance");\r
+ }\r
+\r
// Find a valley between them that is low and closer to the white peak\r
int bestValley = secondPeak - 1;\r
int bestValleyScore = -1;\r
// the middle. So we'd scan row middle, then middle - rowStep, then middle + rowStep,
// then middle - 2*rowStep, etc.
// rowStep is bigger as the image is taller, but is always at least 1. We've somewhat arbitrarily decided
- // that moving up and down by about 1/16 of the image is pretty good.
+ // that moving up and down by about 1/16 of the image is pretty good; we try more of the image if
+ // "trying harder"
int middle = height >> 1;
- int rowStep;
- if (tryHarder) {
- rowStep = 2; // Look at every other line if "trying harder"
- } else {
- rowStep = Math.max(1, height >> 4);
- }
+ int rowStep = Math.max(1, height >> (tryHarder ? 7 : 4));
int maxLines;
if (tryHarder || barcodesToSkip > 0) {
maxLines = height; // Look at the whole image; looking for more than one barcode
} else {
maxLines = 7;
}
+
+ Result lastResult = null;
+
for (int x = 0; x < maxLines; x++) {
int rowStepsAboveOrBelow = (x + 1) >> 1;
break;
}
- image.estimateBlackPoint(BlackPointEstimationMethod.ROW_SAMPLING, rowNumber);
+ try {
+ image.estimateBlackPoint(BlackPointEstimationMethod.ROW_SAMPLING, rowNumber);
+ } catch (ReaderException re) {
+ continue;
+ }
image.getBlackRow(rowNumber, row, 0, width);
- try {
- Result result = decodeRow(rowNumber, row, hints);
- if (barcodesToSkip > 0) { // See if we should skip and keep looking
- barcodesToSkip--;
- } else {
- return result;
+ for (int attempt = 0; attempt < 2; attempt++) {
+ if (attempt == 1) { // trying again?
+ if (tryHarder) { // only if "trying harder"
+ row.reverse(); // reverse the row and continue
+ } else {
+ break;
+ }
}
- } catch (ReaderException re) {
- if (tryHarder) {
- row.reverse(); // try scanning the row backwards
- try {
- Result result = decodeRow(rowNumber, row, hints);
+ try {
+ Result result = decodeRow(rowNumber, row, hints);
+ if (lastResult == null || !lastResult.getText().equals(result.getText())) {
+ // Found new barcode, not just the last one again
if (barcodesToSkip > 0) { // See if we should skip and keep looking
barcodesToSkip--;
+ lastResult = result; // Remember what we just saw
} else {
- // Found it, but upside-down:
- result.putMetadata(ResultMetadataType.ORIENTATION, new Integer(180));
+ if (attempt == 1) {
+ // Found it, but upside-down:
+ result.putMetadata(ResultMetadataType.ORIENTATION, new Integer(180));
+ }
return result;
}
- } catch (ReaderException re2) {
- // continue
}
+ } catch (ReaderException re) {
+ // continue
}
}
-
}
throw new ReaderException("No barcode found");
import com.google.zxing.BlackPointEstimationMethod;
import com.google.zxing.MonochromeBitmapSource;
+import com.google.zxing.ReaderException;
import com.google.zxing.common.BitArray;
import com.google.zxing.common.BlackPointEstimator;
return width;
}
- public void estimateBlackPoint(BlackPointEstimationMethod method, int argument) {
+ public void estimateBlackPoint(BlackPointEstimationMethod method, int argument) throws ReaderException {
if (!method.equals(lastMethod) || argument != lastArgument) {
int[] histogram = new int[LUMINANCE_BUCKETS];
float biasTowardsWhite = 1.0f;
import com.google.zxing.BlackPointEstimationMethod;
import com.google.zxing.MonochromeBitmapSource;
+import com.google.zxing.ReaderException;
import com.google.zxing.common.BitArray;
import com.google.zxing.common.BlackPointEstimator;
lastArgument = 0;
}
+ public BufferedImage getImage() {
+ return image;
+ }
+
public boolean isBlack(int x, int y) {
return computeRGBLuminance(image.getRGB(x, y)) < blackPoint;
}
return image.getWidth();
}
- public void estimateBlackPoint(BlackPointEstimationMethod method, int argument) {
+ public void estimateBlackPoint(BlackPointEstimationMethod method, int argument) throws ReaderException {
if (!method.equals(lastMethod) || argument != lastArgument) {
int width = image.getWidth();
int height = image.getHeight();
throw new IllegalStateException("Rotate not supported");
}
// 90 degrees counterclockwise:
- AffineTransform transform = new AffineTransform(0.0, -1.0, 1.0, 0.0, 0.0, image.getHeight());
+ AffineTransform transform = new AffineTransform(0.0, -1.0, 1.0, 0.0, 0.0, image.getWidth());
BufferedImageOp op = new AffineTransformOp(transform, AffineTransformOp.TYPE_NEAREST_NEIGHBOR);
+ // Note width/height are flipped since we are rotating 90 degrees:
BufferedImage rotatedImage = new BufferedImage(image.getHeight(), image.getWidth(), image.getType());
op.filter(image, rotatedImage);
return new BufferedImageMonochromeBitmapSource(rotatedImage);