Android自定义Camera相机(打开闪光灯、前后摄像头切换)

想搞自定义相机很久了一直觉得很难所以一直拖着前两天有点闲就参考Android自定义相机超详细讲解搞了一下发现并不是那么难,嘿嘿~

一、参考布局


<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent">
    <FrameLayout
        android:id="@+id/diy_camera_fy_context"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        >FrameLayout>
    <LinearLayout
        android:layout_alignParentBottom="true"
        android:orientation="horizontal"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
    <Button
        android:id="@+id/diy_camera_btn_pat"
        android:text="拍照"
        android:layout_width="0dp"
        android:layout_weight="1"
        android:layout_height="wrap_content" />
    <Button
        android:id="@+id/diy_camera_btn_exchange_camera"
        android:text="切换摄像头"
        android:layout_width="0dp"
        android:layout_weight="1"
        android:layout_height="wrap_content" />
        <Button
            android:id="@+id/diy_camera_btn_open_flashlight"
            android:text="打开闪光灯"
            android:layout_width="0dp"
            android:layout_weight="1"
            android:layout_height="wrap_content" />

    LinearLayout>
RelativeLayout>

二、初始化相机

  1. 获取相机
 /**
     * 获取照相机实例
     *
     * @return
     */
    private Camera getCamera() {
     
        Camera camera = null;
        if (CameraProvider.hasCamera()) {
     
            if (Build.VERSION.SDK_INT == Build.VERSION_CODES.GINGERBREAD) {
     
            	//打开摄像头
                camera = Camera.open();
            } else {
     
				//打开摄像头
                camera = Camera.open(cameraType);
            }
        } else {
     
            ToastUtils.showShort("摄像头打开失败");
        }
        return camera;
    }

这里需要说明一下:

  • 在Android2.3以前是不支持前置摄像头的所以默认打开的是后置摄像头
  • 在Android2.3以后有了前置摄像头所以:
    cameraId:0是后置摄像头 1是前置摄像头
  1. 初始化相机信息

    /**
     * 初始化相机
     */
    private void initCamera() {
     

        mCamera = getCamera();
        if (mCamera != null) {
     
            pictureSizes.clear();
            previewSizes.clear();
            pictureSizes = mCamera.getParameters().getSupportedPictureSizes();
            previewSizes = mCamera.getParameters().getSupportedPreviewSizes();
            //得到摄像头的参数
            parameters = mCamera.getParameters();
            parameters.setJpegQuality(80);//设置照片的质量
            parameters.setPreviewSize(previewSizes.get(0).width, previewSizes.get(0).height);//设置预览尺寸
            parameters.setPictureSize(pictureSizes.get(0).width, pictureSizes.get(0).height);//设置照片分辨率
            parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);// 连续对焦模式
            parameters.setFlashMode(flashMode);
            //Camera.Parameters.FOCUS_MODE_AUTO; //自动聚焦模式
            //Camera.Parameters.FOCUS_MODE_INFINITY;//无穷远
            //Camera.Parameters.FOCUS_MODE_MACRO;//微距
            //Camera.Parameters.FOCUS_MODE_FIXED;//固定焦距
            parameters.setRotation(90);  //生成的图像旋转90度
            mCamera.setParameters(parameters);
            isPreviewing = true;
            //设置摄像头角度
            setCameraDisplayOrientation(CustomCameraActivity.this, 0, mCamera);
        } else {
     
            ToastUtils.showShort("摄像头打开失败");
        }
    }
  1. 设置摄像头角度在有些手机上拍出来的照片会自动旋转角度
/**
     * 设置 摄像头的角度
     *
     * @param activity 上下文
     * @param cameraId 摄像头ID(假如手机有N个摄像头,cameraId 的值 就是 0 ~ N-1)
     * @param camera   摄像头对象
     */
    public static void setCameraDisplayOrientation(Activity activity, int cameraId, Camera camera) {
     
        Camera.CameraInfo info = new Camera.CameraInfo();
        //获取摄像头信息
        Camera.getCameraInfo(cameraId, info);
        int rotation = activity.getWindowManager().getDefaultDisplay().getRotation();
        //获取摄像头当前的角度
        int degrees = 0;
        switch (rotation) {
     
            case Surface.ROTATION_0:
                degrees = 0;
                break;
            case Surface.ROTATION_90:
                degrees = 90;
                break;
            case Surface.ROTATION_180:
                degrees = 180;
                break;
            case Surface.ROTATION_270:
                degrees = 270;
                break;
        }
        int result;
        if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
     
            // 前置摄像头
            result = (info.orientation + degrees) % 360;
            result = (360 - result) % 360; // compensate the mirror
        } else {
     
            // 后置摄像头
            result = (info.orientation - degrees + 360) % 360;
        }
        camera.setDisplayOrientation(result);
    }
  1. 自定义SurfaceView
public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {
     
    private Camera mCamera ;
    private SurfaceHolder mHolder;
    public CameraPreview(Context context,Camera camera) {
     
        super(context);
        mCamera = camera;
        //获取SurfaceHolder
        mHolder = getHolder();
        //为SurfaceHolder设置回调
        mHolder.addCallback(this);
        mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);

    }

    @Override
    public void surfaceCreated(SurfaceHolder holder) {
     
        // 当Surface被创建之后,开始Camera的预览
        try {
     

            mCamera.setPreviewDisplay(holder);
            mCamera.startPreview();
        } catch (IOException e) {
     
            Log.d(TAG, "预览失败");
        }
    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
     
        // Surface发生改变的时候将被调用,第一次显示到界面的时候也会被调用
        if (mHolder.getSurface() == null){
     
            // 如果Surface为空,不继续操作
            return;
        }

        // 停止Camera的预览
        try {
     
            mCamera.stopPreview();

        } catch (Exception e){
     
            Log.d(TAG, "当Surface改变后,停止预览出错");
        }

        // 重新开始预览
        try {
     
            mCamera.setPreviewDisplay(mHolder);
            mCamera.startPreview();

        } catch (Exception e){
     
            Log.d(TAG, "预览Camera出错");
        }
    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
     

    }
}

  1. 添加SurfaceView
 cameraPreview = new CameraPreview(mContext, mCamera);
 diyCameraFyContext.addView(cameraPreview);
  1. 拍摄照片
   mCamera.takePicture(null, null, (data, camera) -> {
     
     Bitmap mbitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
            });
  1. 切换摄像头
Camera.open( Camera.CameraInfo.CAMERA_FACING_FRONT/CAMERA_FACING_BACK);
  1. 打开关闭/闪光灯
  parameters.setFlashMode(Camera.Parameters.FLASH_MODE_TORCH / FLASH_MODE_OFF);
  1. 恢复对焦模式
  mCamera.cancelAutoFocus();
  //恢复对焦模式
  parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
  parameters.setFocusAreas(null);
  mCamera.setParameters(parameters);
  mCamera.startPreview();
  1. 打开、销毁相机节省资源

    @Override
    protected void onDestroy() {
     

        super.onDestroy();
        // 回收Camera资源
        if (mCamera != null) {
     
            mCamera.release();
            mCamera = null;
        }
    }

    @Override
    protected void onResume() {
     
        super.onResume();
        if (mCamera != null) {
     
            mCamera.startPreview();
        }

    }

    @Override
    public void onStop() {
     
        super.onStop();
        if (mCamera != null) {
     
            mCamera.stopPreview();
        }
    }

    /**
     * 停止销毁摄像机
     */
    private void stopCamera() {
     
        if (mCamera != null) {
     
            //停止当前摄像头预览
            mCamera.stopPreview();
            //释放摄像机资源
            mCamera.release();
            mCamera = null;
        }
    }

Github:https://github.com/distantplace-z/BaseTools/blob/master/sample/src/main/java/com/xiaohou/sample/ui/camera/CustomCameraActivity.java

温馨提示:
此文章是基于Camera的在Android SDK 21(LOLLIPOP)以后已经弃用Camera了开始使用Camera2但是那么问题来了我们需不需要根据Android SDK来写对应版本的Camera呢?答案是要滴但是呢有个好消息就是Google出了cameraview解决了我们一大部分问题,但是Camera2是一个很强大的库具体有多强大待博主一探究竟…

你可能感兴趣的:(Android,cameraview,Camera,Android,摄像头,拍照)