From 3ba6835d576d6012468fabfc3f22e835172168c1 Mon Sep 17 00:00:00 2001 From: calderwoodra Date: Mon, 19 Jun 2017 16:03:01 -0700 Subject: Rotation Exif data is no longer lost when reducing size of cc images. BitmapFactory.createBitmap doesn't carry-over image exif data. We now hold onto exif data and reapply it through matrix transformations so images are displayed properly. Test: TH PiperOrigin-RevId: 159492684 Change-Id: Ief58f5fc506214e4a6afaf36a1be7dd53c712d4d --- .../callcomposer/CopyAndResizeImageWorker.java | 29 ++++++++++++++++-- .../callcomposer/camera/ImagePersistTask.java | 9 ++---- .../dialer/callcomposer/util/BitmapResizer.java | 35 ++++++++++++---------- 3 files changed, 48 insertions(+), 25 deletions(-) (limited to 'java/com/android/dialer/callcomposer') diff --git a/java/com/android/dialer/callcomposer/CopyAndResizeImageWorker.java b/java/com/android/dialer/callcomposer/CopyAndResizeImageWorker.java index aeb8e0388..725cea723 100644 --- a/java/com/android/dialer/callcomposer/CopyAndResizeImageWorker.java +++ b/java/com/android/dialer/callcomposer/CopyAndResizeImageWorker.java @@ -21,6 +21,7 @@ import android.content.Context; import android.graphics.Bitmap; import android.graphics.Bitmap.CompressFormat; import android.graphics.BitmapFactory; +import android.media.ExifInterface; import android.net.Uri; import android.os.Build.VERSION_CODES; import android.support.annotation.NonNull; @@ -47,17 +48,26 @@ class CopyAndResizeImageWorker implements Worker> { } /** - * @param input The input Uri is expected to be a image openable by {@link - * android.content.ContentResolver#openInputStream(Uri)}. + * @param input The filepath where the image is located. * @return a Pair where the File contains the resized image, and the String is the result File's * MIME type. */ @Nullable @Override public Pair doInBackground(@Nullable Uri input) throws Throwable { + // BitmapFactory.decodeStream strips exif data, so we need to save it here and apply it later. + int rotation = 0; + try { + rotation = + new ExifInterface(input.getPath()) + .getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL); + } catch (Exception ignored) { + // Couldn't get exif tags, not the end of the world + } + try (InputStream inputStream = context.getContentResolver().openInputStream(input)) { Bitmap bitmap = BitmapFactory.decodeStream(inputStream); - bitmap = BitmapResizer.resizeForEnrichedCalling(bitmap); + bitmap = BitmapResizer.resizeForEnrichedCalling(bitmap, exifToDegrees(rotation)); File outputFile = DialerUtils.createShareableFile(context); try (OutputStream outputStream = new FileOutputStream(outputFile)) { @@ -67,4 +77,17 @@ class CopyAndResizeImageWorker implements Worker> { } } } + + private static int exifToDegrees(int exifOrientation) { + switch (exifOrientation) { + case ExifInterface.ORIENTATION_ROTATE_90: + return 90; + case ExifInterface.ORIENTATION_ROTATE_180: + return 180; + case ExifInterface.ORIENTATION_ROTATE_270: + return 270; + default: + return 0; + } + } } diff --git a/java/com/android/dialer/callcomposer/camera/ImagePersistTask.java b/java/com/android/dialer/callcomposer/camera/ImagePersistTask.java index 7cb6921e9..8620701fe 100644 --- a/java/com/android/dialer/callcomposer/camera/ImagePersistTask.java +++ b/java/com/android/dialer/callcomposer/camera/ImagePersistTask.java @@ -20,7 +20,6 @@ import android.annotation.TargetApi; import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; -import android.graphics.Matrix; import android.net.Uri; import android.os.Build.VERSION_CODES; import android.support.v4.content.FileProvider; @@ -119,13 +118,9 @@ public class ImagePersistTask extends FallibleAsyncTask { mWidth = clippedWidth; mHeight = clippedHeight; - Matrix matrix = new Matrix(); - matrix.postRotate(params.rotation); - Bitmap clippedBitmap = - Bitmap.createBitmap( - bitmap, offsetLeft, offsetTop, clippedWidth, clippedHeight, matrix, true); - clippedBitmap = BitmapResizer.resizeForEnrichedCalling(clippedBitmap); + Bitmap.createBitmap(bitmap, offsetLeft, offsetTop, clippedWidth, clippedHeight); + clippedBitmap = BitmapResizer.resizeForEnrichedCalling(clippedBitmap, params.rotation); // EXIF data can take a big chunk of the file size and we've already manually rotated our image, // so remove all of the exif data. exifInterface.clearExif(); diff --git a/java/com/android/dialer/callcomposer/util/BitmapResizer.java b/java/com/android/dialer/callcomposer/util/BitmapResizer.java index 658462def..84ada51d8 100644 --- a/java/com/android/dialer/callcomposer/util/BitmapResizer.java +++ b/java/com/android/dialer/callcomposer/util/BitmapResizer.java @@ -17,6 +17,7 @@ package com.android.dialer.callcomposer.util; import android.graphics.Bitmap; +import android.graphics.Matrix; import android.support.annotation.VisibleForTesting; import com.android.dialer.common.Assert; import com.android.dialer.common.LogUtil; @@ -28,40 +29,44 @@ public final class BitmapResizer { /** * Returns a bitmap that is a resized version of the parameter image. The image will only be * resized down and sized to be appropriate for an enriched call. + * + * @param image to be resized + * @param rotation degrees to rotate the image clockwise + * @return resized image */ - public static Bitmap resizeForEnrichedCalling(Bitmap image) { + public static Bitmap resizeForEnrichedCalling(Bitmap image, int rotation) { Assert.isWorkerThread(); int width = image.getWidth(); int height = image.getHeight(); + Matrix matrix = new Matrix(); + matrix.postRotate(rotation); + LogUtil.i( "BitmapResizer.resizeForEnrichedCalling", "starting height: %d, width: %d", height, width); if (width <= MAX_OUTPUT_RESOLUTION && height <= MAX_OUTPUT_RESOLUTION) { LogUtil.i("BitmapResizer.resizeForEnrichedCalling", "no resizing needed"); - return image; + return Bitmap.createBitmap(image, 0, 0, width, height, matrix, true); } + float ratio = 1; if (width > height) { // landscape - float ratio = width / (float) MAX_OUTPUT_RESOLUTION; - width = MAX_OUTPUT_RESOLUTION; - height = (int) (height / ratio); - } else if (height > width) { - // portrait - float ratio = height / (float) MAX_OUTPUT_RESOLUTION; - height = MAX_OUTPUT_RESOLUTION; - width = (int) (width / ratio); + ratio = MAX_OUTPUT_RESOLUTION / (float) width; } else { - // square - height = MAX_OUTPUT_RESOLUTION; - width = MAX_OUTPUT_RESOLUTION; + // portrait & square + ratio = MAX_OUTPUT_RESOLUTION / (float) height; } LogUtil.i( - "BitmapResizer.resizeForEnrichedCalling", "ending height: %d, width: %d", height, width); + "BitmapResizer.resizeForEnrichedCalling", + "ending height: %f, width: %f", + height * ratio, + width * ratio); - return Bitmap.createScaledBitmap(image, width, height, true); + matrix.postScale(ratio, ratio); + return Bitmap.createBitmap(image, 0, 0, width, height, matrix, true); } } -- cgit v1.2.3