Android 自定义Camera相机(封装工具类贼简单)

背景

目前公司的项目都是,针对生物认证来进行一些验证之类的功能,比方说,交互式活体检测,人脸1v1(对比),人脸1vN(搜索)。用系统自带的相机?当然是不够用了,不够用那就自定义啦,就像是前几天七夕,没对象怎么办,当然是new一个了。对了结尾还提供了一个调用极其简单的相机工具类。

了解一下

通常我们调用相机的话,无非就是Intent打开系统自带的相机,要自定义相机的话,也要通过Android框架所提供的API让我们控制相机硬件,来达到我们的需求。

使用API来控制相机我们需要用到关键类和接口:

  • 使用Camera对象来控制相机
  • 使用SurfaceView来展现照相机采集的图像
  • 通过surfaceholder来控制surfac的尺寸和格式,修改surface的像素,监视surface的变化等等
  • 通过SurfaceHolder.Callback 接口,监听surface状态变化

Camera类
//判断是否存在相机硬件

FEATURE_CAMERA : 后置相机 
FEATURE_CAMERA_FRONT : 前置相机

PackageManager pm = getPackageManager();
boolean hasACamera = pm.hasSystemFeature(PackageManager.FEATURE_CAMERA);

//打开相机

camera = Camera.open();//默认打开后置相机
camera = Camera.open(0);//也可传递参数打开指定相机 0为后置 1为前置

//设置相机参数

Camera.Parameters parameters = camera.getParameters();//得到摄像头的参数
parameters.setJpegQuality(100);//设置照片的质量
parameters.setPreviewSize(640,480);//设置预览尺寸
parameters.setPictureSize(640,480);//设置照片尺寸
parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);// 连续对焦模式
//Camera.Parameters.FOCUS_MODE_AUTO; //自动聚焦模式
//Camera.Parameters.FOCUS_MODE_INFINITY;//无穷远
//Camera.Parameters.FOCUS_MODE_MACRO;//微距
//Camera.Parameters.FOCUS_MODE_FIXED;//固定焦距
camera.setParameters(parameters);

//设置相机旋转角度

//有些手机上面会出现旋转90度的情况(Android兼容性问题)所以我们要在这里适配一下
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;
        } else {
            // 后置摄像头
            result = (info.orientation - degrees + 360) % 360;
        }
        camera.setDisplayOrientation(result);

//开始预览以及结束预览

camera.setPreviewDisplay(surfaceHolder);//通过SurfaceView显示取景画面
camera.startPreview();//开始预览

camera.stopPreview();//结束预览
camera.release();

//拍照

camera.takePicture(null, null, new Camera.PictureCallback() {
    @Override
    public void onPictureTaken(byte[] data, Camera camera) {
        //拍照 byte数据即是照取的图片 可以直接转换成bitmap
        //此方法只会调用一次 建议写在点击事件中
        Bitmap mbitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
    }
});

//获取实时的照相机数据

camera.setPreviewCallback(new Camera.PreviewCallback() {
    @Override
    public void onPreviewFrame(byte[] data, Camera camera) {
        //这里byte数据即是实时获取的帧数据 只要相机正在预览就会一直回调此方法
        //需要注意的是 这里的byte数据不能够直接使用 需要转换下格式
        Bitmap bmp = null;
        try {
            YuvImage image = new YuvImage(bytes, ImageFormat.NV21, 640, 480, null);
            if (image != null) {
                ByteArrayOutputStream stream = new ByteArrayOutputStream();
                image.compressToJpeg(new Rect(0, 0, 640, 480), 80, stream);
                bmp = BitmapFactory.decodeByteArray(stream.toByteArray(), 0, stream.size());
                stream.close();
            }
       } catch (Exception ex) {
            Log.e("Sys", "Error:" + ex.getMessage());
       }
    }
});

SurfaceView 控件

//获取SurfaceHolder对象
SurfaceHolder mSurfaceHolder = mSurfaceView.getHolder();
// 设置 Surface 格式
// 参数: PixelFormat中定义的 int 值 ,详细参见 PixelFormat.java
mSurfaceHolder.setFormat(PixelFormat.TRANSPARENT);
//保持屏幕常亮(可选)
mSurfaceHolder.setKeepScreenOn(true);
// 添加 Surface 的 callback 接口
mSurfaceHolder.addCallback(new SurfaceHolder.Callback() {
    @Override
    public void surfaceCreated(SurfaceHolder surfaceHolder) {
        //在 Surface 首次创建时被立即调用:获得焦点时。一般在这里开启相机预览
    }

    @Override
    public void surfaceChanged(SurfaceHolder surfaceHolder, int format, int width, int height) {
        //在 Surface 格式 和 大小发生变化时会立即调用,可以在这个方法中更新 Surface
    }
    @Override
    public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
        //在 Surface 被销毁时立即调用:失去焦点时。一般在这里将相机预览停止销毁
    }
});

完整的CameraActivity

public class CameraActivity extends BaseActivity{

    private Camera camera;
    private SurfaceView mSurfaceView;
    private boolean isPreview = false;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_camera);

        mSurfaceView = findViewById(R.id.sv);
        // 获得 SurfaceHolder 对象
        SurfaceHolder mSurfaceHolder = mSurfaceView.getHolder();

        // 设置 Surface 格式
        // 参数: PixelFormat中定义的 int 值 ,详细参见 PixelFormat.java
        mSurfaceHolder.setFormat(PixelFormat.TRANSPARENT);

        // 如果需要,保持屏幕常亮
        mSurfaceHolder.setKeepScreenOn(true);

        // 添加 Surface 的 callback 接口
        mSurfaceHolder.addCallback(mSurfaceCallback);

        findViewById(R.id.btn_camera).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                camera.takePicture(null, null, new Camera.PictureCallback() {
                    @Override
                    public void onPictureTaken(byte[] data, Camera camera) {
                        //进行拍照操作
                    }
                });
            }
        });
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if(camera != null) {
            camera.release();
        }
        finish();
    }

    private SurfaceHolder.Callback mSurfaceCallback = new SurfaceHolder.Callback() {

        @Override
        public void surfaceCreated(SurfaceHolder surfaceHolder) {
            try {
                // Camera,open() 默认返回的后置摄像头信息
                camera = Camera.open();
                //此处也可以设置摄像头参数
                Camera.Parameters parameters = camera.getParameters();//得到摄像头的参数
                parameters.setJpegQuality(100);//设置照片的质量
                parameters.setPreviewSize(1920,1080);//设置预览尺寸
                parameters.setPictureSize(1920,1080);//设置照片尺寸
                parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);// 连续对焦模式
                camera.setParameters(parameters);

                //设置角度,此处 CameraId 我默认 为 0 (后置)
                // CameraId 也可以 通过 参考 Camera.open() 源码 方法获取
                setCameraDisplayOrientation(CameraActivity.this,0,camera);
                camera.setPreviewDisplay(surfaceHolder);//通过SurfaceView显示取景画面
                camera.startPreview();//开始预览
                isPreview = true;//设置是否预览
            } catch (IOException e) {
                Log.e("surfaceCreated", e.toString());
            }
        }

        @Override
        public void surfaceChanged(SurfaceHolder surfaceHolder, int format, int width, int height) {

        }

        @Override
        public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
            if(camera != null){
                if(isPreview){//正在预览
                    camera.stopPreview();
                    camera.release();
                }
            }
        }
    };

    /**
     * 设置 摄像头的角度
     * @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);
    }
}

别忘了添加权限

<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" />

极其简单的相机工具类

//首先在布局中注册控件

<com.yxq.camera.CameraPreview
        android:id="@+id/cp"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

//然后在你想打开相机的地方

//找到控件
CameraPreview cp = findViewById(R.id.cp);
CameraUtil.INSTANCE.setPreviewView(cp);//设置预览控件
//设置预览监听
CameraUtil.INSTANCE.setOnCameraListener(new OnCameraListener() {
    @Override
    public void onCameraDataFetched(byte[] bytes) {
        //实时获取相机数据
    }

    @Override
    public void onError(CameraError cameraError) {
        //打开相机错误
    }
});

是不是极其简单,跟上边的一比,我都不明白我为什么要写上边的东西。。。。。
相机jar包的下载地址:https://download.csdn.net/download/qq_38001118/10615455
如果有什么扩展的需求或者我有什么遗失和错误欢迎评论,我会第一时间回复和更新。

猜你喜欢

转载自blog.csdn.net/qq_38001118/article/details/81871564
今日推荐