Kotlin Uri转缩放Bitmap后图片侧向旋转问题排查
问题根因
图片旋转的核心错误是解码流程没有处理图片EXIF元数据中存储的朝向信息:
- 手机拍摄、部分来源的图片会在EXIF信息中标记拍摄时的设备朝向,系统图片组件、常规图片加载库(包括你使用的AsyncImage)直接加载原始Uri时,会自动读取该参数校正图片朝向。
- 你使用的
BitmapFactory.decodeStream方法解码图片流时,会直接丢弃所有EXIF元数据,仅按照图像传感器输出的原始像素方向生成Bitmap,后续将这个未校正方向的Bitmap存储为文件再加载,自然会出现侧向旋转的问题。
修复方法
在解码得到原始Bitmap后,先从原始Uri读取EXIF方向参数,将Bitmap旋转到正确角度后再执行后续存储逻辑:
- 先引入AndroidX的ExifInterface依赖,用于读取图片EXIF信息,在模块级
build.gradle的dependencies块中添加:
implementation "androidx.exifinterface:exifinterface:1.3.7"
- 替换原有的
decodeUri方法,增加方向校正逻辑:
fun decodeUri(c: Context, uri: Uri?, requiredSize: Int): Bitmap? { return try { // 计算采样缩放比例,逻辑与原代码一致 val boundsOptions = BitmapFactory.Options().apply { inJustDecodeBounds = true } c.contentResolver.openInputStream(uri!!).use { stream -> BitmapFactory.decodeStream(stream, null, boundsOptions) } var widthTmp = boundsOptions.outWidth var heightTmp = boundsOptions.outHeight var scale = 1 while (true) { if (widthTmp / 2 < requiredSize || heightTmp / 2 < requiredSize) break widthTmp /= 2 heightTmp /= 2 scale *= 2 } // 解码得到原始Bitmap val decodeOptions = BitmapFactory.Options().apply { inSampleSize = scale } val rawBitmap = c.contentResolver.openInputStream(uri).use { stream -> BitmapFactory.decodeStream(stream, null, decodeOptions) } ?: return null // 读取EXIF方向参数 val exif = c.contentResolver.openInputStream(uri).use { stream -> ExifInterface(stream!!) } val orientation = exif.getAttributeInt( ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL ) val rotateAngle = when (orientation) { ExifInterface.ORIENTATION_ROTATE_90 -> 90f ExifInterface.ORIENTATION_ROTATE_180 -> 180f ExifInterface.ORIENTATION_ROTATE_270 -> 270f else -> 0f } if (rotateAngle == 0f) return rawBitmap // 旋转校正Bitmap val rotateMatrix = Matrix().apply { postRotate(rotateAngle) } val correctedBitmap = Bitmap.createBitmap( rawBitmap, 0, 0, rawBitmap.width, rawBitmap.height, rotateMatrix, true ) rawBitmap.recycle() return correctedBitmap } catch (e: Exception) { e.printStackTrace() null } }
额外说明
- 代码中使用
use扩展函数处理输入流,可以自动关闭流避免资源泄漏,比原代码手动管理流更可靠。 - 校正完成后及时回收原始未旋转的Bitmap,避免不必要的内存占用。
- 不需要修改Composable和
bitmapToFile、resizeImage的原有逻辑,替换decodeUri方法后即可解决旋转问题。
内容的提问来源于stack exchange,提问作者Raj Narayanan
相关产品推荐
相关产品推荐

