From 63cdaf489bd31c306d817eb7d9903ef77786aeb9 Mon Sep 17 00:00:00 2001 From: JohnWowUs Date: Thu, 28 May 2015 14:58:50 +0100 Subject: [PATCH 1/2] Exif fixes --- .../android/crop/CropImageActivity.java | 90 ++++++++++++------- .../com/soundcloud/android/crop/CropUtil.java | 43 ++++++--- 2 files changed, 90 insertions(+), 43 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 62a1596a..7656face 100644 --- a/lib/src/main/java/com/soundcloud/android/crop/CropImageActivity.java +++ b/lib/src/main/java/com/soundcloud/android/crop/CropImageActivity.java @@ -28,6 +28,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; @@ -53,6 +54,7 @@ public class CropImageActivity extends MonitoredActivity { private int maxX; private int maxY; private int exifRotation; + private int exifScale; private Uri sourceUri; private Uri saveUri; @@ -60,7 +62,7 @@ public class CropImageActivity extends MonitoredActivity { private boolean isSaving; private int sampleSize; - private RotateBitmap rotateBitmap; + private Bitmap srcBitmap; private CropImageView imageView; private HighlightView cropView; @@ -72,7 +74,7 @@ public void onCreate(Bundle icicle) { initViews(); setupFromIntent(); - if (rotateBitmap == null) { + if (srcBitmap == null) { finish(); return; } @@ -107,6 +109,7 @@ public void onClick(View v) { private void setupFromIntent() { Intent intent = getIntent(); Bundle extras = intent.getExtras(); + Bitmap initialBitmap ; if (extras != null) { aspectX = extras.getInt(Crop.Extra.ASPECT_X); @@ -118,15 +121,32 @@ private void setupFromIntent() { 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); @@ -137,6 +157,9 @@ private void setupFromIntent() { CropUtil.closeSilently(is); } } + else { + Log.e("Source URI is null"); + } } private int calculateBitmapSampleSize(Uri bitmapUri) throws IOException { @@ -178,7 +201,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() { @@ -205,13 +228,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); @@ -263,6 +286,8 @@ private void onSaveClicked() { int outWidth = width; int outHeight = height; + Log.e("Crop Width = " + width); + Log.e("Crop Height = " + height); if (maxX > 0 && maxY > 0 && (width > maxX || height > maxY)) { float ratio = (float) width / (float) height; if ((float) maxX / (float) maxY > ratio) { @@ -283,7 +308,7 @@ private void onSaveClicked() { } if (croppedImage != null) { - imageView.setImageRotateBitmapResetBase(new RotateBitmap(croppedImage, exifRotation), true); + imageView.setImageBitmapResetBase(croppedImage, true); imageView.center(true, true); imageView.highlightViews.clear(); } @@ -306,22 +331,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)); @@ -331,11 +354,20 @@ private Bitmap decodeRegionCrop(Rect rect, int outWidth, int outHeight) { } try { + matrix.reset(); croppedImage = decoder.decodeRegion(rect, new BitmapFactory.Options()); + 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) { - 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); + 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 @@ -351,14 +383,16 @@ private Bitmap decodeRegionCrop(Rect rect, int outWidth, int outHeight) { setResultException(e); } finally { CropUtil.closeSilently(is); + // Release memory now + clearImageView(); } return croppedImage; } private void clearImageView() { imageView.clear(); - if (rotateBitmap != null) { - rotateBitmap.recycle(); + if (srcBitmap != null) { + srcBitmap.recycle(); } System.gc(); } @@ -377,12 +411,6 @@ private void saveOutput(Bitmap croppedImage) { } finally { CropUtil.closeSilently(outputStream); } - - CropUtil.copyExifRotation( - CropUtil.getFromMediaUri(this, getContentResolver(), sourceUri), - CropUtil.getFromMediaUri(this, getContentResolver(), saveUri) - ); - setResultUri(saveUri); } @@ -400,8 +428,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) { From da79c902878c02e01c60fb6886adf7adc5d40eef Mon Sep 17 00:00:00 2001 From: JohnWowUs Date: Tue, 1 Dec 2015 10:35:59 +0000 Subject: [PATCH 2/2] Synch with master --- .../java/com/soundcloud/android/crop/CropImageActivity.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 2679e77d..6affafb8 100644 --- a/lib/src/main/java/com/soundcloud/android/crop/CropImageActivity.java +++ b/lib/src/main/java/com/soundcloud/android/crop/CropImageActivity.java @@ -321,7 +321,7 @@ private void onSaveClicked() { if (croppedImage != null) { imageView.setImageBitmapResetBase(croppedImage, true); - imageView.center(true, true); + imageView.center(); imageView.highlightViews.clear(); } saveImage(croppedImage);