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

问题描述 投票:1回答:3

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

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

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

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

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

java android image bitmap exif
3个回答
1
投票

有没有办法使BitmapFactory.decodeFile()尊重EXIF并生成正确的位图?

不,对不起

处理此问题的推荐模式是什么?

使用支持库的ExifInterface确定所需的方向。然后,根据您对Bitmap的使用,旋转视图(例如,ImageView)或旋转BitmapThis sample project说明了这两种方法,虽然我使用了一组单独的EXIF代码,因为支持库的ExifInterface不支持我在该示例中使用的一些东西。


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创建的BitmapFactory.decodeFile()返回的宽度和高度相同。所以唯一的方法是手动查看EXIF ExifInterface.TAG_ORIENTATION标签,如果它说图像旋转90度或270度 - 交换宽度和高度:

ExifInterface exif = new ExifInterface(fileNameFull);
orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_UNDEFINED);

BitmapFactory.Options optsForBounds = new BitmapFactory.Options();
optsForBounds.inJustDecodeBounds = true;
BitmapFactory.decodeFile(fileName, optsForBounds);

int width = optsForBounds.outWidth, height = optsForBounds.outHeight;
if (orientation == ExifInterface.ORIENTATION_ROTATE_90 || orientation == ExifInterface.ORIENTATION_ROTATE_270)
{
    int temp = width;
    //noinspection SuspiciousNameCombination
    width = height;
    height = temp;
}

我不确定这种方法和代码是否涵盖100%的案例,因此如果您遇到各种设备/图像源的任何问题 - 请随意发表评论。

一般来说,处理EXIF似乎并不是一种愉快的体验。即使是来自大公司的EXIF标准的实施似乎也会以不同的方式对待细微差别。见广泛的分析here


1
投票

你现在可以用Glide做到这一点。请参阅此处的“背景线程”部分:

https://bumptech.github.io/glide/doc/getting-started.html

Bitmap bitmap = Glide.with(context).asBitmap()。load(new File(fileName))。skipMemoryCache(true).submit()。get();

Glide考虑了EXIF。您需要在后台线程上加载它。我使用的是Glide 4.9.0

© www.soinside.com 2019 - 2024. All rights reserved.