Android手機攝像頭編程入門

 

lesson36

本講內容:Android手機攝像頭編程入門

智能手機中的攝像頭和普通手機中的攝像頭最大的區別在於,智能機上的攝像頭可以由程序員寫程序控制,做一些有趣的應用譬如,畫中畫,做一些有用的應用譬如二維碼識別,等等。本講打算通過一個實例,來介紹一下攝像頭編程,相關解釋都寫在代碼中了,請注意看代碼註釋。

實例:窈窈照相機,功能很簡單,就是點擊程序彈出照相預覽界面,點擊相機按鈕完成照相功能,所照相片會存儲在手機存儲卡根目錄。

1、創建一個項目 Lesson36_Camera ,主程序文件爲 MainActivity.java

2、AndroidManifest.xml 中設置屏幕爲橫屏,並且聲明攝像頭和存儲卡的使用權限,具體代碼如下:

01 <?xml version="1.0" encoding="utf-8"?>
02 <MANIFEST xmlns:android="http://schemas.android.com/apk/res/android" android:versionname="1.0" android:versioncode="1" package="basic.android.lesson36">
03     <APPLICATION android:icon="@drawable/icon" android:label="@string/app_name">
04         <ACTIVITY android:label="@string/app_name" android:configchanges="orientation|keyboardHidden|keyboard" android:screenorientation="landscape" android:name=".MainActivity">
05             <INTENT -filter>
06                 <ACTION android:name="android.intent.action.MAIN" />
07                 <CATEGORY android:name="android.intent.category.LAUNCHER" />
08             </INTENT>
09         </ACTIVITY>
10   
11     </APPLICATION>
12     <USES android:minsdkversion="8" -sdk />
13     <USES android:name="android.permission.CAMERA" -permission></USES>
14     <USES android:name="android.permission.WRITE_EXTERNAL_STORAGE" -permission></USES>
15     <USES android:name="android.hardware.camera" -feature />
16     <USES android:name="android.hardware.camera.autofocus" -feature />
17 </MANIFEST>

3、本例中不需要佈局文件main.xml,因爲本例中的UI組建都是動態添加上去的。

4、最後MainActivity.java的代碼如下:

001 package basic.android.lesson36;
002   
003 import java.io.BufferedOutputStream;
004 import java.io.File;
005 import java.io.FileOutputStream;
006 import java.io.IOException;
007 import java.util.Calendar;
008 import java.util.Locale;
009   
010 import android.app.Activity;
011 import android.content.Context;
012 import android.graphics.Bitmap;
013 import android.graphics.BitmapFactory;
014 import android.graphics.PixelFormat;
015 import android.hardware.Camera;
016 import android.os.Bundle;
017 import android.text.format.DateFormat;
018 import android.util.Log;
019 import android.view.KeyEvent;
020 import android.view.SurfaceHolder;
021 import android.view.SurfaceView;
022 import android.view.Window;
023 import android.view.WindowManager;
024 import android.widget.FrameLayout;
025 import android.widget.TextView;
026 import android.widget.Toast;
027   
028 public class MainActivity extends Activity {
029   
030     private CameraView cv;
031     //準備一個相機對象
032     private Camera mCamera = null;
033     //準備一個Bitmap對象
034     private Bitmap mBitmap = null;  
035   
036     //準備一個保存圖片的PictureCallback對象
037     public Camera.PictureCallback pictureCallback = new Camera.PictureCallback() {
038   
039         public void onPictureTaken(byte[] data, Camera camera) {
040             Log.i("yao","onPictureTaken");
041             Toast.makeText(getApplicationContext(), "正在保存……", Toast.LENGTH_LONG).show();
042             //用BitmapFactory.decodeByteArray()方法可以把相機傳回的裸數據轉換成Bitmap對象
043             mBitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
044             //接下來的工作就是把Bitmap保存成一個存儲卡中的文件
045             File file = new File("/sdcard/YY"+ new DateFormat().format("yyyyMMdd_hhmmss", Calendar.getInstance(Locale.CHINA)) + ".jpg");
046             try {
047                 file.createNewFile();
048                 BufferedOutputStream os = new BufferedOutputStream(new FileOutputStream(file));
049                 mBitmap.compress(Bitmap.CompressFormat.PNG, 100, os);
050                 os.flush();
051                 os.close();
052                 Toast.makeText(getApplicationContext(), "圖片保存完畢,在存儲卡的根目錄", Toast.LENGTH_LONG).show();
053             } catch (IOException e) {
054                 e.printStackTrace();
055             }
056         }
057   
058     };
059   
060     //Activity的創建方法
061     @Override
062     public void onCreate(Bundle savedInstanceState) {
063         super.onCreate(savedInstanceState);
064   
065         //窗口去掉標題
066         requestWindowFeature(Window.FEATURE_NO_TITLE);
067         //窗口設置爲全屏
068         getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,WindowManager.LayoutParams.FLAG_FULLSCREEN);
069         //設置窗口爲半透明
070         getWindow().setFormat(PixelFormat.TRANSLUCENT);
071   
072         //提供一個幀佈局
073         FrameLayout  fl = new FrameLayout(this);      
074   
075         //創建一個照相預覽用的SurfaceView子類,並放在幀佈局的底層
076         cv = new CameraView(this);
077         fl.addView(cv);
078   
079         //創建一個文本框添加在幀佈局中,我們可以看到,文字自動出現在了SurfaceView的前面,由此你可以在預覽窗口做出各種特殊效果
080         TextView tv = new TextView(this);
081         tv.setText("請按\"相機\"按鈕拍攝");
082         fl.addView(tv);
083   
084         //設置Activity的根內容視圖
085         setContentView(fl);
086   
087     }
088   
089     //相機按鍵按下的事件處理方法
090     public boolean onKeyDown(int keyCode, KeyEvent event) {
091         Log.i("yao","MainActivity.onKeyDown");
092         if (keyCode == KeyEvent.KEYCODE_CAMERA) {
093             if (mCamera != null) {
094                 Log.i("yao","mCamera.takePicture");
095                 //當按下相機按鈕時,執行相機對象的takePicture()方法,該方法有三個回調對象做入參,不需要的時候可以設null
096                 mCamera.takePicture(null, null, pictureCallback);
097             }
098         }
099         return cv.onKeyDown(keyCode, event);
100     }
101   
102     // 照相視圖
103     class CameraView extends SurfaceView {
104   
105         private SurfaceHolder holder = null;
106   
107         //構造函數
108         public CameraView(Context context) {
109             super(context);
110             Log.i("yao","CameraView");
111   
112             // 操作surface的holder
113             holder = this.getHolder();
114             // 創建SurfaceHolder.Callback對象
115             holder.addCallback(new SurfaceHolder.Callback() {
116   
117                 @Override
118                 public void surfaceDestroyed(SurfaceHolder holder) {
119                     // 停止預覽
120                     mCamera.stopPreview();
121                     // 釋放相機資源並置空
122                     mCamera.release();
123                     mCamera = null;
124                 }
125   
126                 @Override
127                 public void surfaceCreated(SurfaceHolder holder) {
128                     //當預覽視圖創建的時候開啓相機
129                     mCamera = Camera.open();
130                     try {
131                         //設置預覽
132                         mCamera.setPreviewDisplay(holder);
133                     } catch (IOException e) {
134                         // 釋放相機資源並置空
135                         mCamera.release();
136                         mCamera = null;
137                     }
138   
139                 }
140   
141                 //當surface視圖數據發生變化時,處理預覽信息
142                 @Override
143                 public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
144   
145                     //獲得相機參數對象
146                     Camera.Parameters parameters = mCamera.getParameters();
147                     //設置格式
148                     parameters.setPictureFormat(PixelFormat.JPEG);
149                     //設置預覽大小,這裏我的測試機是Milsstone所以設置的是854x480
150                     parameters.setPreviewSize(854, 480);
151                     //設置自動對焦
152                     parameters.setFocusMode("auto");
153                     //設置圖片保存時的分辨率大小
154                     parameters.setPictureSize(2592, 1456);
155                     //給相機對象設置剛纔設定的參數
156                     mCamera.setParameters(parameters);
157                     //開始預覽
158                     mCamera.startPreview();
159                 }
160             });
161             // 設置Push緩衝類型,說明surface數據由其他來源提供,而不是用自己的Canvas來繪圖,在這裏是由攝像頭來提供數據
162             holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
163         }
164   
165     }
166   
167 }

5、連接Milestone,編譯並運行程序:悲劇的是,截圖只能看到黑黑的一片,無法截取到攝像頭傳輸過來SurfaceView信息,而在真機中是能看到預覽效果的。

device

還是上一張照好的圖片給大家吧,

YY20101208_030141

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章