Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> Android開發實例 >> Android應用開發入門(六十四)使用Camera拍攝照片示例

Android應用開發入門(六十四)使用Camera拍攝照片示例

編輯:Android開發實例

前言

  在開發Android應用的時候,如果需要調用攝像頭獲取拍攝的照片,除了通過Intent調用系統現有相機應用拍攝照片之外,還可以通過直接調用Camera硬件去去獲取攝像頭拍攝的照片。本文將講解如何在Android應用中通過Camera拍攝照片,這個對開發相機類應用尤為重要,同樣最後也將以一個簡單的Demo演示。

  本文的主要內容:

  1. Camera
  2. 驗證設備是否配備攝像頭硬件
  3. Camera捕獲畫面的預覽
  4. 使用Camera拍照
  5. 使用Camera拍照的Demo
  6. Camera的回調監聽
  7. Camera的參數設置

Camera

  Camera是Android攝像頭硬件的相機類,位於硬件包"android.hardware.Camera"下。它主要用於攝像頭捕獲圖片、啟動/停止預覽圖片、拍照、獲取視頻幀等,它是設備本地的服務,負責管理設備上的攝像頭硬件。

  Camera既然用於管理設備上的攝像頭硬件,那麼它也為開發人員提供了相應的方法,並且這些方法大部分都是native的,用C++在底層實現,下面簡單介紹一下Camera的一些方法:

  • static Camera open():打開Camera,返回一個Camera實例。
  • static Camera open(int cameraId):根據cameraId打開一個Camera,返回一個Camera實例。
  • final void release():釋放掉Camera的資源。
  • static int getNumberOfCameras():獲取當前設備支持的Camera硬件個數。
  • Camera.Parameters getParameters():獲取Camera的各項參數設置類。
  • void setParameters(Camera.Parameters params):通過params把Camera的各項參數寫入到Camera中。
  • final void setDisplayOrientation(int degrees):攝像預覽的旋轉度。
  • final void setPreviewDisplay(SurfaceHolder holder):設置Camera預覽的SurfaceHolder。
  • final void starPreview():開始Camera的預覽。
  • final void stopPreview():停止Camera的預覽
  • final void autoFocus(Camera.AutoFocusCallback cb):自動對焦。
  • final takePicture(Camera.ShutterCallback shutter,Camera.PictureCallback raw,Camera.PictureCallback jpeg):拍照。
  • final void lock():鎖定Camera硬件,使其他應用無法訪問。
  • final void unlock():解鎖Camera硬件,使其他應用可以訪問。

  上面已經介紹了Camera的常用方法,下面根據這些方法詳細講解Android下使用Camera開發拍照應用最基本的過程:

  1. 使用open()方法獲取一個Camera對象,鑒於Android設備可能配置了多個攝像頭,open()方法可以通過攝像頭Id開啟指定的攝像頭。
  2. 為Camera對象設置預覽類,它是一個SurfaceHolder對象,通過setPreviewDisplay(SurfaceHolder)方法設置。
  3. 調用startPreview()方法開始Camera對象的預覽。
  4. 調用takePicture()方法進行拍照,其中可以通過Camera.PictureCallback()回調獲得拍攝的Image數據。
  5. 當拍攝完成後,需要調用stopPreview()方法停止預覽,並使用release()釋放Camera占用的資源。

  以上介紹的步驟都是最基本的過程,是必不可少的。Camera沒有提供公開的構造函數,只能通過open()方法獲取,並且必須設置一個預覽類SurfaceHolder,如果不設置的話,將無法使用Camera。在使用完成Camera之後,必須使用release()釋放Camera資源。

驗證設備是否配備攝像頭硬件

  因為Android的開源,所以其支持的設備多而雜,在使用Camera的時候,最好驗證一下當前運行的設備上是否配備了攝像頭硬件。這裡需要用到一個PackageManager,它用於檢測應用安裝設備的各種信息,可以通過Context.getPackageManager()方法獲取。可以通過PackageManager.hasSystemFeature(String name)方法檢測設備是否支持攝像頭操作,它傳遞的是一個String類型的參數,被PackageManager定義為了常量,返回一個Boolean數據,驗證是否檢測通過,對於Camera而言,可以檢測如下信息:

  • FEATURE_CAMERA:設備是否有攝像頭。
  • FEATURE_CAMERA_ANY:設備至少有一個攝像頭。
  • FEATURE_CAMERA_AUTOFOCUS:設備支持的攝像頭是否支持自動對焦
  • FEATURE_CAMERA_FLASH:設備是否配備閃光燈。
  • FEATURE_CAMERA_FRONT:設備是否有一個前置攝像頭。

  一般而言,檢測FEATURE_CAMERA即可:

  1. /** 檢測設備是否存在Camera硬件 */ 
  2.     private boolean checkCameraHardware(Context context) {  
  3.         if (context.getPackageManager().hasSystemFeature(  
  4.                 PackageManager.FEATURE_CAMERA)) {  
  5.             // 存在  
  6.             return true;  
  7.         } else {  
  8.             // 不存在  
  9.             return false;  
  10.         }  
  11.     } 

Camera捕獲畫面的預覽

  Camera的預覽,需要放到一個SurfaceView中,出於安全的考慮,在設計Android的時候就規定,如果需要調用Camera,必須為其制定顯示在屏幕上的SurfaceView預覽,否則將無法使用Camera。關於SurfaceView和SurfaceHolder的內容,在之前的博客中已經詳細講解,這裡不再贅述,不清楚的朋友可以看看之前的:http://www.fengfly.com/plus/view-214102-1.html。

  下面我們直接使用一個類去繼承SurfaceView當做Camera的預覽類:

  1. package cn.bgxt.camerapicturedemo;  
  2.  
  3. import java.io.IOException;  
  4. import android.content.Context;  
  5. import android.hardware.Camera;  
  6. import android.util.Log;  
  7. import android.view.SurfaceHolder;  
  8. import android.view.SurfaceView;  
  9.  
  10. /**  
  11.  * 定義一個預覽類  
  12.  */ 
  13. public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {  
  14.     private static final String TAG = "main";  
  15.     private SurfaceHolder mHolder;  
  16.     private Camera mCamera;  
  17.  
  18.     public CameraPreview(Context context, Camera camera) {  
  19.         super(context);  
  20.         mCamera = camera;  
  21.  
  22.         // 通過SurfaceView獲得SurfaceHolder  
  23.         mHolder = getHolder();  
  24.         // 為SurfaceHolder指定回調  
  25.         mHolder.addCallback(this);  
  26.         // 設置Surface不維護自己的緩沖區,而是等待屏幕的渲染引擎將內容推送到界面 在Android3.0之後棄用  
  27.         mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);  
  28.     }  
  29.  
  30.     public void surfaceCreated(SurfaceHolder holder) {  
  31.         // 當Surface被創建之後,開始Camera的預覽  
  32.         try {  
  33.             mCamera.setPreviewDisplay(holder);  
  34.             mCamera.startPreview();  
  35.         } catch (IOException e) {  
  36.             Log.d(TAG, "預覽失敗");  
  37.         }  
  38.     }  
  39.  
  40.     public void surfaceDestroyed(SurfaceHolder holder) {  
  41.           
  42.     }  
  43.  
  44.     public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {  
  45.         // Surface發生改變的時候將被調用,第一次顯示到界面的時候也會被調用  
  46.         if (mHolder.getSurface() == null){  
  47.           // 如果Surface為空,不繼續操作  
  48.           return;  
  49.         }  
  50.  
  51.         // 停止Camera的預覽  
  52.         try {  
  53.             mCamera.stopPreview();  
  54.         } catch (Exception e){  
  55.             Log.d(TAG, "當Surface改變後,停止預覽出錯");  
  56.         }  
  57.  
  58.         // 在預覽前可以指定Camera的各項參數  
  59.  
  60.         // 重新開始預覽  
  61.         try {  
  62.             mCamera.setPreviewDisplay(mHolder);  
  63.             mCamera.startPreview();  
  64.  
  65.         } catch (Exception e){  
  66.             Log.d(TAG, "預覽Camera出錯");  
  67.         }  
  68.     }  

使用Camera拍照

  當指定了Camera的預覽類,並開始預覽之後,就可以通過takePicture()方法進行拍照了,下面是它的完整簽名:

  上面已經定義好了SurfaceView,它是一個Camera的預覽類,下面直接通過一個示例演示Camera是如何進行拍照的,備注都比較詳細,這裡不再贅述了。

     public final void taskPicture(Camera.ShuffterCallback shutter,Camera.PictureCallback raw,Camera.PictureCallback postview,Camera.PictureCallback jpeg)

  它將以異步的方式從Camera中獲取圖像,具有多個回調類作為參數,並且都可以為null,下面分別介紹這些參數的意義:

  • shutter:在按下快門的時候回調,這裡可以播放一段聲音。
  • raw:從Camera獲取到未經處理的圖像。
  • postview:從Camera獲取一個快速預覽的圖片,不是所有設備都支持。
  • jpeg:從Camera獲取到一個經過壓縮的jpeg圖片。

   雖然raw、postview、jpeg都是Camera.PictureCallback回調,但是一般我們只需要獲取jpeg,其他傳null即可,Camera.PictureCallback裡需要實現一個方法onPictureTaken(byte[] data,Camera camera),data及為圖像數據。值得注意的是,一般taskPicture()方法拍照完成之後,SurfaceView都會停留在拍照的瞬間,需要重新調用startPreview()才會繼續預覽。

  如果直接使用taskPicture()進行拍照的話,Camera是不會進行自動對焦的,這裡需要使用Camera.autoFocus()方法進行對焦,它傳遞一個Camera.AutoFocusCallback參數,用於自動對焦完成後回調,一般會在它對焦完成在進行taskPicture()拍照。

 

使用Camera拍照的Demo

   上面已經介紹了使用Camera的基本步驟以及涉及的內容,這裡通過一個簡單的Demo演示一下,使用上面附上代碼的預覽類進行Camera預覽。代碼中注釋比較完整,這裡不再贅述。

  布局代碼:activity_main.xml

  1. <?xml version="1.0" encoding="utf-8"?> 
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
  3.     android:orientation="horizontal" 
  4.     android:layout_width="fill_parent" 
  5.     android:layout_height="fill_parent" 
  6.     > 
  7.   <FrameLayout 
  8.     android:id="@+id/camera_preview" 
  9.     android:layout_width="fill_parent" 
  10.     android:layout_height="fill_parent" 
  11.     android:layout_weight="1" 
  12.     /> 
  13.  
  14.   <Button 
  15.     android:id="@+id/button_capture" 
  16.     android:text="拍照" 
  17.     android:layout_width="wrap_content" 
  18.     android:layout_height="wrap_content" 
  19.     android:layout_gravity="center" 
  20.     /> 
  21. </LinearLayout> 

  實現代碼:MainActivity.java

  1. package cn.bgxt.camerapicturedemo;  
  2.  
  3. import java.io.File;  
  4. import java.io.FileOutputStream;  
  5.  
  6. import android.os.Bundle;  
  7. import android.util.Log;  
  8. import android.view.View;  
  9. import android.widget.Button;  
  10. import android.widget.FrameLayout;  
  11. import android.app.Activity;  
  12. import android.content.Context;  
  13. import android.content.pm.PackageManager;  
  14. import android.hardware.Camera;  
  15. import android.hardware.Camera.AutoFocusCallback;  
  16. import android.hardware.Camera.PictureCallback;  
  17.  
  18. public class MainActivity extends Activity {  
  19.     protected static final String TAG = "main";  
  20.     private Camera mCamera;  
  21.     private CameraPreview mPreview;  
  22.  
  23.     @Override 
  24.     protected void onCreate(Bundle savedInstanceState) {  
  25.         super.onCreate(savedInstanceState);  
  26.         setContentView(R.layout.activity_main);  
  27.  
  28.         mCamera = getCameraInstance();  
  29.  
  30.         // 創建預覽類,並與Camera關聯,最後添加到界面布局中  
  31.         mPreview = new CameraPreview(this, mCamera);  
  32.         FrameLayout preview = (FrameLayout) findViewById(R.id.camera_preview);  
  33.         preview.addView(mPreview);  
  34.  
  35.  
  36.         Button captureButton = (Button) findViewById(R.id.button_capture);  
  37.         captureButton.setOnClickListener(new View.OnClickListener() {  
  38.             @Override 
  39.             public void onClick(View v) {  
  40.                 // 在捕獲圖片前進行自動對焦  
  41.                 mCamera.autoFocus(new AutoFocusCallback() {  
  42.                       
  43.                     @Override 
  44.                     public void onAutoFocus(boolean success, Camera camera) {  
  45.                         // 從Camera捕獲圖片  
  46.                         mCamera.takePicture(null, null, mPicture);  
  47.                     }  
  48.                 });                  
  49.             }  
  50.         });  
  51.     }  
  52.  
  53.     /** 檢測設備是否存在Camera硬件 */ 
  54.     private boolean checkCameraHardware(Context context) {  
  55.         if (context.getPackageManager().hasSystemFeature(  
  56.                 PackageManager.FEATURE_CAMERA)) {  
  57.             // 存在  
  58.             return true;  
  59.         } else {  
  60.             // 不存在  
  61.             return false;  
  62.         }  
  63.     }  
  64.  
  65.     /** 打開一個Camera */ 
  66.     public static Camera getCameraInstance() {  
  67.         Camera c = null;  
  68.         try {  
  69.             c = Camera.open();   
  70.         } catch (Exception e) {  
  71.             Log.d(TAG, "打開Camera失敗失敗");  
  72.         }  
  73.         return c;   
  74.     }  
  75.  
  76.     private PictureCallback mPicture = new PictureCallback() {  
  77.  
  78.         @Override 
  79.         public void onPictureTaken(byte[] data, Camera camera) {  
  80.             // 獲取Jpeg圖片,並保存在sd卡上  
  81.             File pictureFile = new File("/sdcard/" + System.currentTimeMillis()  
  82.                     + ".jpg");  
  83.             try {  
  84.                 FileOutputStream fos = new FileOutputStream(pictureFile);  
  85.                 fos.write(data);  
  86.                 fos.close();  
  87.             } catch (Exception e) {  
  88.                 Log.d(TAG, "保存圖片失敗");  
  89.             }  
  90.         }  
  91.     };  
  92.  
  93.     @Override 
  94.     protected void onDestroy() {  
  95.         // 回收Camera資源  
  96.         if(mCamera!=null){  
  97.             mCamera.stopPreview();  
  98.             mCamera.release();  
  99.             mCamera=null;  
  100.         }  
  101.         super.onDestroy();  
  102.     }  
  103.       

 

效果展示:

 

Camera的回調監聽

  上面介紹Camera拍照的時候介紹了兩個回調,Camera還提供了一些其他的回調的事件監聽方法,這裡簡單介紹幾個常用的:

  • final void setErrorCallback(Camera.ErrorCallback cb):Camera發送錯誤的時候回調,可以在其中進行錯誤的後續處理。
  • final void setPreviedCallback(Camera.PreviewCallback cb):Camera預覽界面發生變化的時候回調,可以在其中獲取到Camera捕獲到的幀圖像。

Camera的參數設置

  Camera作為一個攝像頭硬件的調用類,還為我們提供了詳細的設置攝像頭各項參數的方法,比如閃光燈的模式、自動對焦的模式等。步驟是使用Camera.getParameters()方法獲取到Camera.Parameters對象,在其中設置好攝像頭的各項參數後,再通過Camera.setParameters()方法寫入到Camera對象中即可。這個設置必須在使用startPreview()之前完成。關於Camera參數的設置,比較細致,不在本篇博客的內容之中,以後有機會再詳細介紹。

 

   源碼下載

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved