注册

CameraX 入门食用方法

CameraX 已经发布了 1.0正式版 对于涉及到使用摄像头的 App , 能否充分利用摄像头有着很大的区别,为此 对 CameraX 进行了解与认知有一定的必要性.

📑即将学会

用 Jetpack 组件支持库 CameraX 创建相机、拍摄、预览

⭕要求

Google官方声明 CameraX 是 Jetpack组件支持库,帮助我们简化相机相关应用的开发工作。并且提供了一致且易用的 API 接口,适用于大多数 Android 设备,并向后兼容至 Android 5.0(API 级别 21)

因此 创建Android应用的时候mininumSDK 需要选择5.0

前置内容

使用 Intent 进行拍照

在应用中拍照的最简便的方法便是使用MediaStore.ACTION_IMAGE_CAPTURE,传入Intent并启动

image.png 这会启动系统照相机,并为用户提供一套完整的拍照功能 这时,如果用户授予了用户拍照权限,并对拍照图片满意,我们将在onActivityResult中获取图片.默认情况下,拍摄的照片会以缩略图的形式返回,使用键data可以获得缩略图

Bundle extras = data.getExtras();
Bitmap imageBitmap = (Bitmap) extras.get("data");

而要获取完整图片,需要在启动相机的Intent中,在intent的意图中,添加MediaStore.EXTRA_OUTPUT 参数中设置文件的输出URI,该URI会存储完整的照片

image.png 存储后进行完整图片路径后的图片 并进行设置 该存储设置有一定的局限性,请参考官方对拍照的操作 拍照  |  Android 开发者  |  Android Developers (google.cn)image.png 这是我们日常中会使用到的一些摄像头获取图片的操作. 而在开发过程中,我们对camera2的API使用时还是会有很多脏代码,而CameraX作为Google推出的jetpack组件.简化了对Camera的开发,让我们看看如何使用CameraX

实战

创建项目

image.png

在 App 模块中添加 CameraX 依赖 并同步

image.png

使用 PreviewView 实现 CameraX 预览

1.修改布局文件 布局中添加 PreviewView

在布局文件中进行修改 image.png

Manifest声明相机权限
<uses-permission android:name="android.permission.CAMERA" />
动态申请相机权限
//覆写onRequestPermissionsResult()方法 
override fun onRequestPermissionsResult(
requestCode: Int, permissions: Array<String>, grantResults: IntArray) {
if (requestCode == REQUEST_CODE_PERMISSIONS) {
if (allPermissionsGranted()) {
startCamera()
} else {
Toast.makeText(this,
"权限未得到用户授予",
Toast.LENGTH_SHORT).show()
finish()
}
}
2.请求 ProcessCameraProvider

ProcessCameraProvider是一个单例 用于将相机的生命周期绑定到应用程序进程中的任何 生命周期持有者。因为cameraX具有生命周期感应 这可以使我们的应用程序省去打开和关闭相机的任务

val cameraProviderFuture = ProcessCameraProvider.getInstance(this)
3.检查 ProcessCameraProvider 可用性
cameraProviderFuture.addListener(Runnable {}, ContextCompat.getMainExecutor(this))
4.ProcessCameraProvider可用后 选择相机并绑定生命周期和用例
  • 创建 Preview
  • 指定所需的相机
  • 将所选相机和任意用例绑定到生命周期
  • 将 Preview 连接到 PreviewView
 cameraProviderFuture.addListener(Runnable {
// 1将camera 绑定到 生命周期持有者
val cameraProvider: ProcessCameraProvider = cameraProviderFuture.get()

// 2创建 Preview。
val preview = Preview.Builder()
.build()
.also {
//preview 连接 previewView
it.setSurfaceProvider(findViewById<PreviewView>(R.id.viewFinder).getSurfaceProvider())
}

//3指定所需的相机
val cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA

try {
// 4绑定前解绑
cameraProvider.unbindAll()

// 5绑定用户用例和相机到生命周期
cameraProvider.bindToLifecycle(
this, cameraSelector, preview)

} catch(exc: Exception) {
Log.e(TAG, "Use case binding failed", exc)
}

}, ContextCompat.getMainExecutor(this))

效果图

image.png

这是camera的预览功能

cameraX相片拍摄

配置应用拍摄图片
  • 利用 ImageCapture.Builder 构建 imageCapture
  • 绑定用户用例和相机到生命周期 多了一个 imageCapture
cameraProvider.bindToLifecycle(this, cameraSelector, preview, imageCapture)
拍照
  • 获取对 ImageCapture 用例的引用
  • 创建图片存储容纳文件
  • 创建OutputFileOptions指定输出方式 输出路径等内容
val outputFileOptions = ImageCapture.OutputFileOptions.Builder(File(...)).build()
  • 对 imageCapture 对象调用 takePicture()方法。传入刚才构建的 outputOptions 以及保存图片的回调

最终修改代码

cameraProviderFuture.addListener(Runnable {
// 1将camera 绑定到 生命周期持有者
val cameraProvider: ProcessCameraProvider = cameraProviderFuture.get()

// 2创建 Preview。
val preview = Preview.Builder()
.build()
.also {
//preview 连接 previewView
it.setSurfaceProvider(findViewById<PreviewView>(R.id.viewFinder).getSurfaceProvider())
}
//todo 新增行
//图像捕获 构建
imageCapture = ImageCapture.Builder()
.build()

//3指定所需的相机
val cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA

try {
// 4绑定前解绑
cameraProvider.unbindAll()

//todo 新增修改行
// 5绑定用户用例和相机到生命周期
cameraProvider.bindToLifecycle(
this, cameraSelector, preview, imageCapture)

} catch(exc: Exception) {
Log.e(TAG, "Use case binding failed", exc)
}

}, ContextCompat.getMainExecutor(this))


private fun takePhoto() {
// 获取图像捕获用例
val imageCapture = imageCapture ?: return


// 创建存储文件对象
val photoFile = File(
outputDirectory,
SimpleDateFormat(FILENAME_FORMAT, Locale.CHINA
).format(System.currentTimeMillis()) + ".jpg")

// 输出条件构建
val outputOptions = ImageCapture.OutputFileOptions.Builder(photoFile).build()

// 拍照 传入输出条件 以及拍照回调
imageCapture.takePicture(
outputOptions, ContextCompat.getMainExecutor(this), object : ImageCapture.OnImageSavedCallback {
override fun onError(exc: ImageCaptureException) {
//异常打印
Log.e(TAG, "拍照失败: ${exc.message}", exc)
}

override fun onImageSaved(output: ImageCapture.OutputFileResults) {
val savedUri = Uri.fromFile(photoFile)
val msg = "拍照成功: $savedUri"
Toast.makeText(baseContext, msg, Toast.LENGTH_SHORT).show()
Log.d(TAG, msg)
}
})
}

运行展示

image.png


0 个评论

要回复文章请先登录注册