android入門:zxing學習筆記(四)


     個人網站:臭蛋 www.choudan.net

  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中得體現點這里
    大家的分享方便你我。

 

 

     


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM