根据官方文档学习CameraX的基础拍照功能
前言
记录使用Camera X时的用例
- 预览
- 图片拍摄
- 图片分析
- 视频拍摄
一、实现预览
在向应用添加预览时,请使用 PreviewView,这是一种可以剪裁、缩放和旋转以确保正确显示的 View
。
当相机处于活动状态时,图片预览会流式传输到 PreviewView
中的 Surface。
1.使用 PreviewView
使用 PreviewView
实现 CameraX 预览,请按以下步骤操作
- 可选)配置 CameraXConfig.Provider
- 将
PreviewView
添加到布局 - 请求 ProcessCameraProvider
- 在创建
View
时,请检查ProcessCameraProvider
- 选择相机并绑定生命周期和用例
tips:使用 PreviewView
存在一些限制。使用 PreviewView
时,您无法执行以下任何操作:
- 创建
SurfaceTexture
,以在TextureView
和 Preview.SurfaceProvider 上进行设置。 - 从
TextureView
检索SurfaceTexture
,并在Preview.SurfaceProvider
上对其进行设置。 - 从
SurfaceView
获取Surface
,并在Preview.SurfaceProvider
上对其进行设置。
如果出现上述任何一种情况,Preview
就会停止将帧流式传输到 PreviewView
。
下面根据步骤实现预览功能,代码如下:
1.将 PreviewView 添加到布局:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.camera.view.PreviewView
android:id="@+id/previewView"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</FrameLayout>
代码中有注释 ,就这样简单实现预览的功能:
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
private lateinit var cameraProviderFuture: ListenableFuture<ProcessCameraProvider>
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
//1.请求 CameraProvider
cameraProviderFuture = ProcessCameraProvider.getInstance(this)
//2.检查 CameraProvider 可用性
cameraProviderFuture.addListener(Runnable {
val cameraProvider = cameraProviderFuture.get()
bindPreview(cameraProvider)
}, ContextCompat.getMainExecutor(this))
}
/**
* 选择相机并绑定生命周期和用例
*/
private fun bindPreview(cameraProvider: ProcessCameraProvider) {
//创建 Preview
var preview: Preview = Preview.Builder().build()
//指定所需的相机 LensFacing 选项
var cameraSelector: CameraSelector = CameraSelector.Builder().requireLensFacing(
CameraSelector.LENS_FACING_BACK
).build()
//将所选相机和任意用例绑定到生命周期。
preview.setSurfaceProvider(binding.previewView.surfaceProvider)
//将 Preview 连接到 PreviewView。并返回一个Camera对象
var camera = cameraProvider.bindToLifecycle(this as LifecycleOwner, cameraSelector, preview)
}
}
二、图片拍摄
- 相机手动控制功能
- 自动白平衡
- 自动曝光
- 自动对焦 (3A) 功能
调用方负责决定如何使用拍摄的照片,具体包括以下选项:
- takePicture(Executor, OnImageCapturedCallback):此方法为拍摄的图片提供内存缓冲区。
- takePicture(OutputFileOptions, Executor, OnImageSavedCallback):此方法将拍摄的图片保存到提供的文件位置。
运行 ImageCapture
的可自定义执行程序有两种类型:回调执行程序和 IO 执行程序。
- 回调执行程序是
takePicture
方法的参数。它用于执行用户提供的 OnImageCapturedCallback()。 - 如果调用方选择将图片保存到文件位置,您可以指定执行程序以执行 IO。如需设置 IO 执行程序,请调用 ImageCapture.Builder.setIoExecutor(Executor)。如果执行程序不存在,则默认 CameraX 为任务的内部 IO 执行程序。
1.拍照
代码如下(示例):
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
private lateinit var cameraProviderFuture: ListenableFuture<ProcessCameraProvider>
private var imageCapture: ImageCapture? = null
private lateinit var cameraExecutor: ExecutorService
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
cameraExecutor = Executors.newSingleThreadExecutor()
//1.请求 CameraProvider
cameraProviderFuture = ProcessCameraProvider.getInstance(this)
//2.检查 CameraProvider 可用性
cameraProviderFuture.addListener(Runnable {
val cameraProvider = cameraProviderFuture.get()
bindPreview(cameraProvider)
}, ContextCompat.getMainExecutor(this))
binding.cameraCaptureButton.setOnClickListener {
val name = SimpleDateFormat("yyyy-MM-dd-HH-mm-ss-SSS", Locale.CHINA)
.format(System.currentTimeMillis())
val contentValues = ContentValues().apply {
put(MediaStore.MediaColumns.DISPLAY_NAME, name)
put(MediaStore.MediaColumns.MIME_TYPE, "image/jpeg")
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.P) {
val appName = "app-name"
put(MediaStore.Images.Media.RELATIVE_PATH, "Pictures/${appName}")
}
}
val outputOptions = ImageCapture.OutputFileOptions.Builder(
contentResolver,
MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
contentValues
).build()
imageCapture?.takePicture(outputOptions, cameraExecutor,
object : ImageCapture.OnImageSavedCallback {
override fun onError(error: ImageCaptureException) {
// insert your code here.
Log.e("onError: ", "onError")
}
override fun onImageSaved(outputFileResults: ImageCapture.OutputFileResults) {
// insert your code here.
Log.e( "onImageSaved: ", "onImageSaved")
}
})
}
}
/**
* 选择相机并绑定生命周期和用例
*/
private fun bindPreview(cameraProvider: ProcessCameraProvider) {
//创建 Preview
var preview: Preview = Preview.Builder().build()
//指定所需的相机 LensFacing 选项
var cameraSelector: CameraSelector = CameraSelector.Builder().requireLensFacing(
CameraSelector.LENS_FACING_BACK
).build()
preview.setSurfaceProvider(binding.previewView.surfaceProvider)
imageCapture = ImageCapture.Builder()
.setTargetRotation(binding.previewView.display.rotation)
.build()
val imageAnalyzer = ImageAnalysis.Builder().build()
//将所选相机和任意用例绑定到生命周期。
cameraProvider.bindToLifecycle(
this as LifecycleOwner,
cameraSelector,
imageCapture,
imageAnalyzer,
preview
)
}
}