是否可以使BitmapFactory.decodeFile()尊重EXIF?

时间:2017-08-07 17:01:11

标签: java android image bitmap exif

在我的测试中,Bitmap创建的BitmapFactory.decodeFile()不尊重EXIF标题。

例如,当我调用Bitmap.getWidth()Bitmap.getHeight()时,如果设备拍摄的肖像图像不会根据相机方向旋转实际像素数据,而是将其存储在EXIF标题中,它们返回不正确的值(宽度的高度,反之亦然)。

有没有办法让BitmapFactory.decodeFile()尊重EXIF并产生正确的Bitmap

如果没有,处理此问题的推荐模式是什么?

如果没有经验丰富的Android开发者的建议,我看到的唯一方法是预处理拍摄的图像(根据EXIF加载,旋转并保存)。但是,除了巨大的处理开销之外,这可能会导致OutOfMemoryException用于大型摄像机分辨率(如果您无法通过使用BitmapFactory.Options.inSampleSize来加载缩小的图像来降低质量)。

3 个答案:

答案 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)或旋转BitmapThis 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