当前位置:   article > 正文

android CameraX构建相机拍照

android CameraX构建相机拍照

Android CameraX 是一个 Jetpack 支持库,旨在简化相机应用的开发工作。它提供了一致且易用的API接口,适用于大多数Android设备,并可向后兼容至Android 5.0(API级别21)。

CameraX解决了在多种设备上实现相机功能时所遇到的兼容性问题,大大减少了需要编写的设备专属代码量。同时,它还通过提供一种基于用例的、具有生命周期感知能力的方式,简化了相机功能的开发。

导入需要的包

    implementation("androidx.camera:camera-core:1.3.4")
    implementation("androidx.camera:camera-camera2:1.3.4")
    implementation("androidx.camera:camera-lifecycle:1.3.4")
    implementation("androidx.camera:camera-video:1.3.4")
    implementation("androidx.camera:camera-view:1.3.4")
  • 1
  • 2
  • 3
  • 4
  • 5

配置简单layout和PhotoActivity

新建一个activity_photo.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:xhead="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#005dd7"
    android:orientation="vertical">
  <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:gravity="center"
        android:layout_margin="20dp"
        android:background="@drawable/shape_common_dialog_bg"
        android:orientation="vertical">

    <androidx.camera.view.PreviewView
        android:layout_width="640dp"
        android:layout_height="600dp"
        android:id="@+id/viewFinder" />

    <Button
        android:layout_marginTop="10dp"
        android:background="@drawable/shape_login_button"
        android:id="@+id/image_capture_button"
        android:layout_width="300dp"
        android:layout_height="wrap_content"
        android:elevation="2dp"
        android:text="拍照" />
</LinearLayout>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
public class PhotoActivity implements View.OnClickListener {

	//图片捕获
   private ImageCapture imageCapture;
	//
    private ProcessCameraProvider cameraProvider;
    
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_photo);
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

请求必要的权限

应用需要获得用户授权才能打开相机。
首先在AndroidManifest.xml中声明
<uses-permission android:name="android.permission.CAMERA" />
所以在onCreate(@Nullable Bundle savedInstanceState)方法中增加:

 protected void onCreate(@Nullable Bundle savedInstanceState){
 String[] permissions = {Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE};
        if (allPermissionsGranted(permissions, this)) {
            startCamera();
        } else {
            ActivityCompat.requestPermissions(this, permissions, REQUEST_CAMERA_PERMISSION);
        }
}
        
        public boolean allPermissionsGranted(String[] permissions, Context context) {
        for (String permission : permissions) {
            int checkSelfPermission = ContextCompat.checkSelfPermission(context, permission);
            if (checkSelfPermission != PackageManager.PERMISSION_GRANTED) {
                ActivityCompat.requestPermissions(this, permissions, REQUEST_CAMERA_PERMISSION);
            }
        }
        return true;
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

当然用户存在不同意的情况,此时可以重写 onRequestPermissionsResult 方法以处理权限请求结果:

 @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        if (requestCode == REQUEST_CAMERA_PERMISSION) {
            if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                // 权限已被授予,可以执行相机相关操作
                startCamera();
            } else {
                // 权限被拒绝,提示用户需要授权
                Toast.makeText(this, "需要相机权限才能使用此功能", Toast.LENGTH_SHORT).show();
            }
        }
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

实现 Preview 用例,开始拍照

我们打开前置摄像头:

 private void startCamera() {
        ListenableFuture<ProcessCameraProvider> cameraProviderFuture = ProcessCameraProvider.getInstance(this);

        cameraProviderFuture.addListener(() -> {
            try {
                cameraProvider = cameraProviderFuture.get();
                //前置摄像头
                CameraSelector cameraSelector = CameraSelector.DEFAULT_FRONT_CAMERA;
                Preview preview = new Preview.Builder().build();

                // 构建预览用例
                preview.setSurfaceProvider(bd.viewFinder.getSurfaceProvider());

                // 构建图片捕获用例
                imageCapture = new ImageCapture.Builder().build();

                // 将用例绑定到相机
                cameraProvider.bindToLifecycle(
                        PersonPhotoActivity.this,
                        cameraSelector,
                        preview,
                        imageCapture);
            } catch (ExecutionException | InterruptedException e) {
                throw new RuntimeException(e);
            }
        }, ContextCompat.getMainExecutor(this));

    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • ListenableFuture cameraProviderFuture = ProcessCameraProvider.getInstance(this); 这行代码的作用是获取一个ProcessCameraProvider的实例,这个实例可以与宿主的生命周期绑定,从而无需手动管理相机的打开和关闭。
  • cameraProviderFuture注册了一个监听器,当cameraProviderFuture完成时,会执行注册的Runnable。在这个Runnable中,首先通过cameraProviderFuture.get()获取到cameraProvider实例。然后,创建一个用于预览的Preview对象,并将其Surface设置到对应的预览界面上。同时,还创建了一个ImageCapture对象用于图片捕获。
  • 使用cameraProvider.bindToLifecycle()方法将相机与当前Activity的生命周期绑定,并指定使用的摄像头、预览、以及图片捕获的配置。这样,相机就会在Activity的生命周期内自动进行资源的申请和释放

在avd虚拟机中显示

配置avd的前置摄像头为虚拟模式:
在这里插入图片描述
启动项目查看页面:
在这里插入图片描述

拍照

当拍照按钮被点击时调用takePhoto 方法,这里我们建立了一个file对象临时保存当前照片,之后我们就可以自由使用该照片:

 @Override
    public void onClick(View view) {
        if (view.getId() == R.id.image_capture_button) {
            takePhoto(view);
        }
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
 private void takePhoto(View view) {
        File file = new File(getContext().getExternalCacheDir() + File.separator + System.currentTimeMillis() + ".png");
        //创建包文件的数据,比如创建文件
        ImageCapture.OutputFileOptions outputFileOptions = new ImageCapture.OutputFileOptions.Builder(file).build();
        //开始拍照
        imageCapture.takePicture(outputFileOptions, ContextCompat.getMainExecutor(this),
                new ImageCapture.OnImageSavedCallback() {
                    @Override
                    public void onImageSaved(@NonNull ImageCapture.OutputFileResults outputFileResults) {
                        // 关闭相机并释放资源
                        cameraProvider.unbindAll();
                        // file.getPath()
						//做业务
						//。。。。
                    }

                    @Override
                    public void onError(@NonNull ImageCaptureException exception) {
                        Log.d(TAG, Objects.requireNonNull(exception.toString()));
                        Toast.makeText(PersonPhotoActivity.this, "照片保存失败", Toast.LENGTH_SHORT).show();
                    }
                });
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

代码分析:

  1. 创建一个ImageCapture.OutputFileOptions对象,用于指定照片的输出选项,这里将照片保存到刚刚创建的File对象中。
  2. 调用imageCapture的takePicture方法开始拍照。传入outputFileOptions作为参数,以及一个回调函数OnImageSavedCallback。
  3. 在OnImageSavedCallback的onImageSaved方法中,当照片成功保存后,关闭相机并释放资源。然后可以进行其他业务操作,如显示照片等。
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/在线问答5/article/detail/806869
推荐阅读
相关标签
  

闽ICP备14008679号