美文网首页
Android相机开发(二)

Android相机开发(二)

作者: 可笑的人人 | 来源:发表于2017-06-26 15:39 被阅读373次

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

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

    相机预览界面一般使用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<Camera.Size> 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<Camera.Size> 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
         * <p>注意:这里的w对应屏幕的height, h对应屏幕的width<p/>
         */
        private Camera.Size getProperSize(List<Camera.Size> 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.
         *
         * <p>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()}.
         *
         * <p>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相机开发(二)

          本文链接:https://www.haomeiwen.com/subject/otmkcxtx.html