您的位置:首页 > 移动开发 > Android开发

android入门:zxing学习笔记(四)

2012-08-08 00:36 211 查看
Camera取景后显示于屏幕上,是个挺简单的过程,但这会出现各种意料不到的问题,例如之前说的屏幕横竖屏与预览图片之间的方向,图片拉伸,还有在Barcode Scanner中,简单的旋转了图片预览方向后,会出现特征点标记错位,等等。

     第三篇简单的完成了相机的取景,还没有将取景的图片拍照存储下来。若想实现拍照的效果,则需要实现回调函数:Camera.PreviewCallback接口。接上一篇的代码,在此实现拍照的功能,将图片显示出来。之前一直在看Barcode Scanner的源码,并只是在其代码上修剪。当昨天自己来实现Camera的自动聚焦时,并遇到比较纠结的问题。在不出意外的情况下,Camera的使用还是挺简单的。

     先在此贴出代码,最简单,代码经过了测试,正常运行,测试机是HTC MyTouch 3G slide。

     需要的权限:

1 <uses-permission android:name="android.permission.CAMERA" />
2 <uses-feature android:name="android.hardware.camera" />
3 <uses-feature android:name="android.hardware.camera.autofocus" />


    整个代码:



1 import java.io.ByteArrayOutputStream;
2 import java.io.IOException;
3 import java.util.Timer;
4 import java.util.TimerTask;
5
6 import android.app.Activity;
7 import android.content.Context;
8 import android.graphics.Bitmap;
9 import android.graphics.BitmapFactory;
10 import android.graphics.ImageFormat;
11 import android.graphics.Rect;
12 import android.graphics.YuvImage;
13 import android.hardware.Camera;
14 import android.os.Bundle;
15 import android.util.Log;
16 import android.view.Display;
17 import android.view.SurfaceHolder;
18 import android.view.SurfaceView;
19 import android.view.WindowManager;
20 import android.widget.ImageView;
21
22 public class CameraTestActivity extends Activity implements SurfaceHolder.Callback {
23     private static String TAG = CameraTestActivity.class.getSimpleName();
24     private SurfaceHolder surfaceHolder;
25     private Camera camera;
26     private ImageView imageView;
27     private Timer mTimer;
28     private TimerTask mTimerTask;
29
30     private Camera.AutoFocusCallback mAutoFocusCallBack;
31     private Camera.PreviewCallback previewCallback;
32
33     /** Called when the activity is first created. */
34     @Override
35     public void onCreate(Bundle savedInstanceState) {
36         super.onCreate(savedInstanceState);
37         setContentView(R.layout.main);
38         SurfaceView surfaceView = (SurfaceView) findViewById(R.id.preview_view);
39         imageView = (ImageView) findViewById(R.id.image_view);
40         surfaceHolder = surfaceView.getHolder();
41         surfaceHolder.addCallback(this);
42         surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
43         mAutoFocusCallBack = new Camera.AutoFocusCallback() {
44             @Override
45             public void onAutoFocus(boolean success, Camera camera) {
46                 if (success) {
47                     // isAutoFocus = true;
48                     camera.setOneShotPreviewCallback(previewCallback);
49                     Log.d(TAG, "onAutoFocus success");
50                 }
51             }
52         };
53
54         previewCallback = new Camera.PreviewCallback() {
55             @Override
56             public void onPreviewFrame(byte[] data, Camera arg1) {
57                 if (data != null)
58                 {
59                     Camera.Parameters parameters = camera.getParameters();
60                     int imageFormat = parameters.getPreviewFormat();
61                     Log.i("map", "Image Format: " + imageFormat);
62
63                     Log.i("CameraPreviewCallback", "data length:" + data.length);
64                     if (imageFormat == ImageFormat.NV21)
65                     {
66                         // get full picture
67                         Bitmap image = null;
68                         int w = parameters.getPreviewSize().width;
69                         int h = parameters.getPreviewSize().height;
70
71                         Rect rect = new Rect(0, 0, w, h);
72                         YuvImage img = new YuvImage(data, ImageFormat.NV21, w, h, null);
73                         ByteArrayOutputStream baos = new ByteArrayOutputStream();
74                         if (img.compressToJpeg(rect, 100, baos))
75                         {
76                             image =  BitmapFactory.decodeByteArray(baos.toByteArray(), 0, baos.size());
77                             imageView.setImageBitmap(image);
78                         }
79
80                     }
81                 }
82             }
83         };
84
85         mTimer = new Timer();
86         mTimerTask = new CameraTimerTask();
87         mTimer.schedule(mTimerTask, 0, 500);
88     }
89
90     @Override
91     public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3) {
92         // TODO Auto-generated method stub
93     }
94
95     @Override
96     public void surfaceCreated(SurfaceHolder arg0) {
97         // TODO Auto-generated method stub
98         initCamera();
99     }
100
101     @Override
102     public void surfaceDestroyed(SurfaceHolder arg0) {
103         // TODO Auto-generated method stub
104         if (camera != null) {
105             camera.stopPreview();
106             camera.release();
107             camera = null;
108         }
109         previewCallback = null;
110         mAutoFocusCallBack = null;
111     }
112
113     public void initCamera() {
114         camera = Camera.open();
115         Camera.Parameters parameters = camera.getParameters();
116         WindowManager wm = (WindowManager) getSystemService(Context.WINDOW_SERVICE); // 获取当前屏幕管理器对象
117         Display display = wm.getDefaultDisplay(); // 获取屏幕信息的描述类
118         parameters.setPreviewSize(display.getWidth(), display.getHeight());
119         camera.setParameters(parameters);
120         try {
121             camera.setPreviewDisplay(surfaceHolder);
122         } catch (IOException e) {
123             System.out.println(e.getMessage());
124         }
125         camera.startPreview();
126     }
127
128     class CameraTimerTask extends TimerTask {
129         @Override
130         public void run() {
131             if (camera != null) {
132                 camera.autoFocus(mAutoFocusCallBack);
133             }
134         }
135     }
136 }




     与上一篇的简单预览相比,这篇增加了两个内容,一个是自动聚焦,一个是拍照。代码看上去很简单,没多少内容。但不亲自测试下,还会发现不少。

     刚开始在Samsung S5570 galaxy mini上测试,总是不能成功的拍照。调试跟踪后,发现自动聚焦总是失败,聚焦失败就没有进行拍照操作。后面并尝试将自动聚焦代码注释掉,直接拍照,发现也是无法显示拍照的结果。之前的PreviewCallback的代码如下:

1 Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);


    这行代码返回的总是null,即bitmap没有成功生成。对这些代码本来就是拿来用,功能实现了,就行,对这些都只是简单的了解,当遇到bug后并百思不得其解。后来在网上几经查找发现原来是BitmapFactory.decodeByteArray只支持一定的格式,camara支持的previewformat格式为NV21,所以在获得bitmap时,需要进行转换。通过YuvImage类来转换成JPEG格式,再显示出来。具体讨论,请点这里。

    解决照片的显示问题后,还有一个问题便是自动聚焦失败。上面特意强调了使用的事HTC 的手机测试成功,是因为之前在samsung s5570 上测试总是失败,拿到HTC的那款手机上立马成功。应该是三星的这款手机不支持自动聚焦。之前在这个三星手机上跑过Barcode Scanner,就自以为这手机能够自动聚焦,并一直在查找自己代码的原因。后面在仔细的读了Barcode Scanner的代码后,发现他得处理方式是:

1 CameraManager.get().requestPreviewFrame(decodeThread.getHandler(), R.id.decode);//实现拍照
2 CameraManager.get().requestAutoFocus(this, R.id.auto_focus);//实现聚焦


     首先实现拍照,再是实现聚焦,并且重载的聚焦回调函数是隔一段时间再次发出聚焦的请求,实现不断的聚焦。



1 public void onAutoFocus(boolean success, Camera camera) {
2     if (autoFocusHandler != null) {
3       Message message = autoFocusHandler.obtainMessage(autoFocusMessage, success);
4       // Simulate continuous autofocus by sending a focus request every
5 // AUTOFOCUS_INTERVAL_MS milliseconds.
6 //Log.d(TAG, "Got auto-focus callback; requesting another");
7       autoFocusHandler.sendMessageDelayed(message, AUTOFOCUS_INTERVAL_MS);
8       autoFocusHandler = null;
9     } else {
10       Log.d(TAG, "Got auto-focus callback, but no handler for it");
11     }
12   }




    聚焦于拍照之前没有先后的逻辑关系,聚焦为了拍照更清晰。这样,关于camera取景聚焦拍照的简单过程并如上了。

    还有一个关键的点幷是回调函数。以前没有接触java代码,在看到很多接口监听处理的代码时,总是很困惑。譬如一段简单的button:

1 private final Button.OnClickListener addCardListener = new TextView.OnClickListener() {
2         @Override
3         public void onClick(View v) {
4         //在此实现button点击后的操作
5     }
6 };


    如上的代码实现了点击监听,通过回调函数,当有点击操作时,并执行onClick函数。这就是一个简单的回调函数的使用。

    关于回调函数请看这里,还有回调函数在android中得体现点这里

    大家的分享方便你我。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息