package com.google.zxing.client.android;
+import com.google.zxing.ResultPoint;
+import com.google.zxing.client.android.camera.CameraManager;
+
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.util.AttributeSet;
import android.view.View;
+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
* transparency outside it, as well as the laser scanner animation and result points.
+ *
+ * @author dswitkin@google.com (Daniel Switkin)
*/
public final class ViewfinderView extends View {
private static final int[] SCANNER_ALPHA = {0, 64, 128, 192, 255, 192, 128, 64};
private static final long ANIMATION_DELAY = 100L;
+ private static final int OPAQUE = 0xFF;
- private final Paint mPaint;
- private final Rect mBox;
- private Bitmap mResultBitmap;
- private final int mMaskColor;
- private final int mResultColor;
- private final int mFrameColor;
- private final int mLaserColor;
- private int mScannerAlpha;
+ private final Paint paint;
+ private Bitmap resultBitmap;
+ private final int maskColor;
+ private final int resultColor;
+ private final int frameColor;
+ private final int laserColor;
+ private final int resultPointColor;
+ private int scannerAlpha;
+ private Collection<ResultPoint> possibleResultPoints;
+ private Collection<ResultPoint> lastPossibleResultPoints;
// This constructor is used when the class is built from an XML resource.
public ViewfinderView(Context context, AttributeSet attrs) {
super(context, attrs);
// Initialize these once for performance rather than calling them every time in onDraw().
- mPaint = new Paint();
- mBox = new Rect();
+ paint = new Paint();
Resources resources = getResources();
- mMaskColor = resources.getColor(R.color.viewfinder_mask);
- mResultColor = resources.getColor(R.color.result_view);
- mFrameColor = resources.getColor(R.color.viewfinder_frame);
- mLaserColor = resources.getColor(R.color.viewfinder_laser);
- mScannerAlpha = 0;
+ maskColor = resources.getColor(R.color.viewfinder_mask);
+ resultColor = resources.getColor(R.color.result_view);
+ frameColor = resources.getColor(R.color.viewfinder_frame);
+ laserColor = resources.getColor(R.color.viewfinder_laser);
+ resultPointColor = resources.getColor(R.color.possible_result_points);
+ scannerAlpha = 0;
+ possibleResultPoints = new HashSet<ResultPoint>(5);
}
@Override
public void onDraw(Canvas canvas) {
Rect frame = CameraManager.get().getFramingRect();
+ if (frame == null) {
+ return;
+ }
int width = canvas.getWidth();
int height = canvas.getHeight();
// Draw the exterior (i.e. outside the framing rect) darkened
- mPaint.setColor(mResultBitmap != null ? mResultColor : mMaskColor);
- mBox.set(0, 0, width, frame.top);
- canvas.drawRect(mBox, mPaint);
- mBox.set(0, frame.top, frame.left, frame.bottom + 1);
- canvas.drawRect(mBox, mPaint);
- mBox.set(frame.right + 1, frame.top, width, frame.bottom + 1);
- canvas.drawRect(mBox, mPaint);
- mBox.set(0, frame.bottom + 1, width, height);
- canvas.drawRect(mBox, mPaint);
-
- if (mResultBitmap != null) {
+ paint.setColor(resultBitmap != null ? resultColor : maskColor);
+ canvas.drawRect(0, 0, width, frame.top, paint);
+ canvas.drawRect(0, frame.top, frame.left, frame.bottom + 1, paint);
+ canvas.drawRect(frame.right + 1, frame.top, width, frame.bottom + 1, paint);
+ canvas.drawRect(0, frame.bottom + 1, width, height, paint);
+
+ if (resultBitmap != null) {
// Draw the opaque result bitmap over the scanning rectangle
- mPaint.setAlpha(255);
- canvas.drawBitmap(mResultBitmap, frame.left, frame.top, mPaint);
+ paint.setAlpha(OPAQUE);
+ canvas.drawBitmap(resultBitmap, null, frame, paint);
} else {
+
// Draw a two pixel solid black border inside the framing rect
- mPaint.setColor(mFrameColor);
- mBox.set(frame.left, frame.top, frame.right + 1, frame.top + 2);
- canvas.drawRect(mBox, mPaint);
- mBox.set(frame.left, frame.top + 2, frame.left + 2, frame.bottom - 1);
- canvas.drawRect(mBox, mPaint);
- mBox.set(frame.right - 1, frame.top, frame.right + 1, frame.bottom - 1);
- canvas.drawRect(mBox, mPaint);
- mBox.set(frame.left, frame.bottom - 1, frame.right + 1, frame.bottom + 1);
- canvas.drawRect(mBox, mPaint);
+ paint.setColor(frameColor);
+ canvas.drawRect(frame.left, frame.top, frame.right + 1, frame.top + 2, paint);
+ canvas.drawRect(frame.left, frame.top + 2, frame.left + 2, frame.bottom - 1, paint);
+ canvas.drawRect(frame.right - 1, frame.top, frame.right + 1, frame.bottom - 1, paint);
+ canvas.drawRect(frame.left, frame.bottom - 1, frame.right + 1, frame.bottom + 1, paint);
// Draw a red "laser scanner" line through the middle to show decoding is active
- mPaint.setColor(mLaserColor);
- mPaint.setAlpha(SCANNER_ALPHA[mScannerAlpha]);
- mScannerAlpha = (mScannerAlpha + 1) % SCANNER_ALPHA.length;
+ paint.setColor(laserColor);
+ paint.setAlpha(SCANNER_ALPHA[scannerAlpha]);
+ scannerAlpha = (scannerAlpha + 1) % SCANNER_ALPHA.length;
int middle = frame.height() / 2 + frame.top;
- mBox.set(frame.left + 2, middle - 1, frame.right - 1, middle + 2);
- canvas.drawRect(mBox, mPaint);
+ canvas.drawRect(frame.left + 2, middle - 1, frame.right - 1, middle + 2, paint);
+
+ Rect previewFrame = CameraManager.get().getFramingRectInPreview();
+ float scaleX = frame.width() / (float) previewFrame.width();
+ float scaleY = frame.height() / (float) previewFrame.height();
+
+ 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 + (int) (point.getX() * scaleX),
+ frame.top + (int) (point.getY() * scaleY),
+ 6.0f, paint);
+ }
+ }
+ if (currentLast != null) {
+ paint.setAlpha(OPAQUE / 2);
+ paint.setColor(resultPointColor);
+ for (ResultPoint point : currentLast) {
+ canvas.drawCircle(frame.left + (int) (point.getX() * scaleX),
+ frame.top + (int) (point.getY() * scaleY),
+ 3.0f, paint);
+ }
+ }
// Request another update at the animation interval, but only repaint the laser line,
// not the entire viewfinder mask.
- postInvalidateDelayed(ANIMATION_DELAY, mBox.left, mBox.top, mBox.right, mBox.bottom);
+ postInvalidateDelayed(ANIMATION_DELAY, frame.left, frame.top, frame.right, frame.bottom);
}
}
public void drawViewfinder() {
- mResultBitmap = null;
+ resultBitmap = null;
invalidate();
}
* @param barcode An image of the decoded barcode.
*/
public void drawResultBitmap(Bitmap barcode) {
- mResultBitmap = barcode;
+ resultBitmap = barcode;
invalidate();
}
+ public void addPossibleResultPoint(ResultPoint point) {
+ possibleResultPoints.add(point);
+ }
+
}