Is it possible to make BitmapFactory.decodeFile() respect EXIF?

Viewed 2915

In my tests, a Bitmap created by BitmapFactory.decodeFile() doesn't respect EXIF header.

For example, with portrait images taken by a devices that doesn't rotate actual pixel data depending on camera orientation but rather stores it in EXIF header, when I'm calling Bitmap.getWidth() and Bitmap.getHeight(), they return incorrect values (height for width and vice versa).

Is there a way to make BitmapFactory.decodeFile() respect EXIF and produce a correct Bitmap?

If not, what is the recommended pattern to handle this issue?

Without an advice from experienced Android devs, the only way I see is to pre-process taken images (load, rotate according to EXIF, and save). But apart from the huge processing overhead, this might cause OutOfMemoryExceptions for large camera resolutions (in cases when you can't reduce the quality by using BitmapFactory.Options.inSampleSize to load downscaled images).

4 Answers

You can do this with Glide now. See the "Background Threads" section here:

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

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

Glide takes into consideration EXIF. You'll need to load it on a background thread. I was using Glide 4.9.0

Bitmap = getThumb(file, dimensionPixelSize);

public Bitmap getThumb(String file, float thumbSize) throws FileNotFoundException, IOException, OutOfMemoryError {

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

    mOptions.inSampleSize = getSample(file, thumbSize);
    mOptions.inJustDecodeBounds = false;

    Bitmap bitmap = BitmapFactory.decodeFile(file, mOptions);

    if (orientation == ExifInterface.ORIENTATION_ROTATE_90 || orientation == ExifInterface.ORIENTATION_ROTATE_270) {
        return rotateBitmap(bitmap, 90);
    } else {
        return bitmap;
    }

}

public int getSample(String file, float thumbSize) throws FileNotFoundException, IOException, OutOfMemoryError {
    mOptions.inJustDecodeBounds = true;
    BitmapFactory.decodeFile(file, mOptions);
    int size = Math.round(Math.max(mOptions.outWidth, mOptions.outHeight) / thumbSize);
    if (size % 2 != 0) {
        size--;
    }
    return size;
}

public Bitmap rotateBitmap(Bitmap source, float angle) {
     Matrix matrix = new Matrix();
     matrix.postRotate(angle);
     return Bitmap.createBitmap(source, 0, 0, source.getWidth(), source.getHeight(), matrix, true);
}
Related