Android相机开发(二)

本篇总结了利用Camera API在Android5.0版本以下开发相机:
本文参考文章http://https://yq.aliyun.com/articles/26706#
相机开发首先需要在Manifanst.xml文件总添加相机权限,以及自动对焦功能,Android6.0以上的需要动态分配权限;




相机预览界面一般使用SurfaceView存放,可以自定义一个继承SurfaceView控件作为相机控件,并实现SurfaceHolder.Callback接口,通过SurfaceView状态控制相机状态;
SurfaceHolder.Callback会在SurfaceView创建后分别回调surfaceCreated(),surfaceChanged,surfaceDestroyed三个方法;相机将在surfaceCreated回调的时候打开,并设置相机预览显示在SurfaceView中,开启相机代码如下:

@Override
    public void surfaceCreated(SurfaceHolder holder) {
        if (mCamera == null) {
            mCamera = Camera.open();
            try {
                mCamera.setPreviewDisplay(holder);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

在开启相机预览前,为了使预览界面长宽比跟手机设备屏幕比相同,需要先设置相机各种设置参数,比如设置相机分辨率,图片分辨率等等。还可以设置照片质量,相机是否自动对焦等等;设置相机参数代码如下:

@Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
        Log.i(TAG, "surfaceChanged");
        setCameraParams(mCamera, mScreenWidth, mScreenHeight);
        mCamera.startPreview();
    }

/**
     * 设置相机参数
     * @param camera 相机
     * @param width 目标宽度
     * @param height 目标高度
     */
    private void setCameraParams(Camera camera, int width, int height) {
        Log.i(TAG,"setCameraParams  width="+width+"  height="+height);
        //返回当前相机设置参数
        Camera.Parameters parameters = camera.getParameters();
        //获取当前相机支持相片大小,并以队列形式返回
        List pictureSizeList = parameters.getSupportedPictureSizes();
        /**从列表中选取合适的分辨率*/
        Camera.Size picSize = getProperSize(pictureSizeList, ((float) height / width));
        if (null == picSize) {
            picSize = parameters.getPictureSize();
        }
        Log.i(TAG, "picSize.width=" + picSize.width + "  picSize.height=" + picSize.height);

        float w = picSize.width;
        float h = picSize.height;
        //设置相片宽度和高度
        parameters.setPictureSize(picSize.width,picSize.height);
        this.setLayoutParams(new FrameLayout.LayoutParams((int) (height*(h/w)), height));

        //获取当前相机支持预览界面大小,并以队列形式返回
        List previewSizeList = parameters.getSupportedPreviewSizes();
        Camera.Size preSize = getProperSize(previewSizeList, ((float) height) / width);
        if (null != preSize) {
            Log.i(TAG, "preSize.width=" + preSize.width + "  preSize.height=" + preSize.height);
            parameters.setPreviewSize(preSize.width, preSize.height);
        }
        //设置相机拍摄图片质量,数值范围1~100,数值越大图片质量越高
        parameters.setJpegQuality(100);
        //如果相机支持自动对焦,则开启
        if (parameters.getSupportedFocusModes().contains(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE)) {
            parameters.setFocusMode(android.hardware.Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
        }
        mCamera.cancelAutoFocus();//自动对焦。
        // 设置PreviewDisplay的方向,将捕获的画面旋转多少度显示
        mCamera.setDisplayOrientation(90);
        mCamera.setParameters(parameters);
}

/**
     * 从列表中选取合适的分辨率
     * 默认w:h = 4:3
     * 

注意:这里的w对应屏幕的height, h对应屏幕的width

*/ private Camera.Size getProperSize(List pictureSizeList, float screenRatio) { Log.i(TAG, "screenRatio=" + screenRatio); Camera.Size result = null; for (Camera.Size size : pictureSizeList) { float currentRatio = ((float) size.width) / size.height; if (currentRatio - screenRatio == 0) { result = size; break; } } if (null == result) { for (Camera.Size size : pictureSizeList) { float curRatio = ((float) size.width) / size.height; if (curRatio == 4f / 3) {// 默认w:h = 4:3 result = size; break; } } } return result; }

相机拍照则调用camera.takePicture(ShutterCallback shutter, PictureCallback raw,PictureCallback postview, PictureCallback jpeg),其中postview为传null,源码如下:

/**
     * Triggers an asynchronous image capture. The camera service will initiate
     * a series of callbacks to the application as the image capture progresses.
     * The shutter callback occurs after the image is captured. This can be used
     * to trigger a sound to let the user know that image has been captured. The
     * raw callback occurs when the raw image data is available (NOTE: the data
     * will be null if there is no raw image callback buffer available or the
     * raw image callback buffer is not large enough to hold the raw image).
     * The postview callback occurs when a scaled, fully processed postview
     * image is available (NOTE: not all hardware supports this). The jpeg
     * callback occurs when the compressed image is available. If the
     * application does not need a particular callback, a null can be passed
     * instead of a callback method.
     *
     * 

This method is only valid when preview is active (after * {@link #startPreview()}). Preview will be stopped after the image is * taken; callers must call {@link #startPreview()} again if they want to * re-start preview or take more pictures. This should not be called between * {@link android.media.MediaRecorder#start()} and * {@link android.media.MediaRecorder#stop()}. * *

After calling this method, you must not call {@link #startPreview()} * or take another picture until the JPEG callback has returned. * * @param shutter the callback for image capture moment, or null * @param raw the callback for raw (uncompressed) image data, or null * @param postview callback with postview image data, may be null * @param jpeg the callback for JPEG image data, or null */ public final void takePicture(ShutterCallback shutter, PictureCallback raw, PictureCallback postview, PictureCallback jpeg) { //源码具体实现 }

ShutterCallback是监听快门按下的回调。后面三个PictureCallback接口参数,分别对应三份图像数据,分别是原始图像、缩放和压缩图像和JPG图像,图像数据可以在PictureCallback接口的void onPictureTaken(byte[] data, Camera camera)中获得,三份数据相应的三个回调正好按照参数顺序调用,通常我们只关心JPG图像数据,此时前面两个PictureCallback接口参数可以直接传null。

每次调用takePicture方法拍照后,摄像头会停止预览,假如需要继续拍照,则需要在上面的PictureCallback的onPictureTaken函数末尾,再调Camera::startPreview()。

最后,如果需要关闭相机,或者关闭当前拍照页面,需要先释放相机资源,代码如下:

@Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        mCamera.stopPreview();//停止预览
        mCamera.release();//释放相机资源
        mCamera = null;
        holder = null;
    }

Android5.0以下版本开发相机,具体源码可参考:Android5.0以下版本

你可能感兴趣的:(Android相机开发(二))