Standardize and update all copyright statements to name "ZXing authors" as suggested...
[zxing.git] / android / src / com / google / zxing / client / android / CameraSurfaceView.java
1 /*
2  * Copyright 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.graphics.Canvas;
21 import android.graphics.Color;
22 import android.graphics.Paint;
23 import android.graphics.Point;
24 import android.graphics.Rect;
25 import android.view.SurfaceHolder;
26 import android.view.SurfaceView;
27 import com.google.zxing.ResultPoint;
28
29 /**
30  * @author dswitkin@google.com (Daniel Switkin)
31  */
32 final class CameraSurfaceView extends SurfaceView implements SurfaceHolder.Callback {
33
34   private static final int[] SCANNER_ALPHA = {0, 64, 128, 192, 255, 192, 128, 64};
35
36   private final CameraManager cameraManager;
37   private final SurfaceHolder surfaceHolder;
38   private boolean hasSurface;
39   private int scannerAlpha;
40
41   CameraSurfaceView(Context context, CameraManager cameraManager) {
42     super(context);
43     this.cameraManager = cameraManager;
44
45     // Install a SurfaceHolder.Callback so we get notified when the underlying surface is created
46     // and destroyed.
47     surfaceHolder = getHolder();
48     surfaceHolder.addCallback(this);
49     hasSurface = false;
50     scannerAlpha = 0;
51     surfaceHolder.setSizeFromLayout();
52   }
53
54   public void surfaceCreated(SurfaceHolder holder) {
55     hasSurface = true;
56   }
57
58   public void surfaceDestroyed(SurfaceHolder holder) {
59     // FIXME(dswitkin): The docs say this surface will be destroyed when this method returns. In
60     // practice this has not been a problem so far. I need to investigate.
61     hasSurface = false;
62   }
63
64   public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
65     // Surface size or format has changed. This won't happen because of the  setFixedSize() call.
66   }
67
68   /**
69    * This method is only called from the WorkerThread. It's job is to grab the next preview frame
70    * from the camera, draw the framing rectangle, and blit everything to the screen.
71    */
72   public void capturePreviewAndDraw() {
73     if (hasSurface) {
74       Canvas canvas = surfaceHolder.lockCanvas();
75       cameraManager.capturePreview(canvas);
76       Rect frame = cameraManager.getFramingRect();
77       int width = canvas.getBitmapWidth();
78       int height = canvas.getBitmapHeight();
79
80       // Draw the exterior (i.e. outside the framing rect) as half darkened
81       Paint paint = new Paint();
82       paint.setColor(Color.BLACK);
83       paint.setAlpha(96);
84       Rect box = new Rect(0, 0, width, frame.top);
85       canvas.drawRect(box, paint);
86       box.set(0, frame.top, frame.left, frame.bottom + 1);
87       canvas.drawRect(box, paint);
88       box.set(frame.right + 1, frame.top, width, frame.bottom + 1);
89       canvas.drawRect(box, paint);
90       box.set(0, frame.bottom + 1, width, height);
91       canvas.drawRect(box, paint);
92
93       // Draw a two pixel solid black border inside the framing rect
94       paint.setAlpha(255);
95       box.set(frame.left, frame.top, frame.right + 1, frame.top + 2);
96       canvas.drawRect(box, paint);
97       box.set(frame.left, frame.top + 2, frame.left + 2, frame.bottom - 1);
98       canvas.drawRect(box, paint);
99       box.set(frame.right - 1, frame.top, frame.right + 1, frame.bottom - 1);
100       canvas.drawRect(box, paint);
101       box.set(frame.left, frame.bottom - 1, frame.right + 1, frame.bottom + 1);
102       canvas.drawRect(box, paint);
103
104       // Draw a red "laser scanner" line through the middle
105       paint.setColor(Color.RED);
106       paint.setAlpha(SCANNER_ALPHA[scannerAlpha]);
107       int middle = frame.height() / 2 + frame.top;
108       box.set(frame.left + 2, middle - 1, frame.right - 1, middle + 2);
109       canvas.drawRect(box, paint);
110
111       surfaceHolder.unlockCanvasAndPost(canvas);
112
113       // This cheap animation is tied to the rate at which we pull previews from the camera.
114       scannerAlpha = (scannerAlpha + 1) % SCANNER_ALPHA.length;
115     }
116   }
117
118   /**
119    * Draw a line for 1D barcodes (which return two points) or otherwise a set of points returned
120    * from the decoder to indicate what we found.
121    * TODO(dswitkin): It might be nice to clear the framing rect and zoom in on the actual still that
122    * was captured, then paint the green points on it. This would also clear the red scanner line
123    * which doesn't make sense after the capture.
124    *
125    * @param resultPoints An array of points from the decoder, whose coordinates are expressed
126    * relative to the still image from the camera.
127    */
128   public void drawResultPoints(ResultPoint[] resultPoints) {
129     if (hasSurface) {
130       Canvas canvas = surfaceHolder.lockCanvas();
131       Paint paint = new Paint();
132       paint.setColor(Color.GREEN);
133       paint.setAlpha(128);
134
135       Point[] points = cameraManager.convertResultPoints(resultPoints);
136       if (points.length == 2) {
137         paint.setStrokeWidth(4);
138         canvas.drawLine(points[0].x, points[0].y, points[1].x, points[1].y, paint);
139       } else {
140         paint.setStrokeWidth(10);
141         for (int x = 0; x < points.length; x++) {
142           canvas.drawPoint(points[x].x, points[x].y, paint);
143         }
144       }
145
146       surfaceHolder.unlockCanvasAndPost(canvas);
147     }
148   }
149         
150 }