[转载]Android Camera系列开发 (三): 通过CameraAPI拍照

链接:http://blog.csdn.net/gobitan/article/details/10135019

概述

使用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相关的声明如下:

  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" />  
  4. <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />    

第三步:编写AndroidCameraActivity类,类的源代码如下: 

  1. import java.io.File;  
  2. import java.io.FileNotFoundException;  
  3. import java.io.FileOutputStream;  
  4. import java.io.IOException;  
  5. import java.text.SimpleDateFormat;  
  6. import java.util.Date;  
  7. import android.app.Activity;  
  8. import android.hardware.Camera;  
  9. import android.hardware.Camera.PictureCallback;  
  10. import android.os.Bundle;  
  11. import android.os.Environment;  
  12. import android.util.Log;  
  13. import android.view.View;  
  14. import android.view.View.OnClickListener;  
  15. import android.widget.Button;  
  16. import android.widget.FrameLayout;  
  17.   
  18. public class AndroidCameraActivity extends Activity implements OnClickListener, PictureCallback {  
  19.     private CameraSurfacePreview mCameraSurPreview = null;  
  20.     private Button mCaptureButton = null;  
  21.     private String TAG = "Dennis";  
  22.       
  23.     @Override    
  24.     protected void onCreate(Bundle savedInstanceState) {    
  25.         super.onCreate(savedInstanceState);    
  26.         setContentView(R.layout.main);    
  27.           
  28.         // Create our Preview view and set it as the content of our activity.  
  29.         FrameLayout preview = (FrameLayout) findViewById(R.id.camera_preview);  
  30.         mCameraSurPreview = new CameraSurfacePreview(this);  
  31.         preview.addView(mCameraSurPreview);    
  32.           
  33.      // Add a listener to the Capture button  
  34.         mCaptureButton = (Button) findViewById(R.id.button_capture);  
  35.         mCaptureButton.setOnClickListener(this);  
  36.     }  
  37.       
  38.     @Override  
  39.     public void onPictureTaken(byte[] data, Camera camera) {  
  40.   
  41.         //save the picture to sdcard  
  42.         File pictureFile = getOutputMediaFile();  
  43.         if (pictureFile == null){  
  44.             Log.d(TAG, "Error creating media file, check storage permissions: ");  
  45.             return;  
  46.         }  
  47.   
  48.         try {  
  49.             FileOutputStream fos = new FileOutputStream(pictureFile);  
  50.             fos.write(data);  
  51.             fos.close();  
  52.         } catch (FileNotFoundException e) {  
  53.             Log.d(TAG, "File not found: " + e.getMessage());  
  54.         } catch (IOException e) {  
  55.             Log.d(TAG, "Error accessing file: " + e.getMessage());  
  56.         }  
  57.           
  58.         // Restart the preview and re-enable the shutter button so that we can take another picture  
  59.         camera.startPreview();  
  60.           
  61.         //See if need to enable or not  
  62.         mCaptureButton.setEnabled(true);  
  63.     }  
  64.       
  65.     @Override  
  66.     public void onClick(View v) {  
  67.         mCaptureButton.setEnabled(false);  
  68.           
  69.         // get an image from the camera  
  70.         mCameraSurPreview.takePicture(this);  
  71.     }  
  72.       
  73.     private File getOutputMediaFile(){    
  74.         //get the mobile Pictures directory    
  75.         File picDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);    
  76.     
  77.         //get the current time    
  78.         String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());     
  79.             
  80.         return new File(picDir.getPath() + File.separator + "IMAGE_"+ timeStamp + ".jpg");      
  81.     }  
  82. }  

 

第四步:新增CameraSurfacePreview类,源代码如下:

  1. import java.io.IOException;  
  2. import android.content.Context;  
  3. import android.hardware.Camera;  
  4. import android.hardware.Camera.PictureCallback;  
  5. import android.util.Log;  
  6. import android.view.SurfaceHolder;  
  7. import android.view.SurfaceView;  
  8.   
  9. public class CameraSurfacePreview extends SurfaceView implements SurfaceHolder.Callback {  
  10.     private SurfaceHolder mHolder;  
  11.     private Camera mCamera;  
  12.   
  13.     public CameraSurfacePreview(Context context) {  
  14.         super(context);  
  15.   
  16.         // Install a SurfaceHolder.Callback so we get notified when the  
  17.         // underlying surface is created and destroyed.  
  18.         mHolder = getHolder();  
  19.         mHolder.addCallback(this);  
  20.         // deprecated setting, but required on Android versions prior to 3.0  
  21.         mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);  
  22.     }  
  23.   
  24.     public void surfaceCreated(SurfaceHolder holder) {  
  25.           
  26.         Log.d("Dennis", "surfaceCreated() is called");  
  27.           
  28.         try {  
  29.             // Open the Camera in preview mode  
  30.             mCamera = Camera.open();  
  31.             mCamera.setPreviewDisplay(holder);  
  32.         } catch (IOException e) {  
  33.             Log.d("Dennis", "Error setting camera preview: " + e.getMessage());  
  34.         }  
  35.     }  
  36.       
  37.     public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {  
  38.           
  39.         Log.d("Dennis", "surfaceChanged() is called");  
  40.           
  41.         try {  
  42.             mCamera.startPreview();  
  43.   
  44.         } catch (Exception e){  
  45.             Log.d("Dennis", "Error starting camera preview: " + e.getMessage());  
  46.         }  
  47.     }  
  48.   
  49.     public void surfaceDestroyed(SurfaceHolder holder) {  
  50.         if (mCamera != null) {  
  51.             mCamera.stopPreview();  
  52.             mCamera.release();  
  53.             mCamera = null;  
  54.         }  
  55.           
  56.         Log.d("Dennis", "surfaceDestroyed() is called");  
  57.     }  
  58.       
  59.     public void takePicture(PictureCallback imageCallback) {  
  60.         mCamera.takePicture(null, null, imageCallback);  
  61.     }  
  62. }  


第五步:替换Layout文件,内容如下:

  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="Capture"  
  17.     android:layout_width="wrap_content"  
  18.     android:layout_height="wrap_content"  
  19.     android:layout_gravity="center"  
  20.     />  
  21. </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

posted @ 2015-01-10 22:26  chenlinyunyi  阅读(104)  评论(0编辑  收藏  举报