如何在使用 Camera X 库捕获图像后自动旋转图像?
how to automatically rotate the image after capturing image using Camera X library?
我是使用相机 X 库的新手。我正在尝试关注 here
中 Google 的代码实验室
我可以显示预览并捕获图像。但问题是......
当我拍摄横向图像时,图像结果仍为纵向。我想让它自动旋转。如果我拍摄横向图像,那么结果应该是横向的,如果我拍摄纵向图像,那么结果应该是纵向的。就像 'Camera' 应用程序
中的相机
怎么做?
我用的是红米Note 7,Android10.
我用的gradle:
implementation "androidx.camera:camera-camera2:1.0.0-beta11"
implementation "androidx.camera:camera-lifecycle:1.0.0-beta11"
implementation "androidx.camera:camera-view:1.0.0-alpha18"
这是我用来显示预览和捕获图像的代码
class CameraFragment : Fragment() {
private var imageCapture: ImageCapture? = null
private lateinit var outputDirectory: File
private lateinit var cameraExecutor: ExecutorService
private var cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA
companion object {
private const val TAG = "CameraFragment"
private const val FILENAME_FORMAT = "yyyy-MM-dd-HH-mm-ss-SSS"
private const val CAMERA_REQUEST_CODE_PERMISSIONS = 10
}
lateinit var mContext : Context
lateinit var mActivity : FragmentActivity
override fun onAttach(context: Context) {
super.onAttach(context)
mContext = context
activity?.let { mActivity = it }
}
private fun getOutputDirectory(): File {
val mediaDir = mActivity.externalMediaDirs.firstOrNull()?.let {
File(it, resources.getString(R.string.app_name)).apply { mkdirs() }
}
return if (mediaDir != null && mediaDir.exists())
mediaDir else mActivity.filesDir
}
private fun startCamera() {
val cameraProviderFuture = ProcessCameraProvider.getInstance(mContext)
cameraProviderFuture.addListener(Runnable {
// Used to bind the lifecycle of cameras to the lifecycle owner
val cameraProvider: ProcessCameraProvider = cameraProviderFuture.get()
// Preview
val preview = Preview.Builder()
.build()
.also {
it.setSurfaceProvider(previewView.surfaceProvider)
}
imageCapture = ImageCapture.Builder().build()
try {
// Unbind use cases before rebinding
cameraProvider.unbindAll()
// Bind use cases to camera
cameraProvider.bindToLifecycle(
this, cameraSelector, preview, imageCapture)
} catch (exc: Exception) {
Log.e(TAG, "Use case binding failed", exc)
}
}, ContextCompat.getMainExecutor(mContext))
}
private fun takePhoto() {
// Get a stable reference of the modifiable image capture use case
val imageCapture = imageCapture ?: return
// Create time-stamped output file to hold the image
val photoFile = File(
outputDirectory,
SimpleDateFormat(FILENAME_FORMAT, Locale.US
).format(System.currentTimeMillis()) + ".jpg")
// Create output options object which contains file + metadata
val outputOptions = ImageCapture.OutputFileOptions.Builder(photoFile).build()
// Set up image capture listener, which is triggered after photo has
// been taken
imageCapture.takePicture(outputOptions, ContextCompat.getMainExecutor(mContext), object : ImageCapture.OnImageSavedCallback {
override fun onError(exc: ImageCaptureException) {
Log.d("agungxxx", "2: ${exc.localizedMessage}")
Log.e(TAG, "Photo capture failed: ${exc.message}", exc)
}
override fun onImageSaved(output: ImageCapture.OutputFileResults) {
cameraSharedViewModel.sendImageUriPathToPreviousDestination(photoFile)
findNavController().navigateUp()
}
})
}
}
捕获图像的旋转取决于 ImageCapture
用例的 the target rotation。默认情况下,当应用程序未设置时,它等于 Display.getRotation()
,其中 Display
是创建 ImageCapture
用例时的默认显示。
这意味着您需要在每次显示方向发生变化时更新 ImageCapture
的目标旋转,例如当设备从纵向旋转到横向时。
我假设您的 activity 方向已锁定 (?)。在这种情况下,您可以使用 OrientationEventListener
来持续获取设备旋转的更新,然后相应地更新用例的目标旋转。
val orientationEventListener = object : OrientationEventListener(this) {
override fun onOrientationChanged(orientation: Int) {
if (orientation == OrientationEventListener.UNKNOWN_ORIENTATION) {
return
}
val rotation = when (orientation) {
in 45 until 135 -> Surface.ROTATION_270
in 135 until 225 -> Surface.ROTATION_180
in 225 until 315 -> Surface.ROTATION_90
else -> Surface.ROTATION_0
}
imageCapture.targetRotation = rotation
}
}
当 Activity 的生命周期为 started/stopped 时,您应该 start/stop orientationEventListener
,这也与相机的 started/stopped 相匹配。你可以看到这个 here.
的例子
您还可以了解有关 CameraX 的用例和旋转的更多信息in the official documentation。
我是使用相机 X 库的新手。我正在尝试关注 here
中 Google 的代码实验室我可以显示预览并捕获图像。但问题是......
当我拍摄横向图像时,图像结果仍为纵向。我想让它自动旋转。如果我拍摄横向图像,那么结果应该是横向的,如果我拍摄纵向图像,那么结果应该是纵向的。就像 'Camera' 应用程序
中的相机怎么做?
我用的是红米Note 7,Android10.
我用的gradle:
implementation "androidx.camera:camera-camera2:1.0.0-beta11"
implementation "androidx.camera:camera-lifecycle:1.0.0-beta11"
implementation "androidx.camera:camera-view:1.0.0-alpha18"
这是我用来显示预览和捕获图像的代码
class CameraFragment : Fragment() {
private var imageCapture: ImageCapture? = null
private lateinit var outputDirectory: File
private lateinit var cameraExecutor: ExecutorService
private var cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA
companion object {
private const val TAG = "CameraFragment"
private const val FILENAME_FORMAT = "yyyy-MM-dd-HH-mm-ss-SSS"
private const val CAMERA_REQUEST_CODE_PERMISSIONS = 10
}
lateinit var mContext : Context
lateinit var mActivity : FragmentActivity
override fun onAttach(context: Context) {
super.onAttach(context)
mContext = context
activity?.let { mActivity = it }
}
private fun getOutputDirectory(): File {
val mediaDir = mActivity.externalMediaDirs.firstOrNull()?.let {
File(it, resources.getString(R.string.app_name)).apply { mkdirs() }
}
return if (mediaDir != null && mediaDir.exists())
mediaDir else mActivity.filesDir
}
private fun startCamera() {
val cameraProviderFuture = ProcessCameraProvider.getInstance(mContext)
cameraProviderFuture.addListener(Runnable {
// Used to bind the lifecycle of cameras to the lifecycle owner
val cameraProvider: ProcessCameraProvider = cameraProviderFuture.get()
// Preview
val preview = Preview.Builder()
.build()
.also {
it.setSurfaceProvider(previewView.surfaceProvider)
}
imageCapture = ImageCapture.Builder().build()
try {
// Unbind use cases before rebinding
cameraProvider.unbindAll()
// Bind use cases to camera
cameraProvider.bindToLifecycle(
this, cameraSelector, preview, imageCapture)
} catch (exc: Exception) {
Log.e(TAG, "Use case binding failed", exc)
}
}, ContextCompat.getMainExecutor(mContext))
}
private fun takePhoto() {
// Get a stable reference of the modifiable image capture use case
val imageCapture = imageCapture ?: return
// Create time-stamped output file to hold the image
val photoFile = File(
outputDirectory,
SimpleDateFormat(FILENAME_FORMAT, Locale.US
).format(System.currentTimeMillis()) + ".jpg")
// Create output options object which contains file + metadata
val outputOptions = ImageCapture.OutputFileOptions.Builder(photoFile).build()
// Set up image capture listener, which is triggered after photo has
// been taken
imageCapture.takePicture(outputOptions, ContextCompat.getMainExecutor(mContext), object : ImageCapture.OnImageSavedCallback {
override fun onError(exc: ImageCaptureException) {
Log.d("agungxxx", "2: ${exc.localizedMessage}")
Log.e(TAG, "Photo capture failed: ${exc.message}", exc)
}
override fun onImageSaved(output: ImageCapture.OutputFileResults) {
cameraSharedViewModel.sendImageUriPathToPreviousDestination(photoFile)
findNavController().navigateUp()
}
})
}
}
捕获图像的旋转取决于 ImageCapture
用例的 the target rotation。默认情况下,当应用程序未设置时,它等于 Display.getRotation()
,其中 Display
是创建 ImageCapture
用例时的默认显示。
这意味着您需要在每次显示方向发生变化时更新 ImageCapture
的目标旋转,例如当设备从纵向旋转到横向时。
我假设您的 activity 方向已锁定 (?)。在这种情况下,您可以使用 OrientationEventListener
来持续获取设备旋转的更新,然后相应地更新用例的目标旋转。
val orientationEventListener = object : OrientationEventListener(this) {
override fun onOrientationChanged(orientation: Int) {
if (orientation == OrientationEventListener.UNKNOWN_ORIENTATION) {
return
}
val rotation = when (orientation) {
in 45 until 135 -> Surface.ROTATION_270
in 135 until 225 -> Surface.ROTATION_180
in 225 until 315 -> Surface.ROTATION_90
else -> Surface.ROTATION_0
}
imageCapture.targetRotation = rotation
}
}
当 Activity 的生命周期为 started/stopped 时,您应该 start/stop orientationEventListener
,这也与相机的 started/stopped 相匹配。你可以看到这个 here.
您还可以了解有关 CameraX 的用例和旋转的更多信息in the official documentation。