Finished work on the local binarizer and renamed it to HybridBinarizer. It uses the...
[zxing.git] / android / src / com / google / zxing / client / android / ViewfinderView.java
1 /*
2  * Copyright (C) 2008 ZXing authors
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 package com.google.zxing.client.android;
18
19 import android.content.Context;
20 import android.content.res.Resources;
21 import android.graphics.Bitmap;
22 import android.graphics.Canvas;
23 import android.graphics.Paint;
24 import android.graphics.Rect;
25 import android.util.AttributeSet;
26 import android.view.View;
27 import com.google.zxing.ResultPoint;
28
29 import java.util.Collection;
30 import java.util.HashSet;
31
32 /**
33  * This view is overlaid on top of the camera preview. It adds the viewfinder rectangle and partial
34  * transparency outside it, as well as the laser scanner animation and result points.
35  *
36  * @author dswitkin@google.com (Daniel Switkin)
37  */
38 public final class ViewfinderView extends View {
39   private static final int[] SCANNER_ALPHA = {0, 64, 128, 192, 255, 192, 128, 64};
40   private static final long ANIMATION_DELAY = 100L;
41   private static final int OPAQUE = 0xFF;
42
43   private final Paint paint;
44   private Bitmap resultBitmap;
45   private final int maskColor;
46   private final int resultColor;
47   private final int frameColor;
48   private final int laserColor;
49   private final int resultPointColor;
50   private int scannerAlpha;
51   private Collection<ResultPoint> possibleResultPoints;
52   private Collection<ResultPoint> lastPossibleResultPoints;
53
54   // This constructor is used when the class is built from an XML resource.
55   public ViewfinderView(Context context, AttributeSet attrs) {
56     super(context, attrs);
57
58     // Initialize these once for performance rather than calling them every time in onDraw().
59     paint = new Paint();
60     Resources resources = getResources();
61     maskColor = resources.getColor(R.color.viewfinder_mask);
62     resultColor = resources.getColor(R.color.result_view);
63     frameColor = resources.getColor(R.color.viewfinder_frame);
64     laserColor = resources.getColor(R.color.viewfinder_laser);
65     resultPointColor = resources.getColor(R.color.possible_result_points);
66     scannerAlpha = 0;
67     possibleResultPoints = new HashSet<ResultPoint>(5);
68   }
69
70   @Override
71   public void onDraw(Canvas canvas) {
72     Rect frame = CameraManager.get().getFramingRect();
73     if (frame == null) {
74       return;
75     }
76     int width = canvas.getWidth();
77     int height = canvas.getHeight();
78
79     // Draw the exterior (i.e. outside the framing rect) darkened
80     paint.setColor(resultBitmap != null ? resultColor : maskColor);
81     canvas.drawRect(0, 0, width, frame.top, paint);
82     canvas.drawRect(0, frame.top, frame.left, frame.bottom + 1, paint);
83     canvas.drawRect(frame.right + 1, frame.top, width, frame.bottom + 1, paint);
84     canvas.drawRect(0, frame.bottom + 1, width, height, paint);
85
86     if (resultBitmap != null) {
87       // Draw the opaque result bitmap over the scanning rectangle
88       paint.setAlpha(OPAQUE);
89       canvas.drawBitmap(resultBitmap, frame.left, frame.top, paint);
90     } else {
91
92       // Draw a two pixel solid black border inside the framing rect
93       paint.setColor(frameColor);
94       canvas.drawRect(frame.left, frame.top, frame.right + 1, frame.top + 2, paint);
95       canvas.drawRect(frame.left, frame.top + 2, frame.left + 2, frame.bottom - 1, paint);
96       canvas.drawRect(frame.right - 1, frame.top, frame.right + 1, frame.bottom - 1, paint);
97       canvas.drawRect(frame.left, frame.bottom - 1, frame.right + 1, frame.bottom + 1, paint);
98
99       // Draw a red "laser scanner" line through the middle to show decoding is active
100       paint.setColor(laserColor);
101       paint.setAlpha(SCANNER_ALPHA[scannerAlpha]);
102       scannerAlpha = (scannerAlpha + 1) % SCANNER_ALPHA.length;
103       int middle = frame.height() / 2 + frame.top;
104       canvas.drawRect(frame.left + 2, middle - 1, frame.right - 1, middle + 2, paint);
105
106       Collection<ResultPoint> currentPossible = possibleResultPoints;
107       Collection<ResultPoint> currentLast = lastPossibleResultPoints;
108       if (currentPossible.isEmpty()) {
109         lastPossibleResultPoints = null;
110       } else {
111         possibleResultPoints = new HashSet<ResultPoint>(5);
112         lastPossibleResultPoints = currentPossible;
113         paint.setAlpha(OPAQUE);
114         paint.setColor(resultPointColor);
115         for (ResultPoint point : currentPossible) {
116           canvas.drawCircle(frame.left + point.getX(), frame.top + point.getY(), 6.0f, paint);
117         }
118       }
119       if (currentLast != null) {
120         paint.setAlpha(OPAQUE / 2);
121         paint.setColor(resultPointColor);
122         for (ResultPoint point : currentLast) {
123           canvas.drawCircle(frame.left + point.getX(), frame.top + point.getY(), 3.0f, paint);
124         }
125       }
126
127       // Request another update at the animation interval, but only repaint the laser line,
128       // not the entire viewfinder mask.
129       postInvalidateDelayed(ANIMATION_DELAY, frame.left, frame.top, frame.right, frame.bottom);
130     }
131   }
132
133   public void drawViewfinder() {
134     resultBitmap = null;
135     invalidate();
136   }
137
138   /**
139    * Draw a bitmap with the result points highlighted instead of the live scanning display.
140    *
141    * @param barcode An image of the decoded barcode.
142    */
143   public void drawResultBitmap(Bitmap barcode) {
144     resultBitmap = barcode;
145     invalidate();
146   }
147
148   public void addPossibleResultPoint(ResultPoint point) {
149     possibleResultPoints.add(point);
150   }
151
152 }