在我的测试中,Bitmap
创建的BitmapFactory.decodeFile()
不尊重EXIF标题。
例如,当我调用Bitmap.getWidth()
和Bitmap.getHeight()
时,如果设备拍摄的肖像图像不会根据相机方向旋转实际像素数据,而是将其存储在EXIF标题中,它们返回不正确的值(宽度的高度,反之亦然)。
有没有办法让BitmapFactory.decodeFile()
尊重EXIF并产生正确的Bitmap
?
如果没有,处理此问题的推荐模式是什么?
如果没有经验丰富的Android开发者的建议,我看到的唯一方法是预处理拍摄的图像(根据EXIF加载,旋转并保存)。但是,除了巨大的处理开销之外,这可能会导致OutOfMemoryException
用于大型摄像机分辨率(如果您无法通过使用BitmapFactory.Options.inSampleSize
来加载缩小的图像来降低质量)。
答案 0 :(得分:2)
事实证明,解决最初的问题变成了一组新问题。以下是进一步读者的完整教程。
首先,作为@CommonsWare pointed in his answer,我们必须使用EXIF方向标记手动处理方向。为避免错误/安全性有缺陷的android.media.ExifInterface
以及第三方依赖项,最佳选择似乎是新的com.android.support:exifinterface
库,我们将其添加到build.gradle
中:
dependencies {
compile 'com.android.support:exifinterface:26.0.0'
}
但对我来说,它导致Gradle同步错误,因为在Google存储库中找不到此特定最新版本的库,但此版本是Support Library Packages页面上的最新版本。
经过一个小时的试验,我发现jcenter()
存储库还不够,并且通过添加Google Maven存储库修复了Gradle同步:
allprojects {
repositories {
jcenter()
maven {
url 'https://maven.google.com'
// Alternative URL is 'https://dl.google.com/dl/android/maven2/'
}
}
}
好的,现在我们可以使用android.support.media.ExifInterface
。
下一个令人失望的是EXIF标签中存储的宽度和高度也不尊重方向,即对于以纵向模式拍摄的图像,您获得的Bitmap
返回的宽度和高度与{{1}相同}}。所以唯一的方法是手动查看EXIF BitmapFactory.decodeFile()
标签,如果它说图像旋转90度或270度 - 交换宽度和高度:
ExifInterface.TAG_ORIENTATION
我不确定这种方法和代码是否涵盖100%的案例,因此如果您遇到各种设备/图片来源的任何问题 - 请随时发表评论。
一般来说,处理EXIF似乎并不是一种愉快的体验。即使是来自大公司的EXIF标准的实施似乎也会以不同的方式对待细微差别。请参阅广泛分析here。
答案 1 :(得分:1)
有没有办法让BitmapFactory.decodeFile()尊重EXIF并生成正确的位图?
不,抱歉。
处理此问题的推荐模式是什么?
使用支持库的ExifInterface
确定所需的方向。然后,根据您对Bitmap
的使用情况,旋转视图(例如ImageView
)或旋转Bitmap
。 This sample project说明了这两种方法,但我使用了一组单独的EXIF代码,因为支持库ExifInterface
不支持我在该示例中使用的一些内容。
答案 2 :(得分:0)
您现在可以使用Glide进行此操作。请参阅此处的“背景线程”部分:
https://bumptech.github.io/glide/doc/getting-started.html
位图位图= Glide.with(上下文).asBitmap()。load(新File(fileName))。skipMemoryCache(true).submit()。get();
Glide将EXIF考虑在内。您需要将其加载到后台线程。我正在使用Glide 4.9.0