Android Camera系列開發 (三): 通過CameraAPI拍照

來源:互聯網
上載者:User

Android Camera系列開發 (三): 通過CameraAPI拍照

作者:雨水   2013-8-21 CSDN部落格:http://blog.csdn.net/gobitan/

概述

使用Camera有兩種方式:通過Intent使用已有的app和通過Camera構建自己的app。在開發系列(一) 中已經介紹了通過Intent方式,本文介紹通過CameraAPI的方式拍照。

 

關鍵類解析

通過CameraAPI方式拍照需要引入幾個關鍵的類:

Camera類:最主要的類,用於管理Camera裝置,本文中主要用到以下方法:

  • open():通過open方法擷取Camera執行個體。
  • setPreviewDisplay(SurfaceHolder):設定預覽拍照
  • startPreview():開始預覽
  • stopPreview():停止預覽
  • release():釋放Camera執行個體
  • takePicture(Camera.ShutterCallback shutter, Camera.PictureCallback raw, Camera.PictureCallback jpeg):這個是拍照要執行的方法,包含了三個回調參數。Shutter是快門按下時的回調,raw是擷取拍照未經處理資料的回調,jpeg是擷取經過壓縮成jpg格式的映像資料。在本文中需要實現最後一個回調,參見下面。

Camera.PictureCallback介面:該回調介面包含了一個onPictureTaken(byte[]data, Camera camera)方法。在這個方法中可以儲存映像資料。

SurfaceView類:用於控制預覽介面

SurfaceHolder.Callback介面:用於處理預覽的事件,需實現如下三個方法:

surfaceCreated(SurfaceHolderholder):預覽介面建立時調用,每次介面改變後都會重新建立,需要擷取相機資源並設定SurfaceHolder。

surfaceChanged(SurfaceHolderholder, int format, int width, int height):預覽介面發生變化時調用,每次介面發生變化之後需要重新啟動預覽。

surfaceDestroyed(SurfaceHolderholder):預覽銷毀時調用,停止預覽,釋放相應資源。

 

通過Camera方式來實現拍照

通過Camera方式 會比通過Intent方式獲得更為豐富的功能。通常建立一個定製化的Camera需要如下步驟:

(1)    通過Camera.open()來擷取Camera執行個體。

(2)    建立Preview類,需要繼承SurfaceView類並實現SurfaceHolder.Callback介面。

(3)    為相機設定Preview

(4)    構建一個Preview的Layout來 預覽相機;

(5)    為拍照建立Listener以擷取拍照後的回調;

(6)    拍照並儲存檔案;

(7)    釋放Camera。

 

具體步驟

第一步:在Eclipse中建立一個名為AndroidCamera的Android工程,可參見Helloworld的例子;

第二步:在AndroidManifest.xml中添加使用Camera相關的聲明如下:

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

第三步:編寫AndroidCameraActivity類,類的原始碼如下: 

import java.io.File;import java.io.FileNotFoundException;import java.io.FileOutputStream;import java.io.IOException;import java.text.SimpleDateFormat;import java.util.Date;import android.app.Activity;import android.hardware.Camera;import android.hardware.Camera.PictureCallback;import android.os.Bundle;import android.os.Environment;import android.util.Log;import android.view.View;import android.view.View.OnClickListener;import android.widget.Button;import android.widget.FrameLayout;public class AndroidCameraActivity extends Activity implements OnClickListener, PictureCallback {    private CameraSurfacePreview mCameraSurPreview = null;    private Button mCaptureButton = null;    private String TAG = "Dennis";        @Override      protected void onCreate(Bundle savedInstanceState) {          super.onCreate(savedInstanceState);          setContentView(R.layout.main);                  // Create our Preview view and set it as the content of our activity.        FrameLayout preview = (FrameLayout) findViewById(R.id.camera_preview);        mCameraSurPreview = new CameraSurfacePreview(this);        preview.addView(mCameraSurPreview);               // Add a listener to the Capture button        mCaptureButton = (Button) findViewById(R.id.button_capture);        mCaptureButton.setOnClickListener(this);    }        @Override    public void onPictureTaken(byte[] data, Camera camera) {    //save the picture to sdcard    File pictureFile = getOutputMediaFile();        if (pictureFile == null){            Log.d(TAG, "Error creating media file, check storage permissions: ");            return;        }        try {            FileOutputStream fos = new FileOutputStream(pictureFile);            fos.write(data);            fos.close();        } catch (FileNotFoundException e) {            Log.d(TAG, "File not found: " + e.getMessage());        } catch (IOException e) {        Log.d(TAG, "Error accessing file: " + e.getMessage());        }                // Restart the preview and re-enable the shutter button so that we can take another picture camera.startPreview();  //See if need to enable or not mCaptureButton.setEnabled(true);    }        @Override    public void onClick(View v) {    mCaptureButton.setEnabled(false);            // get an image from the camera    mCameraSurPreview.takePicture(this);    }        private File getOutputMediaFile(){      //get the mobile Pictures directory          File picDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);            //get the current time          String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());                     return new File(picDir.getPath() + File.separator + "IMAGE_"+ timeStamp + ".jpg");        }}

第四步:新增CameraSurfacePreview類,原始碼如下:

import java.io.IOException;import android.content.Context;import android.hardware.Camera;import android.hardware.Camera.PictureCallback;import android.util.Log;import android.view.SurfaceHolder;import android.view.SurfaceView;public class CameraSurfacePreview extends SurfaceView implements SurfaceHolder.Callback {    private SurfaceHolder mHolder;    private Camera mCamera;    public CameraSurfacePreview(Context context) {        super(context);        // Install a SurfaceHolder.Callback so we get notified when the        // underlying surface is created and destroyed.        mHolder = getHolder();        mHolder.addCallback(this);        // deprecated setting, but required on Android versions prior to 3.0        mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);    }    public void surfaceCreated(SurfaceHolder holder) {        Log.d("Dennis", "surfaceCreated() is called");            try {// Open the Camera in preview modemCamera = Camera.open();mCamera.setPreviewDisplay(holder);        } catch (IOException e) {            Log.d("Dennis", "Error setting camera preview: " + e.getMessage());        }    }        public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {        Log.d("Dennis", "surfaceChanged() is called");            try {            mCamera.startPreview();        } catch (Exception e){            Log.d("Dennis", "Error starting camera preview: " + e.getMessage());        }    }    public void surfaceDestroyed(SurfaceHolder holder) {    if (mCamera != null) {    mCamera.stopPreview();        mCamera.release();        mCamera = null;    }        Log.d("Dennis", "surfaceDestroyed() is called");    }        public void takePicture(PictureCallback imageCallback) {mCamera.takePicture(null, null, imageCallback);}}

第五步:替換Layout檔案,內容如下:

<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:orientation="horizontal"    android:layout_width="fill_parent"    android:layout_height="fill_parent"    >  <FrameLayout    android:id="@+id/camera_preview"    android:layout_width="fill_parent"    android:layout_height="fill_parent"    android:layout_weight="1"    />  <Button    android:id="@+id/button_capture"    android:text="Capture"    android:layout_width="wrap_content"    android:layout_height="wrap_content"    android:layout_gravity="center"    /></LinearLayout>

第六步:為AndroidManifest.xml中的acitvity增加如下屬性:

android:screenOrientation="landscape"

第七步:運行程式。

拍完照之後,可以在SD卡中的Pictures目錄下找到儲存的照片。

 

原始碼工程:https://github.com/dennishucd/DennisTech/blob/master/archives/AndroidCamera_20130821.zip

參考資料

1. 
http://developer.android.com/training/camera/videobasics.html

2. 
http://developer.android.com/guide/topics/media/camera.html

3.  http://developer.android.com/reference/android/hardware/Camera.html

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.