我正在使用CameraX https://developer.android.com/training/camerax拍摄一些图像。但是,我所有的图像都出现了错误的旋转。它们都被标记:ORIENTATION_ROTATE_90
是的,我已检查以确保方向锁定未打开,并且清单中没有任何内容可以锁定屏幕方向,我也没有覆盖任何方向方法。
无论我如何通过模拟器或真实设备对其进行测试,方向似乎都被“锁定”了。唯一正确旋转的图片是设备处于纵向模式时。但是,它仍然被标记为ORIENTATION_ROTATE_90
谁能看到我可能做错了什么?
private var imageCapture: ImageCapture? = null
private lateinit var cameraExecutor: ExecutorService
//.. other methods removed for brievity
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// Request camera permissions
cameraExecutor = Executors.newSingleThreadExecutor()
}
override fun onResume() {
super.onResume()
startCamera()
}
private fun startCamera() {
val cameraProviderFuture = ProcessCameraProvider.getInstance(requireContext())
cameraProviderFuture.addListener({
// 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(binding.cameraPreview.surfaceProvider)
}
imageCapture = Builder().build()
// Doesn't work
// activity?.display.let { d ->
// d.let { imageCapture!!.targetRotation = d!!.rotation }
// }
// Select back camera as a default
val cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA
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(requireContext()))
}
private fun captureImage() {
// Get a stable reference of the modifiable image capture use case
val imageCapture = imageCapture ?: return
// this way the images will stay in order
val id = System.currentTimeMillis().toString()
// Make directory if it doesn't exist, and build a file for the new image to go into
val photoFile = File("${sharedViewModel.fileDirectory}/${id}").apply {
@Suppress("RECEIVER_NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS")
parentFile.mkdirs()
}
// Create output options object which contains file + metadata
val outputOptions = OutputFileOptions.Builder(photoFile).build()
// Set up image capture listener, which is triggered after photo has been taken
imageCapture.takePicture(
outputOptions, ContextCompat.getMainExecutor(requireContext()), object : OnImageSavedCallback {
override fun onError(exc: ImageCaptureException) {
Toast.makeText(requireContext(), "Photo capture failed: ${exc.message}", Toast.LENGTH_LONG).show()
Log.e(TAG, "Photo capture failed: ${exc.message}", exc)
}
override fun onImageSaved(output: OutputFileResults) {
fixRotation(photoFile.path)
}
})
}
private fun fixRotation(imageUri: String) {
val bitmap = File(imageUri)
if (!bitmap.exists()) return
Uri.parse(imageUri)?.let{
CoroutineScope(Dispatchers.IO).launch { spinAndSave(it) }
}
}
private suspend fun spinAndSave(imageURI: Uri) = withContext(Dispatchers.IO) {
val options = BitmapFactory.Options()
options.inPreferredConfig = Bitmap.Config.ARGB_8888
imageURI.path?.let { path ->
ExifInterface(path).getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_UNDEFINED).let { orientation ->
debugOrientation(orientation)
val rotatedBitmap = rotateBitmap( BitmapFactory.decodeFile(path, options), orientation)!!
FileOutputStream(imageURI.path).use { fos ->
rotatedBitmap.compress(Bitmap.CompressFormat.JPEG, 50, fos)
Log.i(TAG,"New Image Saved")
}
}
}
}
private fun debugOrientation(orientation: Int) {
val o = when (orientation) {
ExifInterface.ORIENTATION_NORMAL -> "ORIENTATION_NORMAL"
ExifInterface.ORIENTATION_FLIP_HORIZONTAL -> "ORIENTATION_FLIP_HORIZONTAL"
ExifInterface.ORIENTATION_ROTATE_180 -> "ORIENTATION_ROTATE_180"
ExifInterface.ORIENTATION_FLIP_VERTICAL -> "ORIENTATION_FLIP_VERTICAL"
ExifInterface.ORIENTATION_TRANSPOSE -> "ORIENTATION_TRANSPOSE"
ExifInterface.ORIENTATION_ROTATE_90 -> "ORIENTATION_ROTATE_90"
ExifInterface.ORIENTATION_TRANSVERSE -> "ORIENTATION_TRANSVERSE"
ExifInterface.ORIENTATION_ROTATE_270 -> "ORIENTATION_ROTATE_270"
else -> "UKNONWN ORIENTATION"
}
Log.w(TAG,"ORIEntation int: $orientation is: $o")
}
private fun rotateBitmap(bitmap: Bitmap, orientation: Int): Bitmap? {
val matrix = Matrix()
when (orientation) {
ExifInterface.ORIENTATION_NORMAL -> return bitmap
ExifInterface.ORIENTATION_FLIP_HORIZONTAL -> matrix.setScale(-1f, 1f)
ExifInterface.ORIENTATION_ROTATE_180 -> matrix.setRotate(180f)
ExifInterface.ORIENTATION_FLIP_VERTICAL -> {
matrix.setRotate(180f)
matrix.postScale(-1f, 1f)
}
ExifInterface.ORIENTATION_TRANSPOSE -> {
matrix.setRotate(90f)
matrix.postScale(-1f, 1f)
}
ExifInterface.ORIENTATION_ROTATE_90 -> matrix.setRotate(90f)
ExifInterface.ORIENTATION_TRANSVERSE -> {
matrix.setRotate(-90f)
matrix.postScale(-1f, 1f)
}
ExifInterface.ORIENTATION_ROTATE_270 -> matrix.setRotate(-90f)
else -> return bitmap
}
return try {
val bmRotated = Bitmap.createBitmap(bitmap, 0, 0, bitmap.width, bitmap.height, matrix, true)
bitmap.recycle()
bmRotated
} catch (e: OutOfMemoryError) {
e.printStackTrace()
null
}
}