Android拍摄图片真机显示方向错误,模拟器正常的问题求助
问题分析
你遇到的核心问题是模拟器与真机的Camera API对Bitmap方向的处理逻辑不一致,再加上MediaStore.Images.Media.insertImage方法不会保留或写入正确的Exif方向信息,导致真机上保存的图片显示异常:
- 模拟器中,Camera返回的Bitmap已经是符合竖屏方向的,且对应文件的Exif标签为
ORIENTATION_NORMAL,所以你的旋转逻辑不会改变Bitmap方向,保存后图库显示正常。 - 真机中,部分Camera API会返回原始拍摄方向的Bitmap(横屏),但文件的Exif标签标记了需要旋转90/270度;或者反过来,Camera已经返回旋转后的Bitmap,但你又根据原始文件的Exif再次旋转,导致方向错乱。同时
insertImage保存Bitmap时不会写入正确的Exif方向标签,图库读取时会默认按原始Bitmap尺寸显示,最终出现横屏的问题。
解决方案
方案1:从原始文件加载Bitmap并处理旋转(最可靠)
避免使用Camera返回的capturedImg,直接从照片文件路径加载Bitmap,确保Bitmap与Exif信息完全对应:
private fun getPictureBitmap(yourPathToPicture: String?): Bitmap? { val originalBitmap = BitmapFactory.decodeFile(yourPathToPicture) ?: return null val ei = ExifInterface(yourPathToPicture!!) val orientation = ei.getAttributeInt( ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_UNDEFINED ) return when (orientation) { ExifInterface.ORIENTATION_ROTATE_90 -> rotateImage(originalBitmap, 90) ExifInterface.ORIENTATION_ROTATE_180 -> rotateImage(originalBitmap, 180) ExifInterface.ORIENTATION_ROTATE_270 -> rotateImage(originalBitmap, 270) else -> originalBitmap } } // 确保rotateImage方法正确实现 private fun rotateImage(source: Bitmap, angle: Int): Bitmap { val matrix = Matrix() matrix.postRotate(angle.toFloat()) return Bitmap.createBitmap(source, 0, 0, source.width, source.height, matrix, true) }
调用方式:
val rotatedBitmap = getPictureBitmap(path) rotatedBitmap?.let { // 替换原有的insertImage调用 saveBitmapToGallery(contentResolver, it) }
方案2:替换insertImage,手动保存Bitmap并写入Exif信息
MediaStore.Images.Media.insertImage不会处理Exif,改用ContentResolver插入图片并手动设置Exif方向标签,确保图库能正确识别方向:
fun saveBitmapToGallery(contentResolver: ContentResolver, bitmap: Bitmap) { val values = ContentValues().apply { put(MediaStore.Images.Media.DISPLAY_NAME, "IMG_${System.currentTimeMillis()}.jpg") put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg") put(MediaStore.Images.Media.WIDTH, bitmap.width) put(MediaStore.Images.Media.HEIGHT, bitmap.height) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { put(MediaStore.Images.Media.RELATIVE_PATH, Environment.DIRECTORY_DCIM) } } val uri = contentResolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values) uri?.let { contentResolver.openFileDescriptor(it, "w")?.use { fd -> // 压缩Bitmap到文件 bitmap.compress(Bitmap.CompressFormat.JPEG, 90, FileOutputStream(fd.fileDescriptor)) // 写入Exif方向为NORMAL(因为已经旋转过Bitmap) val exif = ExifInterface(fd.fileDescriptor) exif.setAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL) exif.saveAttributes() } // 通知图库更新 contentResolver.notifyChange(uri, null) } }
方案3:排查是否重复旋转Bitmap
在真机上打印日志,确认capturedImg的实际尺寸和原始文件的Exif方向,判断是否存在重复旋转的情况:
Log.d("BitmapDebug", "capturedImg: ${capturedImg.width}x${capturedImg.height}") val ei = ExifInterface(path) val orientation = ei.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_UNDEFINED) Log.d("ExifDebug", "orientation code: $orientation")
- 如果
capturedImg的宽高已经是竖屏(高>宽),但Exif方向是ORIENTATION_ROTATE_90,说明Camera已经返回旋转后的Bitmap,此时你的代码会再次旋转导致方向错误,需要去掉旋转逻辑。
内容的提问来源于stack exchange,提问作者Captai-N
相关产品推荐
相关产品推荐

