package com.google.zxing.qrcode.detector;
-import com.google.zxing.BlackPointEstimationMethod;
-import com.google.zxing.MonochromeBitmapSource;
+import com.google.zxing.DecodeHintType;
import com.google.zxing.ReaderException;
import com.google.zxing.ResultPoint;
+import com.google.zxing.ResultPointCallback;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.common.DetectorResult;
import com.google.zxing.common.GridSampler;
* <p>Encapsulates logic that can detect a QR Code in an image, even if the QR Code
* is rotated or skewed, or partially obscured.</p>
*
- * @author srowen@google.com (Sean Owen)
+ * @author Sean Owen
*/
-public final class Detector {
+public class Detector {
- private final MonochromeBitmapSource image;
+ private final BitMatrix image;
+ private ResultPointCallback resultPointCallback;
- public Detector(MonochromeBitmapSource image) {
+ public Detector(BitMatrix image) {
this.image = image;
}
+ protected BitMatrix getImage() {
+ return image;
+ }
+
/**
* <p>Detects a QR Code in an image, simply.</p>
*
*/
public DetectorResult detect(Hashtable hints) throws ReaderException {
- MonochromeBitmapSource image = this.image;
- if (!BlackPointEstimationMethod.TWO_D_SAMPLING.equals(image.getLastEstimationMethod())) {
- image.estimateBlackPoint(BlackPointEstimationMethod.TWO_D_SAMPLING, 0);
- }
+ resultPointCallback = hints == null ? null :
+ (ResultPointCallback) hints.get(DecodeHintType.NEED_RESULT_POINT_CALLBACK);
- FinderPatternFinder finder = new FinderPatternFinder(image);
+ FinderPatternFinder finder = new FinderPatternFinder(image, resultPointCallback);
FinderPatternInfo info = finder.find(hints);
+ return processFinderPatternInfo(info);
+ }
+
+ protected DetectorResult processFinderPatternInfo(FinderPatternInfo info) throws ReaderException {
+
FinderPattern topLeft = info.getTopLeft();
FinderPattern topRight = info.getTopRight();
FinderPattern bottomLeft = info.getBottomLeft();
float moduleSize = calculateModuleSize(topLeft, topRight, bottomLeft);
+ if (moduleSize < 1.0f) {
+ throw ReaderException.getInstance();
+ }
int dimension = computeDimension(topLeft, topRight, bottomLeft, moduleSize);
Version provisionalVersion = Version.getProvisionalVersionForDimension(dimension);
int modulesBetweenFPCenters = provisionalVersion.getDimensionForVersion() - 7;
// try next round
}
}
- if (alignmentPattern == null) {
- throw new ReaderException("Could not find alignment pattern");
- }
-
+ // If we didn't find alignment pattern... well try anyway without it
}
BitMatrix bits = sampleGrid(image, topLeft, topRight, bottomLeft, alignmentPattern, dimension);
return new DetectorResult(bits, points);
}
- private static BitMatrix sampleGrid(MonochromeBitmapSource image,
+ private static BitMatrix sampleGrid(BitMatrix image,
ResultPoint topLeft,
ResultPoint topRight,
ResultPoint bottomLeft,
ResultPoint topRight,
ResultPoint bottomLeft,
float moduleSize) throws ReaderException {
- int tltrCentersDimension = round(FinderPatternFinder.distance(topLeft, topRight) / moduleSize);
- int tlblCentersDimension = round(FinderPatternFinder.distance(topLeft, bottomLeft) / moduleSize);
+ int tltrCentersDimension = round(ResultPoint.distance(topLeft, topRight) / moduleSize);
+ int tlblCentersDimension = round(ResultPoint.distance(topLeft, bottomLeft) / moduleSize);
int dimension = ((tltrCentersDimension + tlblCentersDimension) >> 1) + 7;
switch (dimension & 0x03) { // mod 4
case 0:
dimension--;
break;
case 3:
- throw new ReaderException("Bad dimension: " + dimension);
+ throw ReaderException.getInstance();
}
return dimension;
}
* <p>Computes an average estimated module size based on estimated derived from the positions
* of the three finder patterns.</p>
*/
- private float calculateModuleSize(ResultPoint topLeft, ResultPoint topRight, ResultPoint bottomLeft) {
+ private float calculateModuleSize(ResultPoint topLeft, ResultPoint topRight,
+ ResultPoint bottomLeft) {
// Take the average
return (calculateModuleSizeOneWay(topLeft, topRight) +
calculateModuleSizeOneWay(topLeft, bottomLeft)) / 2.0f;
int realX = steep ? y : x;
int realY = steep ? x : y;
if (state == 1) { // In white pixels, looking for black
- if (image.isBlack(realX, realY)) {
+ if (image.get(realX, realY)) {
state++;
}
} else {
- if (!image.isBlack(realX, realY)) {
+ if (!image.get(realX, realY)) {
state++;
}
}
* @param overallEstModuleSize estimated module size so far
* @param estAlignmentX x coordinate of center of area probably containing alignment pattern
* @param estAlignmentY y coordinate of above
- * @param allowanceFactor number of pixels in all directons to search from the center
+ * @param allowanceFactor number of pixels in all directions to search from the center
* @return {@link AlignmentPattern} if found, or null otherwise
* @throws ReaderException if an unexpected error occurs during detection
*/
int allowance = (int) (allowanceFactor * overallEstModuleSize);
int alignmentAreaLeftX = Math.max(0, estAlignmentX - allowance);
int alignmentAreaRightX = Math.min(image.getWidth() - 1, estAlignmentX + allowance);
+ if (alignmentAreaRightX - alignmentAreaLeftX < overallEstModuleSize * 3) {
+ throw ReaderException.getInstance();
+ }
+
int alignmentAreaTopY = Math.max(0, estAlignmentY - allowance);
int alignmentAreaBottomY = Math.min(image.getHeight() - 1, estAlignmentY + allowance);
alignmentAreaTopY,
alignmentAreaRightX - alignmentAreaLeftX,
alignmentAreaBottomY - alignmentAreaTopY,
- overallEstModuleSize);
+ overallEstModuleSize,
+ resultPointCallback);
return alignmentFinder.find();
}