Skip to content

Commit 76f1a06

Browse files
JohnWowUsGuillaume
authored and
Guillaume
committed
Exif fixes
1 parent 2f043d2 commit 76f1a06

File tree

2 files changed

+91
-44
lines changed

2 files changed

+91
-44
lines changed

lib/src/main/java/com/soundcloud/android/crop/CropImageActivity.java

+60-32
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
import android.os.Bundle;
3131
import android.os.Handler;
3232
import android.provider.MediaStore;
33+
import android.util.Pair;
3334
import android.view.View;
3435
import android.view.Window;
3536
import android.view.WindowManager;
@@ -56,6 +57,7 @@ public class CropImageActivity extends MonitoredActivity {
5657
private int maxX;
5758
private int maxY;
5859
private int exifRotation;
60+
private int exifScale;
5961
private boolean saveAsPng;
6062

6163
private Uri sourceUri;
@@ -64,7 +66,7 @@ public class CropImageActivity extends MonitoredActivity {
6466
private boolean isSaving;
6567

6668
private int sampleSize;
67-
private RotateBitmap rotateBitmap;
69+
private Bitmap srcBitmap;
6870
private CropImageView imageView;
6971
private HighlightView cropView;
7072

@@ -75,7 +77,7 @@ public void onCreate(Bundle icicle) {
7577
setupViews();
7678

7779
loadInput();
78-
if (rotateBitmap == null) {
80+
if (srcBitmap == null) {
7981
finish();
8082
return;
8183
}
@@ -120,6 +122,7 @@ public void onClick(View v) {
120122
private void loadInput() {
121123
Intent intent = getIntent();
122124
Bundle extras = intent.getExtras();
125+
Bitmap initialBitmap;
123126

124127
if (extras != null) {
125128
aspectX = extras.getInt(Crop.Extra.ASPECT_X);
@@ -132,15 +135,32 @@ private void loadInput() {
132135

133136
sourceUri = intent.getData();
134137
if (sourceUri != null) {
135-
exifRotation = CropUtil.getExifRotation(CropUtil.getFromMediaUri(this, getContentResolver(), sourceUri));
136-
138+
Pair<Integer,Integer> exifRotationTrans =
139+
CropUtil.getExifRotationTranslation(
140+
CropUtil.getFromMediaUri(this, getContentResolver(), sourceUri));
141+
exifRotation = exifRotationTrans.first;
142+
exifScale = exifRotationTrans.second;
137143
InputStream is = null;
138144
try {
139145
sampleSize = calculateBitmapSampleSize(sourceUri);
140146
is = getContentResolver().openInputStream(sourceUri);
141147
BitmapFactory.Options option = new BitmapFactory.Options();
142148
option.inSampleSize = sampleSize;
143-
rotateBitmap = new RotateBitmap(BitmapFactory.decodeStream(is, null, option), exifRotation);
149+
initialBitmap = BitmapFactory.decodeStream(is, null, option);
150+
int drawHeight = initialBitmap.getHeight();
151+
int drawWidth = initialBitmap.getWidth();
152+
if ((exifRotation != 0) || (exifScale != 1)) {
153+
Matrix matrix = new Matrix() ;
154+
if (exifRotation != 0) {
155+
matrix.preRotate(exifRotation);
156+
}
157+
if (exifScale != 1) {
158+
matrix.postScale(exifScale, 1);
159+
}
160+
srcBitmap = Bitmap.createBitmap(initialBitmap, 0, 0, drawWidth, drawHeight, matrix, true);
161+
} else {
162+
srcBitmap = initialBitmap ;
163+
}
144164
} catch (IOException e) {
145165
Log.e("Error reading image: " + e.getMessage(), e);
146166
setResultException(e);
@@ -151,6 +171,9 @@ private void loadInput() {
151171
CropUtil.closeSilently(is);
152172
}
153173
}
174+
else {
175+
Log.e("Source URI is null");
176+
}
154177
}
155178

156179
private int calculateBitmapSampleSize(Uri bitmapUri) throws IOException {
@@ -192,7 +215,7 @@ private void startCrop() {
192215
if (isFinishing()) {
193216
return;
194217
}
195-
imageView.setImageRotateBitmapResetBase(rotateBitmap, true);
218+
imageView.setImageBitmapResetBase(srcBitmap, true);
196219
CropUtil.startBackgroundJob(this, null, getResources().getString(R.string.crop__wait),
197220
new Runnable() {
198221
public void run() {
@@ -219,13 +242,13 @@ public void run() {
219242
private class Cropper {
220243

221244
private void makeDefault() {
222-
if (rotateBitmap == null) {
245+
if (srcBitmap == null) {
223246
return;
224247
}
225248

226249
HighlightView hv = new HighlightView(imageView);
227-
final int width = rotateBitmap.getWidth();
228-
final int height = rotateBitmap.getHeight();
250+
final int width = srcBitmap.getWidth();
251+
final int height = srcBitmap.getHeight();
229252

230253
Rect imageRect = new Rect(0, 0, width, height);
231254

@@ -277,6 +300,8 @@ private void onSaveClicked() {
277300

278301
int outWidth = width;
279302
int outHeight = height;
303+
Log.e("Crop Width = " + width);
304+
Log.e("Crop Height = " + height);
280305
if (maxX > 0 && maxY > 0 && (width > maxX || height > maxY)) {
281306
float ratio = (float) width / (float) height;
282307
if ((float) maxX / (float) maxY > ratio) {
@@ -297,7 +322,7 @@ private void onSaveClicked() {
297322
}
298323

299324
if (croppedImage != null) {
300-
imageView.setImageRotateBitmapResetBase(new RotateBitmap(croppedImage, exifRotation), true);
325+
imageView.setImageBitmapResetBase(croppedImage, true);
301326
imageView.center();
302327
imageView.highlightViews.clear();
303328
}
@@ -320,22 +345,20 @@ public void run() {
320345
}
321346

322347
private Bitmap decodeRegionCrop(Rect rect, int outWidth, int outHeight) {
323-
// Release memory now
324-
clearImageView();
325-
348+
Matrix matrix = new Matrix();
326349
InputStream is = null;
327350
Bitmap croppedImage = null;
351+
boolean transformed = false;
328352
try {
329353
is = getContentResolver().openInputStream(sourceUri);
330354
BitmapRegionDecoder decoder = BitmapRegionDecoder.newInstance(is, false);
331355
final int width = decoder.getWidth();
332356
final int height = decoder.getHeight();
333357

334-
if (exifRotation != 0) {
335-
// Adjust crop area to account for image rotation
336-
Matrix matrix = new Matrix();
337-
matrix.setRotate(-exifRotation);
338-
358+
if ((exifRotation != 0) || (exifScale != 1)) {
359+
// Adjust crop area to account for EXIF transformation so what you crop is what you get
360+
matrix.preRotate(-exifRotation);
361+
matrix.postScale(exifScale, 1);
339362
RectF adjusted = new RectF();
340363
matrix.mapRect(adjusted, new RectF(rect));
341364

@@ -345,11 +368,20 @@ private Bitmap decodeRegionCrop(Rect rect, int outWidth, int outHeight) {
345368
}
346369

347370
try {
371+
matrix.reset();
348372
croppedImage = decoder.decodeRegion(rect, new BitmapFactory.Options());
349-
if (croppedImage != null && (rect.width() > outWidth || rect.height() > outHeight)) {
350-
Matrix matrix = new Matrix();
351-
matrix.postScale((float) outWidth / rect.width(), (float) outHeight / rect.height());
352-
croppedImage = Bitmap.createBitmap(croppedImage, 0, 0, croppedImage.getWidth(), croppedImage.getHeight(), matrix, true);
373+
if ((exifRotation != 0) || (exifScale != 1)) {
374+
transformed = true;
375+
// Remove the EXIF transformation from the cropped image so we can dispense with it altogether
376+
matrix.preRotate(exifRotation);
377+
matrix.postScale(exifScale, 1);
378+
}
379+
if (rect.width() > outWidth || rect.height() > outHeight) {
380+
transformed = true ;
381+
matrix.postScale(((float)outWidth)/((float)rect.width()), ((float)outHeight)/((float)rect.height()));
382+
}
383+
if (transformed) {
384+
croppedImage = Bitmap.createBitmap(croppedImage, 0, 0, croppedImage.getWidth(), croppedImage.getHeight(), matrix, true);
353385
}
354386
} catch (IllegalArgumentException e) {
355387
// Rethrow with some extra information
@@ -365,14 +397,16 @@ private Bitmap decodeRegionCrop(Rect rect, int outWidth, int outHeight) {
365397
setResultException(e);
366398
} finally {
367399
CropUtil.closeSilently(is);
400+
// Release memory now
401+
clearImageView();
368402
}
369403
return croppedImage;
370404
}
371405

372406
private void clearImageView() {
373407
imageView.clear();
374-
if (rotateBitmap != null) {
375-
rotateBitmap.recycle();
408+
if (srcBitmap != null) {
409+
srcBitmap.recycle();
376410
}
377411
System.gc();
378412
}
@@ -393,12 +427,6 @@ private void saveOutput(Bitmap croppedImage) {
393427
} finally {
394428
CropUtil.closeSilently(outputStream);
395429
}
396-
397-
CropUtil.copyExifRotation(
398-
CropUtil.getFromMediaUri(this, getContentResolver(), sourceUri),
399-
CropUtil.getFromMediaUri(this, getContentResolver(), saveUri)
400-
);
401-
402430
setResultUri(saveUri);
403431
}
404432

@@ -416,8 +444,8 @@ public void run() {
416444
@Override
417445
protected void onDestroy() {
418446
super.onDestroy();
419-
if (rotateBitmap != null) {
420-
rotateBitmap.recycle();
447+
if (srcBitmap != null) {
448+
srcBitmap.recycle();
421449
}
422450
}
423451

lib/src/main/java/com/soundcloud/android/crop/CropUtil.java

+31-12
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import android.provider.MediaStore;
2828
import android.support.annotation.Nullable;
2929
import android.text.TextUtils;
30+
import android.util.Pair;
3031

3132
import java.io.Closeable;
3233
import java.io.File;
@@ -52,25 +53,43 @@ public static void closeSilently(@Nullable Closeable c) {
5253
}
5354
}
5455

55-
public static int getExifRotation(File imageFile) {
56-
if (imageFile == null) return 0;
56+
public static Pair<Integer,Integer> getExifRotationTranslation(File imageFile) {
57+
int exifRotation = 0, exifScale = 1;
58+
if (imageFile == null) return new Pair<Integer,Integer>(0,1);
5759
try {
5860
ExifInterface exif = new ExifInterface(imageFile.getAbsolutePath());
59-
// We only recognize a subset of orientation tag values
6061
switch (exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_UNDEFINED)) {
61-
case ExifInterface.ORIENTATION_ROTATE_90:
62-
return 90;
63-
case ExifInterface.ORIENTATION_ROTATE_180:
64-
return 180;
65-
case ExifInterface.ORIENTATION_ROTATE_270:
66-
return 270;
67-
default:
68-
return ExifInterface.ORIENTATION_UNDEFINED;
62+
case ExifInterface.ORIENTATION_UNDEFINED:
63+
case ExifInterface.ORIENTATION_NORMAL:
64+
break ;
65+
case ExifInterface.ORIENTATION_FLIP_HORIZONTAL:
66+
exifScale=-1;
67+
break;
68+
case ExifInterface.ORIENTATION_ROTATE_180:
69+
exifRotation = 180;
70+
break;
71+
case ExifInterface.ORIENTATION_FLIP_VERTICAL:
72+
exifRotation = 180;
73+
exifScale=-1;
74+
break;
75+
case ExifInterface.ORIENTATION_TRANSPOSE:
76+
exifRotation = 90;
77+
exifScale=-1;
78+
break;
79+
case ExifInterface.ORIENTATION_ROTATE_90:
80+
exifRotation = 90;
81+
break;
82+
case ExifInterface.ORIENTATION_TRANSVERSE:
83+
exifRotation = 270;
84+
exifScale=-1;
85+
break;
86+
case ExifInterface.ORIENTATION_ROTATE_270:
87+
exifRotation = 270;
6988
}
7089
} catch (IOException e) {
7190
Log.e("Error getting Exif data", e);
72-
return 0;
7391
}
92+
return new Pair<Integer,Integer>(exifRotation,exifScale);
7493
}
7594

7695
public static boolean copyExifRotation(File sourceFile, File destFile) {

0 commit comments

Comments
 (0)