(二)进阶练习____8、捕捉照片——操作相机

原文链接:http://docs.eoeandroid.com/training/camera/cameradirect.html

作者:2003yyyyyy

完成时间:

目录

 [隐藏

控制相机

这一课,我们讨论怎么利用框架的api直接控制相机硬件。

直接控制照相机设备,比请求从现有的照片或视频应用程序需要更多的代码。然而,如果你想搭建一个专业相机应用或者一些完全融入你的程序UI上,这节课展示给你怎么做。

打开照相机

获取 Camera 类的实例是能够控制相机的第一步程序。就像 android 自己的相机程序那样。推荐的一个方法是通过在onCreate方法里分别打开线程启动相机。这个方法是个这种方法是一个好主意,因为它可以花上一段时间,可能陷入困境的UI线程。在更基础的实现上,打开相机可能会推迟 onResume() 方法的重用和保持接下来的简单使用。

如果相机正在被另外一个程序调用时,调用 Camera.open()抛出异常。所以我们要把代码包裹在一个try块中。 

private boolean safeCameraOpen(int id) {
    boolean qOpened = false;
 
    try {
        releaseCameraAndPreview();
        mCamera = Camera.open(id);
        qOpened = (mCamera != null);
    } catch (Exception e) {
        Log.e(getString(R.string.app_name), "failed to open Camera");
        e.printStackTrace();
    }
 
    return qOpened;    
}
 
private void releaseCameraAndPreview() {
    mPreview.setCamera(null);
    if (mCamera != null) {
        mCamera.release();
        mCamera = null;
    }
}

从第九级api,相机框架支持多相机。如果你使用遗留的API和调用 open() 没有加任何参数,你将会回去第一个后置相机。

创建相机预览

通常照相都要你的用户在按下快门前看到预览。这样做,你可以用SurfaceView 绘制相机传感器捕捉到的影像。

 

预览类

开始显示一个预览,你需要预览类。预览类需要一个实现 android.view.SurfaceHolder.Callback 接口,这是用于传递图像的数据来自于相机的硬件到应用程序。 

class Preview extends ViewGroup implements SurfaceHolder.Callback {
 
    SurfaceView mSurfaceView;
    SurfaceHolder mHolder;
 
    Preview(Context context) {
        super(context);
 
        mSurfaceView = new SurfaceView(context);
        addView(mSurfaceView);
 
        // Install a SurfaceHolder.Callback so we get notified when the
        // underlying surface is created and destroyed.
        mHolder = mSurfaceView.getHolder();
        mHolder.addCallback(this);
        mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
    }
  ...
}

在通过Camera 对象之后生活照片预览方可开始显示,见下一节。

设置和开始预览

首先启动相机时,一个相机实例和它有关联的预览必须创建一个特殊的规则。下面的代码片段中,初始化进程是封装在相机中的,所以Camera.startPreview() 是被setCamera()方法调用的,任何时候用户做出某些相机的更改。预览必须surfaceChanged()回调方法中被重启。 

public void setCamera(Camera camera) {
    if (mCamera == camera) { return; }
 
    stopPreviewAndFreeCamera();
 
    mCamera = camera;
 
    if (mCamera != null) {
        List<Size> localSizes = mCamera.getParameters().getSupportedPreviewSizes();
        mSupportedPreviewSizes = localSizes;
        requestLayout();
 
        try {
            mCamera.setPreviewDisplay(mHolder);
        } catch (IOException e) {
            e.printStackTrace();
        }
 
        /*
          Important: Call startPreview() to start updating the preview surface. Preview must 
          be started before you can take a picture.
          */
        mCamera.startPreview();
    }
}

修改相机设置

由曝光补偿缩放级别,改变相机照相设置的方法,这个例子仅仅是改变预览画面的大小而已;更多的代码请查看相机应用程序. 

public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
    // Now that the size is known, set up the camera parameters and begin
    // the preview.
    Camera.Parameters parameters = mCamera.getParameters();
    parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height);
    requestLayout();
    mCamera.setParameters(parameters);
 
    /*
      Important: Call startPreview() to start updating the preview surface. Preview must be
      started before you can take a picture.
    */
    mCamera.startPreview();
}

设置预览方向

大多数相机应用锁显示成横向模式,因为这是取自相机传感器的。这个设置不会阻止你把肖像模式的照片,因为设备的方向是记录在EXIF头部。setCameraDisplayOrientation() 方法允许您在不影响图像是如何记录情况下改变预览显示。然而,在Android API级别14之前,你必须停止你之前预览转变方向,然后重新启动它。

照一张相

一旦预览开始,使用Camera.takePicture()方法来拍摄照片。您可以创建Camera.PictureCallbackCamera.ShutterCallback对象并将它们传递到Camera.takePicture() 。

如果你想抓住图像不停,您可以创建一个Camera.PreviewCallback实现onPreviewFrame()。对于介于两者之间,您可以捕获唯一选择的预览框架,或者设置一个延迟动作执行takePicture() 。

重启预览

得到一张图像后,在用户用户可以照另一张照片前您必须重新启动前预览。在这个例子中,重新启动是通过重载快门按钮。例如,重启是通过重载快门按钮。 

@Override
public void onClick(View v) {
    switch(mPreviewState) {
    case K_STATE_FROZEN:
        mCamera.startPreview();
        mPreviewState = K_STATE_PREVIEW;
        break;
 
    default:
        mCamera.takePicture( null, rawCallback, null);
        mPreviewState = K_STATE_BUSY;
    } // switch
    shutterBtnConfig();
}

停止预览和释放相机对象

一旦你结束使用相机对象,它就是时候清理了。特别是,您必须释放相机对象,否则你可能会使其他应用程序崩溃,包括您自己的应用程序的新实例。

什么时候应该停止和释放相机对象?嗯,让你预览表层回收是个好的提议,是时候停止预览和释放相机,从Preview类中看这些方法。 

public void surfaceDestroyed(SurfaceHolder holder) {
    // Surface will be destroyed when we return, so stop the preview.
    if (mCamera != null) {
        /*
          Call stopPreview() to stop updating the preview surface.
        */
        mCamera.stopPreview();
    }
}
 
/**
  * When this function returns, mCamera will be null.
  */
private void stopPreviewAndFreeCamera() {
 
    if (mCamera != null) {
        /*
          Call stopPreview() to stop updating the preview surface.
        */
        mCamera.stopPreview();
 
        /*
          Important: Call release() to release the camera for use by other applications. 
          Applications should release the camera immediately in onPause() (and re-open() it in
          onResume()).
        */
        mCamera.release();
 
        mCamera = null;
    }
}

早在这一课,这个步骤也是setCamera()方法中的一部分,因为初始化一个相机总是在停止预览前开始的。

 

posted @ 2014-07-30 16:52  ╰→劉じ尛鶴  阅读(134)  评论(0)    收藏  举报