gpt4 book ai didi

android - Camera.takePicture 返回一个旋转的 byteArray

转载 作者:行者123 更新时间:2023-12-04 03:58:52 25 4
gpt4 key购买 nike

我正在尝试使用 hardware.camera 制作自定义相机应用。

我已经实现了一个 PictureCallback,它会在拍照时写入具有特定路径的文件。写入文件的data是camera API中takePicture返回的ByteArray

所以在写入文件后,我注意到垂直拍摄的照片是水平保存的。问题不是因为 Exif 标记导致 byteArray 在写入文件之前和之后都有 ORIENTATION_NORMAL

写入文件的data是camera API中takePicture返回的ByteArray

这是 takePictureCamera.Java 中的样子:

    public final void takePicture(ShutterCallback shutter, PictureCallback raw,
PictureCallback jpeg) {
takePicture(shutter, raw, null, jpeg);
}

这是 CameraPreview 的一部分,它将捕获照片:

相机预览代码

    val imageProcessor = ImageProcessor()
private val fileSaver = FileSaver(context)
fun capture() {
val callback = PictureCallback { data, _ ->
imageProcessor.process(data)?.apply {
val file = fileSaver.saveBitmap(this, outputFileName ?: DEFAULT_FILE_NAME)
onCaptureTaken?.invoke(file)
}
}
camera?.takePicture(null, null, callback)
}

ImageProcessor.kt 代码

class ImageProcessor {

fun process(data: ByteArray): Bitmap? {
val options = BitmapFactory.Options().apply {
inMutable = true
}

val bitmap = BitmapFactory.decodeByteArray(data, 0, data.size, options)
return fixImageRotation(data, bitmap)
}
private fun fixImageRotation(picture: ByteArray, bitmap: Bitmap): Bitmap? {
return when (exifPostProcessor(picture)) {
ExifInterface.ORIENTATION_ROTATE_90 ->
rotateImage(bitmap, 90F)
ExifInterface.ORIENTATION_ROTATE_180 ->
rotateImage(bitmap, 180F)
ExifInterface.ORIENTATION_ROTATE_270 ->
rotateImage(
bitmap, 270F
)
ExifInterface.ORIENTATION_NORMAL -> bitmap
else -> bitmap
}
}

private fun rotateImage(source: Bitmap, angle: Float): Bitmap? {
val matrix = Matrix()
matrix.postRotate(angle)
return Bitmap.createBitmap(
source, 0, 0, source.width, source.height,
matrix, true
)
}

private fun exifPostProcessor(picture: ByteArray?): Int {
try {
return getExifOrientation(ByteArrayInputStream(picture))
} catch (e: IOException) {
e.printStackTrace()
}
return -1
}

@Throws(IOException::class)
private fun getExifOrientation(inputStream: InputStream): Int {
val exif = ExifInterface(inputStream)
return exif.getAttributeInt(
ExifInterface.TAG_ORIENTATION,
ExifInterface.ORIENTATION_NORMAL
)
}
}

FileSaver.kt 代码

internal class FileSaver(context: Context) {

private val context: Context = context.applicationContext
fun saveBitmap(bitmap: Bitmap, fileName: String): File {
val file = File(mkdirsCacheFolder(), fileName)
try {
FileOutputStream(file).use { out ->
bitmap.compress(Bitmap.CompressFormat.JPEG, ORIGINAL_QUALITY, out)
}
bitmap.recycle()
} catch (e: IOException) {
e.printStackTrace()
}
return file
}


private fun mkdirsCacheFolder(): File {
return File(context.externalCacheDir, CACHE_DIRECTORY).apply {
if (!exists()) {
mkdirs()
}
}
}

companion object {
private const val ORIGINAL_QUALITY = 100
private const val CACHE_DIRECTORY = "/Lens"
}
}

有什么建议吗?

编辑:我打印了 Exif 标签,结果是 ORIENTATION_NORMAL 所以我真的不知道它是否旋转了。

编辑 2 :示例照片是在纵向模式下拍摄的,并从文件管理器 [!并非如此,这些结果是在模拟器和真实的 android 手机上测试的,它们是相同的。预习: Preview

从文件管理器中捕获的图像: Captured image from file manager

最佳答案

在这个问题中几乎没有与这种情况重叠的问题,因此我花了很长时间才明白到底发生了什么。

您所做的是,您从相机收到了一个有效的 Jpeg ByteArray,并且该流包含一些 EXIF 信息,但它缺少方向标签。这发生在许多设备上,也发生在 Xiaomi Mi 上。 .

因此,您无法正确旋转位图。但你确切地知道 orientation of your Activity : preview.display.rotation。这应该会告诉您在这种情况下位图应该如何旋转,但是如果您的 Activity 被锁定为纵向,您甚至不需要检查。显示旋转可能在 0…3 范围内,这些代表 Surface.ROTATION_0Surface.ROTATION_90Surface.ROTATION_180Surface.ROTATION_270

要选择正确的旋转方式,您必须了解硬件的组装方式,即相机传感器如何与设备对齐。这orientation of the camera可以是 0、90、180 或 270。

您可能在不同的来源中看到过这段代码:

var degrees = 0
when (preview.display.rotation) {
Surface.ROTATION_0 -> degrees = 0
Surface.ROTATION_90 -> degrees = 90
Surface.ROTATION_180 -> degrees = 180
Surface.ROTATION_270 -> degrees = 270
}
val ci = Camera.CameraInfo()
Camera.getCameraInfo(cameraId, ci)
if (ci.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
degrees += ci.orientation
degrees %= 360
degrees = 360 - degrees
} else {
degrees = 360 - degrees
degrees += ci.orientation
}
camera!!.setDisplayOrientation(degrees % 360)

此代码允许相机预览与您的屏幕正确对齐;您的应用程序中可能也有这个。如果 getExifOrientation() 返回 ExifInterface.ORIENTATION_UNKNOWN,则可以使用相同的代码在 fixImageRotation() 中选择正确的位图旋转。

在某些情况下,您需要有关设备方向的更多详细信息,如 here 所述.

无论如何,我建议您切换到现代 CameraX API,为大多数设备提供更好的支持。它允许我调用 ImageCapture.setTargetRotation()图书馆为我旋转了生成的 Jpeg。

关于android - Camera.takePicture 返回一个旋转的 byteArray,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63373615/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com