30
30
import android .os .Bundle ;
31
31
import android .os .Handler ;
32
32
import android .provider .MediaStore ;
33
+ import android .util .Pair ;
33
34
import android .view .View ;
34
35
import android .view .Window ;
35
36
import android .view .WindowManager ;
@@ -56,6 +57,7 @@ public class CropImageActivity extends MonitoredActivity {
56
57
private int maxX ;
57
58
private int maxY ;
58
59
private int exifRotation ;
60
+ private int exifScale ;
59
61
private boolean saveAsPng ;
60
62
61
63
private Uri sourceUri ;
@@ -64,7 +66,7 @@ public class CropImageActivity extends MonitoredActivity {
64
66
private boolean isSaving ;
65
67
66
68
private int sampleSize ;
67
- private RotateBitmap rotateBitmap ;
69
+ private Bitmap srcBitmap ;
68
70
private CropImageView imageView ;
69
71
private HighlightView cropView ;
70
72
@@ -75,7 +77,7 @@ public void onCreate(Bundle icicle) {
75
77
setupViews ();
76
78
77
79
loadInput ();
78
- if (rotateBitmap == null ) {
80
+ if (srcBitmap == null ) {
79
81
finish ();
80
82
return ;
81
83
}
@@ -120,6 +122,7 @@ public void onClick(View v) {
120
122
private void loadInput () {
121
123
Intent intent = getIntent ();
122
124
Bundle extras = intent .getExtras ();
125
+ Bitmap initialBitmap ;
123
126
124
127
if (extras != null ) {
125
128
aspectX = extras .getInt (Crop .Extra .ASPECT_X );
@@ -132,15 +135,32 @@ private void loadInput() {
132
135
133
136
sourceUri = intent .getData ();
134
137
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 ;
137
143
InputStream is = null ;
138
144
try {
139
145
sampleSize = calculateBitmapSampleSize (sourceUri );
140
146
is = getContentResolver ().openInputStream (sourceUri );
141
147
BitmapFactory .Options option = new BitmapFactory .Options ();
142
148
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
+ }
144
164
} catch (IOException e ) {
145
165
Log .e ("Error reading image: " + e .getMessage (), e );
146
166
setResultException (e );
@@ -151,6 +171,9 @@ private void loadInput() {
151
171
CropUtil .closeSilently (is );
152
172
}
153
173
}
174
+ else {
175
+ Log .e ("Source URI is null" );
176
+ }
154
177
}
155
178
156
179
private int calculateBitmapSampleSize (Uri bitmapUri ) throws IOException {
@@ -192,7 +215,7 @@ private void startCrop() {
192
215
if (isFinishing ()) {
193
216
return ;
194
217
}
195
- imageView .setImageRotateBitmapResetBase ( rotateBitmap , true );
218
+ imageView .setImageBitmapResetBase ( srcBitmap , true );
196
219
CropUtil .startBackgroundJob (this , null , getResources ().getString (R .string .crop__wait ),
197
220
new Runnable () {
198
221
public void run () {
@@ -219,13 +242,13 @@ public void run() {
219
242
private class Cropper {
220
243
221
244
private void makeDefault () {
222
- if (rotateBitmap == null ) {
245
+ if (srcBitmap == null ) {
223
246
return ;
224
247
}
225
248
226
249
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 ();
229
252
230
253
Rect imageRect = new Rect (0 , 0 , width , height );
231
254
@@ -297,7 +320,7 @@ private void onSaveClicked() {
297
320
}
298
321
299
322
if (croppedImage != null ) {
300
- imageView .setImageRotateBitmapResetBase ( new RotateBitmap ( croppedImage , exifRotation ) , true );
323
+ imageView .setImageBitmapResetBase ( croppedImage , true );
301
324
imageView .center ();
302
325
imageView .highlightViews .clear ();
303
326
}
@@ -322,20 +345,20 @@ public void run() {
322
345
private Bitmap decodeRegionCrop (Rect rect , int outWidth , int outHeight ) {
323
346
// Release memory now
324
347
clearImageView ();
325
-
348
+ Matrix matrix = new Matrix ();
326
349
InputStream is = null ;
327
350
Bitmap croppedImage = null ;
351
+ boolean transformed = false ;
328
352
try {
329
353
is = getContentResolver ().openInputStream (sourceUri );
330
354
BitmapRegionDecoder decoder = BitmapRegionDecoder .newInstance (is , false );
331
355
final int width = decoder .getWidth ();
332
356
final int height = decoder .getHeight ();
333
357
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 );
339
362
RectF adjusted = new RectF ();
340
363
matrix .mapRect (adjusted , new RectF (rect ));
341
364
@@ -345,11 +368,20 @@ private Bitmap decodeRegionCrop(Rect rect, int outWidth, int outHeight) {
345
368
}
346
369
347
370
try {
371
+ matrix .reset ();
348
372
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 );
353
385
}
354
386
} catch (IllegalArgumentException e ) {
355
387
// Rethrow with some extra information
@@ -371,8 +403,8 @@ private Bitmap decodeRegionCrop(Rect rect, int outWidth, int outHeight) {
371
403
372
404
private void clearImageView () {
373
405
imageView .clear ();
374
- if (rotateBitmap != null ) {
375
- rotateBitmap .recycle ();
406
+ if (srcBitmap != null ) {
407
+ srcBitmap .recycle ();
376
408
}
377
409
System .gc ();
378
410
}
@@ -393,12 +425,6 @@ private void saveOutput(Bitmap croppedImage) {
393
425
} finally {
394
426
CropUtil .closeSilently (outputStream );
395
427
}
396
-
397
- CropUtil .copyExifRotation (
398
- CropUtil .getFromMediaUri (this , getContentResolver (), sourceUri ),
399
- CropUtil .getFromMediaUri (this , getContentResolver (), saveUri )
400
- );
401
-
402
428
setResultUri (saveUri );
403
429
}
404
430
@@ -416,8 +442,8 @@ public void run() {
416
442
@ Override
417
443
protected void onDestroy () {
418
444
super .onDestroy ();
419
- if (rotateBitmap != null ) {
420
- rotateBitmap .recycle ();
445
+ if (srcBitmap != null ) {
446
+ srcBitmap .recycle ();
421
447
}
422
448
}
423
449
0 commit comments