mirror of
https://github.com/zxing/zxing.git
synced 2025-03-05 20:48:51 -08:00
Draft of 'thinking' visualization for barcode scanning. Works for 1D and QR codes.
git-svn-id: https://zxing.googlecode.com/svn/trunk@1125 59b500cc-1b3d-0410-9834-0bbf25fbcc57
This commit is contained in:
parent
aee98771a2
commit
d1973dce0a
|
@ -19,6 +19,7 @@
|
||||||
<color name="encode_view">#ffffffff</color>
|
<color name="encode_view">#ffffffff</color>
|
||||||
<color name="help_button_view">#ffcccccc</color>
|
<color name="help_button_view">#ffcccccc</color>
|
||||||
<color name="help_view">#ff404040</color>
|
<color name="help_view">#ff404040</color>
|
||||||
|
<color name="possible_result_points">#c0ffff00</color>
|
||||||
<color name="result_image_border">#ffffffff</color>
|
<color name="result_image_border">#ffffffff</color>
|
||||||
<color name="result_minor_text">#ffc0c0c0</color>
|
<color name="result_minor_text">#ffc0c0c0</color>
|
||||||
<color name="result_points">#c000ff00</color>
|
<color name="result_points">#c000ff00</color>
|
||||||
|
|
|
@ -125,6 +125,10 @@ public final class CaptureActivity extends Activity implements SurfaceHolder.Cal
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
ViewfinderView getViewfinderView() {
|
||||||
|
return viewfinderView;
|
||||||
|
}
|
||||||
|
|
||||||
public Handler getHandler() {
|
public Handler getHandler() {
|
||||||
return handler;
|
return handler;
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,10 +42,12 @@ public final class CaptureActivityHandler extends Handler {
|
||||||
DONE
|
DONE
|
||||||
}
|
}
|
||||||
|
|
||||||
CaptureActivityHandler(CaptureActivity activity, String decodeMode,
|
CaptureActivityHandler(CaptureActivity activity,
|
||||||
boolean beginScanning) {
|
String decodeMode,
|
||||||
|
boolean beginScanning) {
|
||||||
this.activity = activity;
|
this.activity = activity;
|
||||||
decodeThread = new DecodeThread(activity, decodeMode);
|
decodeThread = new DecodeThread(activity, decodeMode,
|
||||||
|
new ViewfinderResultPointCallback(activity.getViewfinderView()));
|
||||||
decodeThread.start();
|
decodeThread.start();
|
||||||
state = State.SUCCESS;
|
state = State.SUCCESS;
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,7 @@ import com.google.zxing.DecodeHintType;
|
||||||
import com.google.zxing.MultiFormatReader;
|
import com.google.zxing.MultiFormatReader;
|
||||||
import com.google.zxing.ReaderException;
|
import com.google.zxing.ReaderException;
|
||||||
import com.google.zxing.Result;
|
import com.google.zxing.Result;
|
||||||
|
import com.google.zxing.ResultPointCallback;
|
||||||
import com.google.zxing.common.GlobalHistogramBinarizer;
|
import com.google.zxing.common.GlobalHistogramBinarizer;
|
||||||
|
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
|
@ -47,10 +48,12 @@ final class DecodeThread extends Thread {
|
||||||
private Handler handler;
|
private Handler handler;
|
||||||
private final CaptureActivity activity;
|
private final CaptureActivity activity;
|
||||||
private final MultiFormatReader multiFormatReader;
|
private final MultiFormatReader multiFormatReader;
|
||||||
|
private final ResultPointCallback resultPointCallback;
|
||||||
|
|
||||||
DecodeThread(CaptureActivity activity, String mode) {
|
DecodeThread(CaptureActivity activity, String mode, ResultPointCallback resultPointCallback) {
|
||||||
this.activity = activity;
|
this.activity = activity;
|
||||||
multiFormatReader = new MultiFormatReader();
|
multiFormatReader = new MultiFormatReader();
|
||||||
|
this.resultPointCallback = resultPointCallback;
|
||||||
|
|
||||||
// The prefs can't change while the thread is running, so pick them up once here.
|
// The prefs can't change while the thread is running, so pick them up once here.
|
||||||
if (mode == null || mode.length() == 0) {
|
if (mode == null || mode.length() == 0) {
|
||||||
|
@ -101,39 +104,27 @@ final class DecodeThread extends Thread {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setDecodeProductMode() {
|
private void setDecodeProductMode() {
|
||||||
Hashtable<DecodeHintType, Object> hints = new Hashtable<DecodeHintType, Object>(3);
|
doSetDecodeMode(BarcodeFormat.UPC_A,
|
||||||
Vector<BarcodeFormat> vector = new Vector<BarcodeFormat>(4);
|
BarcodeFormat.UPC_E,
|
||||||
vector.addElement(BarcodeFormat.UPC_A);
|
BarcodeFormat.EAN_13,
|
||||||
vector.addElement(BarcodeFormat.UPC_E);
|
BarcodeFormat.EAN_8);
|
||||||
vector.addElement(BarcodeFormat.EAN_13);
|
|
||||||
vector.addElement(BarcodeFormat.EAN_8);
|
|
||||||
hints.put(DecodeHintType.POSSIBLE_FORMATS, vector);
|
|
||||||
multiFormatReader.setHints(hints);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Select the 1D formats we want this client to decode by hand.
|
* Select the 1D formats we want this client to decode by hand.
|
||||||
*/
|
*/
|
||||||
private void setDecode1DMode() {
|
private void setDecode1DMode() {
|
||||||
Hashtable<DecodeHintType, Object> hints = new Hashtable<DecodeHintType, Object>(3);
|
doSetDecodeMode(BarcodeFormat.UPC_A,
|
||||||
Vector<BarcodeFormat> vector = new Vector<BarcodeFormat>(7);
|
BarcodeFormat.UPC_E,
|
||||||
vector.addElement(BarcodeFormat.UPC_A);
|
BarcodeFormat.EAN_13,
|
||||||
vector.addElement(BarcodeFormat.UPC_E);
|
BarcodeFormat.EAN_8,
|
||||||
vector.addElement(BarcodeFormat.EAN_13);
|
BarcodeFormat.CODE_39,
|
||||||
vector.addElement(BarcodeFormat.EAN_8);
|
BarcodeFormat.CODE_128,
|
||||||
vector.addElement(BarcodeFormat.CODE_39);
|
BarcodeFormat.ITF);
|
||||||
vector.addElement(BarcodeFormat.CODE_128);
|
|
||||||
vector.addElement(BarcodeFormat.ITF);
|
|
||||||
hints.put(DecodeHintType.POSSIBLE_FORMATS, vector);
|
|
||||||
multiFormatReader.setHints(hints);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setDecodeQRMode() {
|
private void setDecodeQRMode() {
|
||||||
Hashtable<DecodeHintType, Object> hints = new Hashtable<DecodeHintType, Object>(3);
|
doSetDecodeMode(BarcodeFormat.QR_CODE);
|
||||||
Vector<BarcodeFormat> vector = new Vector<BarcodeFormat>(1);
|
|
||||||
vector.addElement(BarcodeFormat.QR_CODE);
|
|
||||||
hints.put(DecodeHintType.POSSIBLE_FORMATS, vector);
|
|
||||||
multiFormatReader.setHints(hints);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -141,17 +132,24 @@ final class DecodeThread extends Thread {
|
||||||
* explicitly set which formats are available.
|
* explicitly set which formats are available.
|
||||||
*/
|
*/
|
||||||
private void setDecodeAllMode() {
|
private void setDecodeAllMode() {
|
||||||
|
doSetDecodeMode(BarcodeFormat.UPC_A,
|
||||||
|
BarcodeFormat.UPC_E,
|
||||||
|
BarcodeFormat.EAN_13,
|
||||||
|
BarcodeFormat.EAN_8,
|
||||||
|
BarcodeFormat.CODE_39,
|
||||||
|
BarcodeFormat.CODE_128,
|
||||||
|
BarcodeFormat.ITF,
|
||||||
|
BarcodeFormat.QR_CODE);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void doSetDecodeMode(BarcodeFormat... formats) {
|
||||||
Hashtable<DecodeHintType, Object> hints = new Hashtable<DecodeHintType, Object>(3);
|
Hashtable<DecodeHintType, Object> hints = new Hashtable<DecodeHintType, Object>(3);
|
||||||
Vector<BarcodeFormat> vector = new Vector<BarcodeFormat>(8);
|
Vector<BarcodeFormat> vector = new Vector<BarcodeFormat>(formats.length);
|
||||||
vector.addElement(BarcodeFormat.UPC_A);
|
for (BarcodeFormat format : formats) {
|
||||||
vector.addElement(BarcodeFormat.UPC_E);
|
vector.addElement(format);
|
||||||
vector.addElement(BarcodeFormat.EAN_13);
|
}
|
||||||
vector.addElement(BarcodeFormat.EAN_8);
|
|
||||||
vector.addElement(BarcodeFormat.CODE_39);
|
|
||||||
vector.addElement(BarcodeFormat.CODE_128);
|
|
||||||
vector.addElement(BarcodeFormat.ITF);
|
|
||||||
vector.addElement(BarcodeFormat.QR_CODE);
|
|
||||||
hints.put(DecodeHintType.POSSIBLE_FORMATS, vector);
|
hints.put(DecodeHintType.POSSIBLE_FORMATS, vector);
|
||||||
|
hints.put(DecodeHintType.NEED_RESULT_POINT_CALLBACK, resultPointCallback);
|
||||||
multiFormatReader.setHints(hints);
|
multiFormatReader.setHints(hints);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,34 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 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.client.android;
|
||||||
|
|
||||||
|
import com.google.zxing.ResultPoint;
|
||||||
|
import com.google.zxing.ResultPointCallback;
|
||||||
|
|
||||||
|
final class ViewfinderResultPointCallback implements ResultPointCallback {
|
||||||
|
|
||||||
|
private final ViewfinderView viewfinderView;
|
||||||
|
|
||||||
|
ViewfinderResultPointCallback(ViewfinderView viewfinderView) {
|
||||||
|
this.viewfinderView = viewfinderView;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void foundPossibleResultPoint(ResultPoint point) {
|
||||||
|
viewfinderView.addPossibleResultPoint(point);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -24,6 +24,10 @@ import android.graphics.Paint;
|
||||||
import android.graphics.Rect;
|
import android.graphics.Rect;
|
||||||
import android.util.AttributeSet;
|
import android.util.AttributeSet;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
import com.google.zxing.ResultPoint;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.HashSet;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This view is overlaid on top of the camera preview. It adds the viewfinder rectangle and partial
|
* This view is overlaid on top of the camera preview. It adds the viewfinder rectangle and partial
|
||||||
|
@ -34,15 +38,18 @@ import android.view.View;
|
||||||
public final class ViewfinderView extends View {
|
public final class ViewfinderView extends View {
|
||||||
private static final int[] SCANNER_ALPHA = {0, 64, 128, 192, 255, 192, 128, 64};
|
private static final int[] SCANNER_ALPHA = {0, 64, 128, 192, 255, 192, 128, 64};
|
||||||
private static final long ANIMATION_DELAY = 100L;
|
private static final long ANIMATION_DELAY = 100L;
|
||||||
|
private static final int OPAQUE = 0xFF;
|
||||||
|
|
||||||
private final Paint paint;
|
private final Paint paint;
|
||||||
private final Rect box;
|
|
||||||
private Bitmap resultBitmap;
|
private Bitmap resultBitmap;
|
||||||
private final int maskColor;
|
private final int maskColor;
|
||||||
private final int resultColor;
|
private final int resultColor;
|
||||||
private final int frameColor;
|
private final int frameColor;
|
||||||
private final int laserColor;
|
private final int laserColor;
|
||||||
|
private final int resultPointColor;
|
||||||
private int scannerAlpha;
|
private int scannerAlpha;
|
||||||
|
private Collection<ResultPoint> possibleResultPoints;
|
||||||
|
private Collection<ResultPoint> lastPossibleResultPoints;
|
||||||
|
|
||||||
// This constructor is used when the class is built from an XML resource.
|
// This constructor is used when the class is built from an XML resource.
|
||||||
public ViewfinderView(Context context, AttributeSet attrs) {
|
public ViewfinderView(Context context, AttributeSet attrs) {
|
||||||
|
@ -50,13 +57,14 @@ public final class ViewfinderView extends View {
|
||||||
|
|
||||||
// Initialize these once for performance rather than calling them every time in onDraw().
|
// Initialize these once for performance rather than calling them every time in onDraw().
|
||||||
paint = new Paint();
|
paint = new Paint();
|
||||||
box = new Rect();
|
|
||||||
Resources resources = getResources();
|
Resources resources = getResources();
|
||||||
maskColor = resources.getColor(R.color.viewfinder_mask);
|
maskColor = resources.getColor(R.color.viewfinder_mask);
|
||||||
resultColor = resources.getColor(R.color.result_view);
|
resultColor = resources.getColor(R.color.result_view);
|
||||||
frameColor = resources.getColor(R.color.viewfinder_frame);
|
frameColor = resources.getColor(R.color.viewfinder_frame);
|
||||||
laserColor = resources.getColor(R.color.viewfinder_laser);
|
laserColor = resources.getColor(R.color.viewfinder_laser);
|
||||||
|
resultPointColor = resources.getColor(R.color.possible_result_points);
|
||||||
scannerAlpha = 0;
|
scannerAlpha = 0;
|
||||||
|
possibleResultPoints = new HashSet<ResultPoint>(5);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -70,42 +78,55 @@ public final class ViewfinderView extends View {
|
||||||
|
|
||||||
// Draw the exterior (i.e. outside the framing rect) darkened
|
// Draw the exterior (i.e. outside the framing rect) darkened
|
||||||
paint.setColor(resultBitmap != null ? resultColor : maskColor);
|
paint.setColor(resultBitmap != null ? resultColor : maskColor);
|
||||||
box.set(0, 0, width, frame.top);
|
canvas.drawRect(0, 0, width, frame.top, paint);
|
||||||
canvas.drawRect(box, paint);
|
canvas.drawRect(0, frame.top, frame.left, frame.bottom + 1, paint);
|
||||||
box.set(0, frame.top, frame.left, frame.bottom + 1);
|
canvas.drawRect(frame.right + 1, frame.top, width, frame.bottom + 1, paint);
|
||||||
canvas.drawRect(box, paint);
|
canvas.drawRect(0, frame.bottom + 1, width, height, paint);
|
||||||
box.set(frame.right + 1, frame.top, width, frame.bottom + 1);
|
|
||||||
canvas.drawRect(box, paint);
|
|
||||||
box.set(0, frame.bottom + 1, width, height);
|
|
||||||
canvas.drawRect(box, paint);
|
|
||||||
|
|
||||||
if (resultBitmap != null) {
|
if (resultBitmap != null) {
|
||||||
// Draw the opaque result bitmap over the scanning rectangle
|
// Draw the opaque result bitmap over the scanning rectangle
|
||||||
paint.setAlpha(255);
|
paint.setAlpha(OPAQUE);
|
||||||
canvas.drawBitmap(resultBitmap, frame.left, frame.top, paint);
|
canvas.drawBitmap(resultBitmap, frame.left, frame.top, paint);
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
// Draw a two pixel solid black border inside the framing rect
|
// Draw a two pixel solid black border inside the framing rect
|
||||||
paint.setColor(frameColor);
|
paint.setColor(frameColor);
|
||||||
box.set(frame.left, frame.top, frame.right + 1, frame.top + 2);
|
canvas.drawRect(frame.left, frame.top, frame.right + 1, frame.top + 2, paint);
|
||||||
canvas.drawRect(box, paint);
|
canvas.drawRect(frame.left, frame.top + 2, frame.left + 2, frame.bottom - 1, paint);
|
||||||
box.set(frame.left, frame.top + 2, frame.left + 2, frame.bottom - 1);
|
canvas.drawRect(frame.right - 1, frame.top, frame.right + 1, frame.bottom - 1, paint);
|
||||||
canvas.drawRect(box, paint);
|
canvas.drawRect(frame.left, frame.bottom - 1, frame.right + 1, frame.bottom + 1, paint);
|
||||||
box.set(frame.right - 1, frame.top, frame.right + 1, frame.bottom - 1);
|
|
||||||
canvas.drawRect(box, paint);
|
|
||||||
box.set(frame.left, frame.bottom - 1, frame.right + 1, frame.bottom + 1);
|
|
||||||
canvas.drawRect(box, paint);
|
|
||||||
|
|
||||||
// Draw a red "laser scanner" line through the middle to show decoding is active
|
// Draw a red "laser scanner" line through the middle to show decoding is active
|
||||||
paint.setColor(laserColor);
|
paint.setColor(laserColor);
|
||||||
paint.setAlpha(SCANNER_ALPHA[scannerAlpha]);
|
paint.setAlpha(SCANNER_ALPHA[scannerAlpha]);
|
||||||
scannerAlpha = (scannerAlpha + 1) % SCANNER_ALPHA.length;
|
scannerAlpha = (scannerAlpha + 1) % SCANNER_ALPHA.length;
|
||||||
int middle = frame.height() / 2 + frame.top;
|
int middle = frame.height() / 2 + frame.top;
|
||||||
box.set(frame.left + 2, middle - 1, frame.right - 1, middle + 2);
|
canvas.drawRect(frame.left + 2, middle - 1, frame.right - 1, middle + 2, paint);
|
||||||
canvas.drawRect(box, paint);
|
|
||||||
|
Collection<ResultPoint> currentPossible = possibleResultPoints;
|
||||||
|
Collection<ResultPoint> currentLast = lastPossibleResultPoints;
|
||||||
|
if (currentPossible.isEmpty()) {
|
||||||
|
lastPossibleResultPoints = null;
|
||||||
|
} else {
|
||||||
|
possibleResultPoints = new HashSet<ResultPoint>(5);
|
||||||
|
lastPossibleResultPoints = currentPossible;
|
||||||
|
paint.setAlpha(OPAQUE);
|
||||||
|
paint.setColor(resultPointColor);
|
||||||
|
for (ResultPoint point : currentPossible) {
|
||||||
|
canvas.drawCircle(frame.left + point.getX(), frame.top + point.getY(), 6.0f, paint);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (currentLast != null) {
|
||||||
|
paint.setAlpha(OPAQUE / 2);
|
||||||
|
paint.setColor(resultPointColor);
|
||||||
|
for (ResultPoint point : currentLast) {
|
||||||
|
canvas.drawCircle(frame.left + point.getX(), frame.top + point.getY(), 3.0f, paint);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Request another update at the animation interval, but only repaint the laser line,
|
// Request another update at the animation interval, but only repaint the laser line,
|
||||||
// not the entire viewfinder mask.
|
// not the entire viewfinder mask.
|
||||||
postInvalidateDelayed(ANIMATION_DELAY, box.left, box.top, box.right, box.bottom);
|
postInvalidateDelayed(ANIMATION_DELAY, frame.left, frame.top, frame.right, frame.bottom);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -123,4 +144,9 @@ public final class ViewfinderView extends View {
|
||||||
resultBitmap = barcode;
|
resultBitmap = barcode;
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void addPossibleResultPoint(ResultPoint point) {
|
||||||
|
possibleResultPoints.add(point);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -62,6 +62,12 @@ public final class DecodeHintType {
|
||||||
*/
|
*/
|
||||||
public static final DecodeHintType ASSUME_CODE_39_CHECK_DIGIT = new DecodeHintType();
|
public static final DecodeHintType ASSUME_CODE_39_CHECK_DIGIT = new DecodeHintType();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The caller needs to be notified via callback when a possible {@link ResultPoint}
|
||||||
|
* is found. Maps to a {@link ResultPointCallback}.
|
||||||
|
*/
|
||||||
|
public static final DecodeHintType NEED_RESULT_POINT_CALLBACK = new DecodeHintType();
|
||||||
|
|
||||||
private DecodeHintType() {
|
private DecodeHintType() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
29
core/src/com/google/zxing/ResultPointCallback.java
Normal file
29
core/src/com/google/zxing/ResultPointCallback.java
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback which is invoked when a possible result point (significant
|
||||||
|
* point in the barcode image such as a corner) is found.
|
||||||
|
*
|
||||||
|
* @see DecodeHintType#NEED_RESULT_POINT_CALLBACK
|
||||||
|
*/
|
||||||
|
public interface ResultPointCallback {
|
||||||
|
|
||||||
|
void foundPossibleResultPoint(ResultPoint point);
|
||||||
|
|
||||||
|
}
|
|
@ -19,6 +19,7 @@ package com.google.zxing.multi.qrcode.detector;
|
||||||
import com.google.zxing.DecodeHintType;
|
import com.google.zxing.DecodeHintType;
|
||||||
import com.google.zxing.ReaderException;
|
import com.google.zxing.ReaderException;
|
||||||
import com.google.zxing.ResultPoint;
|
import com.google.zxing.ResultPoint;
|
||||||
|
import com.google.zxing.ResultPointCallback;
|
||||||
import com.google.zxing.common.Collections;
|
import com.google.zxing.common.Collections;
|
||||||
import com.google.zxing.common.Comparator;
|
import com.google.zxing.common.Comparator;
|
||||||
import com.google.zxing.common.BitMatrix;
|
import com.google.zxing.common.BitMatrix;
|
||||||
|
@ -90,6 +91,10 @@ final class MultiFinderPatternFinder extends FinderPatternFinder {
|
||||||
super(image);
|
super(image);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MultiFinderPatternFinder(BitMatrix image, ResultPointCallback resultPointCallback) {
|
||||||
|
super(image, resultPointCallback);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the 3 best {@link FinderPattern}s from our list of candidates. The "best" are
|
* @return the 3 best {@link FinderPattern}s from our list of candidates. The "best" are
|
||||||
* those that have been detected at least {@link #CENTER_QUORUM} times, and whose module
|
* those that have been detected at least {@link #CENTER_QUORUM} times, and whose module
|
||||||
|
|
|
@ -118,6 +118,14 @@ public abstract class AbstractOneDReader implements OneDReader {
|
||||||
for (int attempt = 0; attempt < 2; attempt++) {
|
for (int attempt = 0; attempt < 2; attempt++) {
|
||||||
if (attempt == 1) { // trying again?
|
if (attempt == 1) { // trying again?
|
||||||
row.reverse(); // reverse the row and continue
|
row.reverse(); // reverse the row and continue
|
||||||
|
// This means we will only ever draw result points *once* in the life of this method
|
||||||
|
// since we want to avoid drawing the wrong points after flipping the row, and,
|
||||||
|
// don't want to clutter with noise from every single row scan -- just the scans
|
||||||
|
// that start on the center line.
|
||||||
|
if (hints != null && hints.containsKey(DecodeHintType.NEED_RESULT_POINT_CALLBACK)) {
|
||||||
|
hints = (Hashtable) hints.clone();
|
||||||
|
hints.remove(DecodeHintType.NEED_RESULT_POINT_CALLBACK);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
// Look for a barcode
|
// Look for a barcode
|
||||||
|
|
|
@ -17,9 +17,11 @@
|
||||||
package com.google.zxing.oned;
|
package com.google.zxing.oned;
|
||||||
|
|
||||||
import com.google.zxing.BarcodeFormat;
|
import com.google.zxing.BarcodeFormat;
|
||||||
|
import com.google.zxing.DecodeHintType;
|
||||||
import com.google.zxing.ReaderException;
|
import com.google.zxing.ReaderException;
|
||||||
import com.google.zxing.Result;
|
import com.google.zxing.Result;
|
||||||
import com.google.zxing.ResultPoint;
|
import com.google.zxing.ResultPoint;
|
||||||
|
import com.google.zxing.ResultPointCallback;
|
||||||
import com.google.zxing.common.BitArray;
|
import com.google.zxing.common.BitArray;
|
||||||
|
|
||||||
import java.util.Hashtable;
|
import java.util.Hashtable;
|
||||||
|
@ -110,16 +112,40 @@ public abstract class AbstractUPCEANReader extends AbstractOneDReader implements
|
||||||
|
|
||||||
public final Result decodeRow(int rowNumber, BitArray row, Hashtable hints)
|
public final Result decodeRow(int rowNumber, BitArray row, Hashtable hints)
|
||||||
throws ReaderException {
|
throws ReaderException {
|
||||||
return decodeRow(rowNumber, row, findStartGuardPattern(row));
|
return decodeRow(rowNumber, row, findStartGuardPattern(row), hints);
|
||||||
}
|
}
|
||||||
|
|
||||||
public final Result decodeRow(int rowNumber, BitArray row, int[] startGuardRange)
|
public final Result decodeRow(int rowNumber, BitArray row, int[] startGuardRange, Hashtable hints)
|
||||||
throws ReaderException {
|
throws ReaderException {
|
||||||
|
|
||||||
|
ResultPointCallback resultPointCallback = hints == null ? null :
|
||||||
|
(ResultPointCallback) hints.get(DecodeHintType.NEED_RESULT_POINT_CALLBACK);
|
||||||
|
|
||||||
|
if (resultPointCallback != null) {
|
||||||
|
resultPointCallback.foundPossibleResultPoint(new ResultPoint(
|
||||||
|
(startGuardRange[0] + startGuardRange[1]) / 2.0f, rowNumber
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
StringBuffer result = decodeRowStringBuffer;
|
StringBuffer result = decodeRowStringBuffer;
|
||||||
result.setLength(0);
|
result.setLength(0);
|
||||||
int endStart = decodeMiddle(row, startGuardRange, result);
|
int endStart = decodeMiddle(row, startGuardRange, result);
|
||||||
|
|
||||||
|
if (resultPointCallback != null) {
|
||||||
|
resultPointCallback.foundPossibleResultPoint(new ResultPoint(
|
||||||
|
endStart, rowNumber
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
int[] endRange = decodeEnd(row, endStart);
|
int[] endRange = decodeEnd(row, endStart);
|
||||||
|
|
||||||
|
if (resultPointCallback != null) {
|
||||||
|
resultPointCallback.foundPossibleResultPoint(new ResultPoint(
|
||||||
|
(endRange[0] + endRange[1]) / 2.0f, rowNumber
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// Make sure there is a quiet zone at least as big as the end pattern after the barcode. The
|
// Make sure there is a quiet zone at least as big as the end pattern after the barcode. The
|
||||||
// spec might want more whitespace, but in practice this is the maximum we can count on.
|
// spec might want more whitespace, but in practice this is the maximum we can count on.
|
||||||
int end = endRange[1];
|
int end = endRange[1];
|
||||||
|
|
|
@ -68,7 +68,7 @@ public final class MultiFormatUPCEANReader extends AbstractOneDReader {
|
||||||
UPCEANReader reader = (UPCEANReader) readers.elementAt(i);
|
UPCEANReader reader = (UPCEANReader) readers.elementAt(i);
|
||||||
Result result;
|
Result result;
|
||||||
try {
|
try {
|
||||||
result = reader.decodeRow(rowNumber, row, startGuardPattern);
|
result = reader.decodeRow(rowNumber, row, startGuardPattern, hints);
|
||||||
} catch (ReaderException re) {
|
} catch (ReaderException re) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,8 +34,9 @@ public final class UPCAReader implements UPCEANReader {
|
||||||
|
|
||||||
private final UPCEANReader ean13Reader = new EAN13Reader();
|
private final UPCEANReader ean13Reader = new EAN13Reader();
|
||||||
|
|
||||||
public Result decodeRow(int rowNumber, BitArray row, int[] startGuardRange) throws ReaderException {
|
public Result decodeRow(int rowNumber, BitArray row, int[] startGuardRange, Hashtable hints)
|
||||||
return maybeReturnResult(ean13Reader.decodeRow(rowNumber, row, startGuardRange));
|
throws ReaderException {
|
||||||
|
return maybeReturnResult(ean13Reader.decodeRow(rowNumber, row, startGuardRange, hints));
|
||||||
}
|
}
|
||||||
|
|
||||||
public Result decodeRow(int rowNumber, BitArray row, Hashtable hints) throws ReaderException {
|
public Result decodeRow(int rowNumber, BitArray row, Hashtable hints) throws ReaderException {
|
||||||
|
|
|
@ -20,6 +20,8 @@ import com.google.zxing.ReaderException;
|
||||||
import com.google.zxing.Result;
|
import com.google.zxing.Result;
|
||||||
import com.google.zxing.common.BitArray;
|
import com.google.zxing.common.BitArray;
|
||||||
|
|
||||||
|
import java.util.Hashtable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>This interfaces captures additional functionality that readers of
|
* <p>This interfaces captures additional functionality that readers of
|
||||||
* UPC/EAN family of barcodes should expose.</p>
|
* UPC/EAN family of barcodes should expose.</p>
|
||||||
|
@ -33,6 +35,7 @@ public interface UPCEANReader extends OneDReader {
|
||||||
* allows caller to inform method about where the UPC/EAN start pattern is
|
* allows caller to inform method about where the UPC/EAN start pattern is
|
||||||
* found. This allows this to be computed once and reused across many implementations.</p>
|
* found. This allows this to be computed once and reused across many implementations.</p>
|
||||||
*/
|
*/
|
||||||
Result decodeRow(int rowNumber, BitArray row, int[] startGuardRange) throws ReaderException;
|
Result decodeRow(int rowNumber, BitArray row, int[] startGuardRange, Hashtable hints)
|
||||||
|
throws ReaderException;
|
||||||
|
|
||||||
}
|
}
|
|
@ -17,6 +17,8 @@
|
||||||
package com.google.zxing.qrcode.detector;
|
package com.google.zxing.qrcode.detector;
|
||||||
|
|
||||||
import com.google.zxing.ReaderException;
|
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.BitMatrix;
|
||||||
|
|
||||||
import java.util.Vector;
|
import java.util.Vector;
|
||||||
|
@ -45,6 +47,7 @@ final class AlignmentPatternFinder {
|
||||||
private final int height;
|
private final int height;
|
||||||
private final float moduleSize;
|
private final float moduleSize;
|
||||||
private final int[] crossCheckStateCount;
|
private final int[] crossCheckStateCount;
|
||||||
|
private final ResultPointCallback resultPointCallback;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>Creates a finder that will look in a portion of the whole image.</p>
|
* <p>Creates a finder that will look in a portion of the whole image.</p>
|
||||||
|
@ -61,7 +64,8 @@ final class AlignmentPatternFinder {
|
||||||
int startY,
|
int startY,
|
||||||
int width,
|
int width,
|
||||||
int height,
|
int height,
|
||||||
float moduleSize) {
|
float moduleSize,
|
||||||
|
ResultPointCallback resultPointCallback) {
|
||||||
this.image = image;
|
this.image = image;
|
||||||
this.possibleCenters = new Vector(5);
|
this.possibleCenters = new Vector(5);
|
||||||
this.startX = startX;
|
this.startX = startX;
|
||||||
|
@ -70,6 +74,7 @@ final class AlignmentPatternFinder {
|
||||||
this.height = height;
|
this.height = height;
|
||||||
this.moduleSize = moduleSize;
|
this.moduleSize = moduleSize;
|
||||||
this.crossCheckStateCount = new int[3];
|
this.crossCheckStateCount = new int[3];
|
||||||
|
this.resultPointCallback = resultPointCallback;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -262,7 +267,11 @@ final class AlignmentPatternFinder {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Hadn't found this before; save it
|
// Hadn't found this before; save it
|
||||||
possibleCenters.addElement(new AlignmentPattern(centerJ, centerI, estimatedModuleSize));
|
ResultPoint point = new AlignmentPattern(centerJ, centerI, estimatedModuleSize);
|
||||||
|
possibleCenters.addElement(point);
|
||||||
|
if (resultPointCallback != null) {
|
||||||
|
resultPointCallback.foundPossibleResultPoint(point);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,8 +16,10 @@
|
||||||
|
|
||||||
package com.google.zxing.qrcode.detector;
|
package com.google.zxing.qrcode.detector;
|
||||||
|
|
||||||
|
import com.google.zxing.DecodeHintType;
|
||||||
import com.google.zxing.ReaderException;
|
import com.google.zxing.ReaderException;
|
||||||
import com.google.zxing.ResultPoint;
|
import com.google.zxing.ResultPoint;
|
||||||
|
import com.google.zxing.ResultPointCallback;
|
||||||
import com.google.zxing.common.BitMatrix;
|
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;
|
||||||
|
@ -34,6 +36,7 @@ import java.util.Hashtable;
|
||||||
public class Detector {
|
public class Detector {
|
||||||
|
|
||||||
private final BitMatrix image;
|
private final BitMatrix image;
|
||||||
|
private ResultPointCallback resultPointCallback;
|
||||||
|
|
||||||
public Detector(BitMatrix image) {
|
public Detector(BitMatrix image) {
|
||||||
this.image = image;
|
this.image = image;
|
||||||
|
@ -62,7 +65,10 @@ public class Detector {
|
||||||
*/
|
*/
|
||||||
public DetectorResult detect(Hashtable hints) throws ReaderException {
|
public DetectorResult detect(Hashtable hints) throws ReaderException {
|
||||||
|
|
||||||
FinderPatternFinder finder = new FinderPatternFinder(image);
|
resultPointCallback = hints == null ? null :
|
||||||
|
(ResultPointCallback) hints.get(DecodeHintType.NEED_RESULT_POINT_CALLBACK);
|
||||||
|
|
||||||
|
FinderPatternFinder finder = new FinderPatternFinder(image, resultPointCallback);
|
||||||
FinderPatternInfo info = finder.find(hints);
|
FinderPatternInfo info = finder.find(hints);
|
||||||
|
|
||||||
return processFinderPatternInfo(info);
|
return processFinderPatternInfo(info);
|
||||||
|
@ -347,7 +353,8 @@ public class Detector {
|
||||||
alignmentAreaTopY,
|
alignmentAreaTopY,
|
||||||
alignmentAreaRightX - alignmentAreaLeftX,
|
alignmentAreaRightX - alignmentAreaLeftX,
|
||||||
alignmentAreaBottomY - alignmentAreaTopY,
|
alignmentAreaBottomY - alignmentAreaTopY,
|
||||||
overallEstModuleSize);
|
overallEstModuleSize,
|
||||||
|
resultPointCallback);
|
||||||
return alignmentFinder.find();
|
return alignmentFinder.find();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,7 @@ package com.google.zxing.qrcode.detector;
|
||||||
import com.google.zxing.DecodeHintType;
|
import com.google.zxing.DecodeHintType;
|
||||||
import com.google.zxing.ReaderException;
|
import com.google.zxing.ReaderException;
|
||||||
import com.google.zxing.ResultPoint;
|
import com.google.zxing.ResultPoint;
|
||||||
|
import com.google.zxing.ResultPointCallback;
|
||||||
import com.google.zxing.common.Collections;
|
import com.google.zxing.common.Collections;
|
||||||
import com.google.zxing.common.Comparator;
|
import com.google.zxing.common.Comparator;
|
||||||
import com.google.zxing.common.BitMatrix;
|
import com.google.zxing.common.BitMatrix;
|
||||||
|
@ -45,6 +46,7 @@ public class FinderPatternFinder {
|
||||||
private final Vector possibleCenters;
|
private final Vector possibleCenters;
|
||||||
private boolean hasSkipped;
|
private boolean hasSkipped;
|
||||||
private final int[] crossCheckStateCount;
|
private final int[] crossCheckStateCount;
|
||||||
|
private final ResultPointCallback resultPointCallback;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>Creates a finder that will search the image for three finder patterns.</p>
|
* <p>Creates a finder that will search the image for three finder patterns.</p>
|
||||||
|
@ -52,9 +54,14 @@ public class FinderPatternFinder {
|
||||||
* @param image image to search
|
* @param image image to search
|
||||||
*/
|
*/
|
||||||
public FinderPatternFinder(BitMatrix image) {
|
public FinderPatternFinder(BitMatrix image) {
|
||||||
|
this(image, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public FinderPatternFinder(BitMatrix image, ResultPointCallback resultPointCallback) {
|
||||||
this.image = image;
|
this.image = image;
|
||||||
this.possibleCenters = new Vector();
|
this.possibleCenters = new Vector();
|
||||||
this.crossCheckStateCount = new int[5];
|
this.crossCheckStateCount = new int[5];
|
||||||
|
this.resultPointCallback = resultPointCallback;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected BitMatrix getImage() {
|
protected BitMatrix getImage() {
|
||||||
|
@ -401,7 +408,11 @@ public class FinderPatternFinder {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!found) {
|
if (!found) {
|
||||||
possibleCenters.addElement(new FinderPattern(centerJ, centerI, estimatedModuleSize));
|
ResultPoint point = new FinderPattern(centerJ, centerI, estimatedModuleSize);
|
||||||
|
possibleCenters.addElement(point);
|
||||||
|
if (resultPointCallback != null) {
|
||||||
|
resultPointCallback.foundPossibleResultPoint(point);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue