Android调用系统Camera硬件完成拍照

通常情况下我们都会用Intent直接跳转到系统相机里面进行拍照,然后在回调里面处理回传的图片;但是如果android底层源码被改写,取消了系统的相机我们要怎么办?

今天来记录一下,在Android中通过调用系统的Camera硬件来完成拍照功能。

首先绘制拍照界面的布局

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".CameraActivity">
    <FrameLayout
        android:id="@+id/camera_preview"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
        <SurfaceView
            android:id="@+id/surface_view"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />
    </FrameLayout>
    <Button
        android:id="@+id/button_capture"
        android:layout_width="60dp"
        android:layout_height="wrap_content"
        android:text="拍照"
        android:layout_alignParentBottom="true"
        android:layout_centerHorizontal="true"
        />

</RelativeLayout>

在Activity中封装打开相机硬件的方法

/**
 * 打开一个Camera
 */
public static Camera getCameraInstance() {
    Camera c = null;
    try {
        c = Camera.open();
    } catch (Exception e) {
        Log.d(TAG, "打开Camera失败失败");
    }
    return c;
}

获取一个最为适配屏幕尺寸的Camera尺寸

private Camera.Size getOptimalPreviewSize(List<Camera.Size> sizes, int w, int h) {
    final double ASPECT_TOLERANCE = 0.3;
    double targetRatio = (double) w / h;
    if (sizes == null) return null;

    Camera.Size optimalSize = null;
    double minDiff = Double.MAX_VALUE;

    int targetHeight = h;

    // Try to find an size match aspect ratio and size
    for (Camera.Size size : sizes) {
        double ratio = (double) size.width / size.height;
        if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE) continue;
        if (Math.abs(size.height - targetHeight) < minDiff) {
            optimalSize = size;
            minDiff = Math.abs(size.height - targetHeight);
        }
    }

    // Cannot find the one match the aspect ratio, ignore the requirement
    if (optimalSize == null) {
        minDiff = Double.MAX_VALUE;
        for (Camera.Size size : sizes) {
            if (Math.abs(size.height - targetHeight) < minDiff) {
                optimalSize = size;
                minDiff = Math.abs(size.height - targetHeight);
            }
        }
    }
    return optimalSize;
}

初始化Camera硬件的配置

private void initCamera() {
    Camera.Parameters parameters = mCamera.getParameters();//获取camera的parameter实例
    List<Camera.Size> sizeList = parameters.getSupportedPreviewSizes();//获取所有支持的camera尺寸
    Camera.Size optionSize = getOptimalPreviewSize(sizeList,preview.getWidth(), preview.getHeight());//获取一个最为适配的camera.size
    parameters.setPreviewSize(optionSize.width,optionSize.height);//把camera.size赋值到parameters
    mCamera.setParameters(parameters);//把parameters设置给camera

    mCamera.setDisplayOrientation(0);
}

在Activity的onCreate方法中初始化

         preview = (FrameLayout) findViewById(R.id.camera_preview);
         surfaceView = findViewById(R.id.surface_view);
         surfaceHolder = surfaceView.getHolder();
         surfaceHolder.addCallback(new SurfaceHolder.Callback() {
             @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 (surfaceHolder.getSurface() == null){
                     // 如果Surface为空,不继续操作
                     return;
                 }

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

                 // 在预览前可以指定Camera的各项参数
                 initCamera();
                 // 重新开始预览
                 try {
                     mCamera.setPreviewDisplay(surfaceHolder);
                     mCamera.startPreview();

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

             @Override
             public void surfaceDestroyed(SurfaceHolder holder) {

             }
         });
        mCamera = getCameraInstance();

       initCamera();

下面是拍照按钮的监听

Button captureButton = (Button) findViewById(R.id.button_capture);
captureButton.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        // 在捕获图片前进行自动对焦
        mCamera.autoFocus(new AutoFocusCallback() {

            @Override
            public void onAutoFocus(boolean success, Camera camera) {
                // 从Camera捕获图片
                mCamera.takePicture(null, null, mPicture);
                Toast.makeText(CameraActivity.this,"拍照完成",Toast.LENGTH_SHORT).show();
                finish();
            }
        });
    }
});

下面是监听回调

private PictureCallback mPicture = new PictureCallback() {

    @Override
    public void onPictureTaken(byte[] data, Camera camera) {
        // 获取Jpeg图片,并保存在sd卡上
        Bitmap bitmap =BitmapFactory.decodeByteArray(data,0,data.length);
        File file = new File(Environment.getExternalStorageDirectory(),"camera");
        if (!file.exists()) {
            file.mkdirs();
        }
            String fileName = System.currentTimeMillis()+".jpg";
          final File pictureFile = new File(file,fileName);
          final String strFile = pictureFile.getPath();

        try {
            FileOutputStream fos = new FileOutputStream(pictureFile);
            bitmap.compress(Bitmap.CompressFormat.JPEG, 100, fos);
            fos.flush();
            fos.close();

        } catch (Exception e) {
            Log.d(TAG, "保存图片失败");
        }
    }
};

运行便可以实现拍照功能了

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值