From 19865685488bf1370eb269739c28ecaa42fc906f Mon Sep 17 00:00:00 2001 From: JohnWowUs Date: Thu, 28 May 2015 14:58:50 +0100 Subject: [PATCH] Exif fixes --- .../android/crop/CropImageActivity.java | 86 ++++++++++++------- .../com/soundcloud/android/crop/CropUtil.java | 43 +++++++--- 2 files changed, 87 insertions(+), 42 deletions(-) diff --git a/lib/src/main/java/com/soundcloud/android/crop/CropImageActivity.java b/lib/src/main/java/com/soundcloud/android/crop/CropImageActivity.java index 1cb31d04..e4b867d0 100644 --- a/lib/src/main/java/com/soundcloud/android/crop/CropImageActivity.java +++ b/lib/src/main/java/com/soundcloud/android/crop/CropImageActivity.java @@ -30,6 +30,7 @@ import android.os.Bundle; import android.os.Handler; import android.provider.MediaStore; +import android.util.Pair; import android.view.View; import android.view.Window; import android.view.WindowManager; @@ -56,6 +57,7 @@ public class CropImageActivity extends MonitoredActivity { private int maxX; private int maxY; private int exifRotation; + private int exifScale; private boolean saveAsPng; private Uri sourceUri; @@ -64,7 +66,7 @@ public class CropImageActivity extends MonitoredActivity { private boolean isSaving; private int sampleSize; - private RotateBitmap rotateBitmap; + private Bitmap srcBitmap; private CropImageView imageView; private HighlightView cropView; @@ -75,7 +77,7 @@ public void onCreate(Bundle icicle) { setupViews(); loadInput(); - if (rotateBitmap == null) { + if (srcBitmap == null) { finish(); return; } @@ -120,6 +122,7 @@ public void onClick(View v) { private void loadInput() { Intent intent = getIntent(); Bundle extras = intent.getExtras(); + Bitmap initialBitmap; if (extras != null) { aspectX = extras.getInt(Crop.Extra.ASPECT_X); @@ -132,15 +135,32 @@ private void loadInput() { sourceUri = intent.getData(); if (sourceUri != null) { - exifRotation = CropUtil.getExifRotation(CropUtil.getFromMediaUri(this, getContentResolver(), sourceUri)); - + Pair exifRotationTrans = + CropUtil.getExifRotationTranslation( + CropUtil.getFromMediaUri(this, getContentResolver(), sourceUri)); + exifRotation = exifRotationTrans.first; + exifScale = exifRotationTrans.second; InputStream is = null; try { sampleSize = calculateBitmapSampleSize(sourceUri); is = getContentResolver().openInputStream(sourceUri); BitmapFactory.Options option = new BitmapFactory.Options(); option.inSampleSize = sampleSize; - rotateBitmap = new RotateBitmap(BitmapFactory.decodeStream(is, null, option), exifRotation); + initialBitmap = BitmapFactory.decodeStream(is, null, option); + int drawHeight = initialBitmap.getHeight(); + int drawWidth = initialBitmap.getWidth(); + if ((exifRotation != 0) || (exifScale != 1)) { + Matrix matrix = new Matrix() ; + if (exifRotation != 0) { + matrix.preRotate(exifRotation); + } + if (exifScale != 1) { + matrix.postScale(exifScale, 1); + } + srcBitmap = Bitmap.createBitmap(initialBitmap, 0, 0, drawWidth, drawHeight, matrix, true); + } else { + srcBitmap = initialBitmap ; + } } catch (IOException e) { Log.e("Error reading image: " + e.getMessage(), e); setResultException(e); @@ -151,6 +171,9 @@ private void loadInput() { CropUtil.closeSilently(is); } } + else { + Log.e("Source URI is null"); + } } private int calculateBitmapSampleSize(Uri bitmapUri) throws IOException { @@ -192,7 +215,7 @@ private void startCrop() { if (isFinishing()) { return; } - imageView.setImageRotateBitmapResetBase(rotateBitmap, true); + imageView.setImageBitmapResetBase(srcBitmap, true); CropUtil.startBackgroundJob(this, null, getResources().getString(R.string.crop__wait), new Runnable() { public void run() { @@ -219,13 +242,13 @@ public void run() { private class Cropper { private void makeDefault() { - if (rotateBitmap == null) { + if (srcBitmap == null) { return; } HighlightView hv = new HighlightView(imageView); - final int width = rotateBitmap.getWidth(); - final int height = rotateBitmap.getHeight(); + final int width = srcBitmap.getWidth(); + final int height = srcBitmap.getHeight(); Rect imageRect = new Rect(0, 0, width, height); @@ -297,7 +320,7 @@ private void onSaveClicked() { } if (croppedImage != null) { - imageView.setImageRotateBitmapResetBase(new RotateBitmap(croppedImage, exifRotation), true); + imageView.setImageBitmapResetBase(croppedImage, true); imageView.center(); imageView.highlightViews.clear(); } @@ -322,20 +345,20 @@ public void run() { private Bitmap decodeRegionCrop(Rect rect, int outWidth, int outHeight) { // Release memory now clearImageView(); - + Matrix matrix = new Matrix(); InputStream is = null; Bitmap croppedImage = null; + boolean transformed = false; try { is = getContentResolver().openInputStream(sourceUri); BitmapRegionDecoder decoder = BitmapRegionDecoder.newInstance(is, false); final int width = decoder.getWidth(); final int height = decoder.getHeight(); - if (exifRotation != 0) { - // Adjust crop area to account for image rotation - Matrix matrix = new Matrix(); - matrix.setRotate(-exifRotation); - + if ((exifRotation != 0) || (exifScale != 1)) { + // Adjust crop area to account for EXIF transformation so what you crop is what you get + matrix.preRotate(-exifRotation); + matrix.postScale(exifScale, 1); RectF adjusted = new RectF(); matrix.mapRect(adjusted, new RectF(rect)); @@ -345,11 +368,20 @@ private Bitmap decodeRegionCrop(Rect rect, int outWidth, int outHeight) { } try { + matrix.reset(); croppedImage = decoder.decodeRegion(rect, new BitmapFactory.Options()); - if (croppedImage != null && (rect.width() > outWidth || rect.height() > outHeight)) { - Matrix matrix = new Matrix(); - matrix.postScale((float) outWidth / rect.width(), (float) outHeight / rect.height()); - croppedImage = Bitmap.createBitmap(croppedImage, 0, 0, croppedImage.getWidth(), croppedImage.getHeight(), matrix, true); + if ((exifRotation != 0) || (exifScale != 1)) { + transformed = true; + // Remove the EXIF transformation from the cropped image so we can dispense with it altogether + matrix.preRotate(exifRotation); + matrix.postScale(exifScale, 1); + } + if (rect.width() > outWidth || rect.height() > outHeight) { + transformed = true ; + matrix.postScale(((float)outWidth)/((float)rect.width()), ((float)outHeight)/((float)rect.height())); + } + if (transformed) { + croppedImage = Bitmap.createBitmap(croppedImage, 0, 0, croppedImage.getWidth(), croppedImage.getHeight(), matrix, true); } } catch (IllegalArgumentException e) { // Rethrow with some extra information @@ -371,8 +403,8 @@ private Bitmap decodeRegionCrop(Rect rect, int outWidth, int outHeight) { private void clearImageView() { imageView.clear(); - if (rotateBitmap != null) { - rotateBitmap.recycle(); + if (srcBitmap != null) { + srcBitmap.recycle(); } System.gc(); } @@ -393,12 +425,6 @@ private void saveOutput(Bitmap croppedImage) { } finally { CropUtil.closeSilently(outputStream); } - - CropUtil.copyExifRotation( - CropUtil.getFromMediaUri(this, getContentResolver(), sourceUri), - CropUtil.getFromMediaUri(this, getContentResolver(), saveUri) - ); - setResultUri(saveUri); } @@ -416,8 +442,8 @@ public void run() { @Override protected void onDestroy() { super.onDestroy(); - if (rotateBitmap != null) { - rotateBitmap.recycle(); + if (srcBitmap != null) { + srcBitmap.recycle(); } } diff --git a/lib/src/main/java/com/soundcloud/android/crop/CropUtil.java b/lib/src/main/java/com/soundcloud/android/crop/CropUtil.java index 04e83224..754ea289 100644 --- a/lib/src/main/java/com/soundcloud/android/crop/CropUtil.java +++ b/lib/src/main/java/com/soundcloud/android/crop/CropUtil.java @@ -27,6 +27,7 @@ import android.provider.MediaStore; import android.support.annotation.Nullable; import android.text.TextUtils; +import android.util.Pair; import java.io.Closeable; import java.io.File; @@ -52,25 +53,43 @@ public static void closeSilently(@Nullable Closeable c) { } } - public static int getExifRotation(File imageFile) { - if (imageFile == null) return 0; + public static Pair getExifRotationTranslation(File imageFile) { + int exifRotation = 0, exifScale = 1; + if (imageFile == null) return new Pair(0,1); try { ExifInterface exif = new ExifInterface(imageFile.getAbsolutePath()); - // We only recognize a subset of orientation tag values switch (exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_UNDEFINED)) { - case ExifInterface.ORIENTATION_ROTATE_90: - return 90; - case ExifInterface.ORIENTATION_ROTATE_180: - return 180; - case ExifInterface.ORIENTATION_ROTATE_270: - return 270; - default: - return ExifInterface.ORIENTATION_UNDEFINED; + case ExifInterface.ORIENTATION_UNDEFINED: + case ExifInterface.ORIENTATION_NORMAL: + break ; + case ExifInterface.ORIENTATION_FLIP_HORIZONTAL: + exifScale=-1; + break; + case ExifInterface.ORIENTATION_ROTATE_180: + exifRotation = 180; + break; + case ExifInterface.ORIENTATION_FLIP_VERTICAL: + exifRotation = 180; + exifScale=-1; + break; + case ExifInterface.ORIENTATION_TRANSPOSE: + exifRotation = 90; + exifScale=-1; + break; + case ExifInterface.ORIENTATION_ROTATE_90: + exifRotation = 90; + break; + case ExifInterface.ORIENTATION_TRANSVERSE: + exifRotation = 270; + exifScale=-1; + break; + case ExifInterface.ORIENTATION_ROTATE_270: + exifRotation = 270; } } catch (IOException e) { Log.e("Error getting Exif data", e); - return 0; } + return new Pair(exifRotation,exifScale); } public static boolean copyExifRotation(File sourceFile, File destFile) {