• Android的camerax预览拍照


    前面讲了,camera1和camera2的简单使用。从前文可以看出来,API 的调用还是比较繁琐的,而且像一些最佳尺寸,角度等还得自己算。由于camera1支持的特性很少,camera2流程又很繁琐,google 也意识到这个问题,所以推出了 Camerax。它虽然底层也是利用了 Camera2 的功能,但它的使用却更加简洁,它的主要优势如下:

    • 更加简洁的 API 调用,基本十几行代码就能实现预览
    • Camerax 为 Jetpack 的支持库,所以也具备感知生命周期的功能,即你无需自己释放 生命周期
    • 更好兼容性
    • 更多功能,比如图片分析等

    注意,Camerax 也只支持 API21 及以上。

    本文也仅展示怎么预览和拍照,其他功能可以参照Android开发者官网。代码非常简单,如下:

    首先,添加关联库:

    1. def camerax_version = "1.0.0-beta06"
    2. // CameraX 核心库
    3. implementation "androidx.camera:camera-camera2:$camerax_version"
    4. // CameraX 生命周期
    5. implementation "androidx.camera:camera-lifecycle:$camerax_version"
    6. // CameraX view 集合,比如 cameraview,preview等
    7. implementation "androidx.camera:camera-view:1.0.0-alpha10"

    权限

    1. <uses-permission android:name="android.permission.CAMERA" />
    2. <uses-feature android:name="android.hardware.camera.any" />

    预览

     xml布局:

    1. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    2. xmlns:app="http://schemas.android.com/apk/res-auto"
    3. xmlns:tools="http://schemas.android.com/tools"
    4. android:layout_width="match_parent"
    5. android:layout_height="match_parent"
    6. tools:context=".FullScreenClipActivity">
    7. <androidx.camera.view.PreviewView
    8. android:id="@+id/pv"
    9. android:layout_width="match_parent"
    10. android:layout_height="match_parent"/>
    11. RelativeLayout>

    通过

      ListenableFuture cameraProviderFuture = ProcessCameraProvider.getInstance(this);
    

    返回当前可以绑定生命周期的 ProcessCameraProvider,ProcessCameraProvider 它会和宿主绑定生命周期,这样就不用担心打开相机和关闭的问题了。

    接着,向 cameraProviderFuture 注册一个监听,第一个参数是一个 runnable,第二个参数是线程池,即runnable 运行在哪个线程中:

    cameraProviderFuture.addListener(Runnable {}, ContextCompat.getMainExecutor(this))
    

    上面我们让它运行在主线程的线程池中,这样,在这个 runnable 中,就可以配置我们的 capture 了,代码如下:

    1. mViewFinder = findViewById(R.id.pv);
    2. //创建相机进程监听
    3. ListenableFuture cameraProviderFuture = ProcessCameraProvider.getInstance(this);
    4. cameraProviderFuture.addListener(new Runnable() {
    5. @SuppressLint("RestrictedApi")
    6. @Override
    7. public void run() {
    8. try {
    9. //将相机的生命周期和activity的生命周期绑定,camerax 会自己释放,不用担心了
    10. ProcessCameraProvider cameraProvider = cameraProviderFuture.get();
    11. //预览的 capture,它里面支持角度换算
    12. Preview preview = new Preview.Builder().build();
    13. //创建图片的 capture
    14. mImageCapture = new ImageCapture.Builder()
    15. .setFlashMode(ImageCapture.FLASH_MODE_AUTO)
    16. .build();
    17. //选择后置摄像头
    18. CameraSelector cameraSelector = new CameraSelector.Builder().requireLensFacing(CameraSelector.LENS_FACING_BACK).build();
    19. //预览之前先解绑
    20. cameraProvider.unbindAll();
    21. //将数据绑定到相机的生命周期中
    22. Camera camera = cameraProvider.bindToLifecycle(CameraxActivity.this, cameraSelector, preview, mImageCapture);
    23. //将previewview 的 surface 给相机预览
    24. preview.setSurfaceProvider(mViewFinder.createSurfaceProvider(camera.getCameraInfo()));
    25. } catch (Exception e) {
    26. e.printStackTrace();
    27. }
    28. }
    29. },ContextCompat.getMainExecutor(this));

    创建并确认 CameraProvider 后,执行步骤如下

    • 创建 Preview,使用 new Preview.Builder().build() 创建Preview,它是相机预览的数据流,图像数据会通过它来输出,比如输出到 Surface 中
    • 创建 ImageCapture 用于拍照,这里的 builder 都可以设置参数,比如大小,曝光等
    • 指定所需的相机 LensFacing 选项,这里直接使用后置即可
    • 将所选相机和任意用例绑定到生命周期,通过 cameraProvider.bindToLifecycle,将宿主的生命周期,与 cameraSelector,preview和mImageCapture判定起来。
    • 将 Preview 连接到 PreviewView,preview.setSurfaceProvider() 设置要预览的 surface

    拍照

    上面已经设置了 mImageCapture,拍照在 Camerax 中也很简单,使用 takePicture 即可,如下

    1. public void takePhoto(View view) {
    2. if (mImageCapture != null) {
    3. File dir = new File(Constants.PATH);
    4. if (!dir.exists()) {
    5. dir.mkdirs();
    6. }
    7. //创建文件
    8. File file = new File(Constants.PATH,"testx.jpg");
    9. if (file.exists()) {
    10. file.delete();
    11. }
    12. //创建包文件的数据,比如创建文件
    13. ImageCapture.OutputFileOptions outputFileOptions = new ImageCapture.OutputFileOptions.Builder(file).build();
    14. //开始拍照
    15. mImageCapture.takePicture(outputFileOptions, ContextCompat.getMainExecutor(this), new ImageCapture.OnImageSavedCallback() {
    16. @Override
    17. public void onImageSaved(@NonNull ImageCapture.OutputFileResults outputFileResults) {
    18. // Uri savedUri = outputFileResults.getSavedUri();
    19. Toast.makeText(CameraxActivity.this, "保存成功: ", Toast.LENGTH_SHORT).show();
    20. }
    21. @Override
    22. public void onError(@NonNull ImageCaptureException exception) {
    23. Toast.makeText(CameraxActivity.this, "保存失败", Toast.LENGTH_SHORT).show();
    24. }
    25. });
    26. }
    27. }

    注释已经很清楚了,注意我们可以使用 ImageCapture.OutputFileOptions 让 Camerax 去帮我们保存图片文件。

  • 相关阅读:
    秒杀同龄人的顶级复盘能力,坚持1年,领先5年!
    基于JAVA药房管理系统计算机毕业设计源码+系统+数据库+lw文档+部署
    tensor.eq() tensor.item() tensor.argmax()
    方舟生存进化服务器怎么开?方舟生存进化架设服务器教程
    Golang 中的字符串:常见错误和最佳实践
    多项式算法6:分治 FFT
    考研人考研魂——英语单词篇(20231010)
    计算机网络-网络互连与互联网(三)
    树莓派raspberry pi 4 SSH默认密码无法登录解决办法
    springBoot + Hikari 配置多数据源连接数据库
  • 原文地址:https://blog.csdn.net/Jason_Lee155/article/details/126341488