Skip to content

Commit 7a706d2

Browse files
committed
Merge pull request square#1032 from JohnWowUs/fix-rotate-dimension
Generalized dimension recalculation on rotation fixes
2 parents ceafe59 + beb6beb commit 7a706d2

File tree

2 files changed

+114
-9
lines changed

2 files changed

+114
-9
lines changed

picasso/src/main/java/com/squareup/picasso/BitmapHunter.java

Lines changed: 54 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -504,16 +504,69 @@ static Bitmap transformResult(Request data, Bitmap result, int exifOrientation)
504504

505505
Matrix matrix = new Matrix();
506506

507-
if (data.needsMatrixTransform()) {
507+
if (data.needsMatrixTransform() || exifOrientation != 0) {
508508
int targetWidth = data.targetWidth;
509509
int targetHeight = data.targetHeight;
510510

511511
float targetRotation = data.rotationDegrees;
512512
if (targetRotation != 0) {
513+
double cosR = Math.cos(Math.toRadians(targetRotation));
514+
double sinR = Math.sin(Math.toRadians(targetRotation));
513515
if (data.hasRotationPivot) {
514516
matrix.setRotate(targetRotation, data.rotationPivotX, data.rotationPivotY);
517+
// Recalculate dimensions after rotation around pivot point
518+
double x1T = data.rotationPivotX * (1.0 - cosR) + (data.rotationPivotY * sinR);
519+
double y1T = data.rotationPivotY * (1.0 - cosR) - (data.rotationPivotX * sinR);
520+
double x2T = x1T + (data.targetWidth * cosR);
521+
double y2T = y1T + (data.targetWidth * sinR);
522+
double x3T = x1T + (data.targetWidth * cosR) - (data.targetHeight * sinR);
523+
double y3T = y1T + (data.targetWidth * sinR) + (data.targetHeight * cosR);
524+
double x4T = x1T - (data.targetHeight * sinR);
525+
double y4T = y1T + (data.targetHeight * cosR);
526+
527+
double maxX = Math.max(x4T, Math.max(x3T, Math.max(x1T, x2T)));
528+
double minX = Math.min(x4T, Math.min(x3T, Math.min(x1T, x2T)));
529+
double maxY = Math.max(y4T, Math.max(y3T, Math.max(y1T, y2T)));
530+
double minY = Math.min(y4T, Math.min(y3T, Math.min(y1T, y2T)));
531+
targetWidth = (int) Math.floor(maxX - minX);
532+
targetHeight = (int) Math.floor(maxY - minY);
515533
} else {
516534
matrix.setRotate(targetRotation);
535+
// Recalculate dimensions after rotation (around origin)
536+
double x1T = 0.0;
537+
double y1T = 0.0;
538+
double x2T = (data.targetWidth * cosR);
539+
double y2T = (data.targetWidth * sinR);
540+
double x3T = (data.targetWidth * cosR) - (data.targetHeight * sinR);
541+
double y3T = (data.targetWidth * sinR) + (data.targetHeight * cosR);
542+
double x4T = -(data.targetHeight * sinR);
543+
double y4T = (data.targetHeight * cosR);
544+
545+
double maxX = Math.max(x4T, Math.max(x3T, Math.max(x1T, x2T)));
546+
double minX = Math.min(x4T, Math.min(x3T, Math.min(x1T, x2T)));
547+
double maxY = Math.max(y4T, Math.max(y3T, Math.max(y1T, y2T)));
548+
double minY = Math.min(y4T, Math.min(y3T, Math.min(y1T, y2T)));
549+
targetWidth = (int) Math.floor(maxX - minX);
550+
targetHeight = (int) Math.floor(maxY - minY);
551+
}
552+
}
553+
554+
// EXIf interpretation should be done before cropping in case the dimensions need to
555+
// be recalculated
556+
if (exifOrientation != 0) {
557+
int exifRotation = getExifRotation(exifOrientation);
558+
int exifTranslation = getExifTranslation(exifOrientation);
559+
if (exifRotation != 0) {
560+
matrix.preRotate(exifRotation);
561+
if (exifRotation == 90 || exifRotation == 270) {
562+
// Recalculate dimensions after exif rotation
563+
int tmpHeight = targetHeight;
564+
targetHeight = targetWidth;
565+
targetWidth = tmpHeight;
566+
}
567+
}
568+
if (exifTranslation != 1) {
569+
matrix.postScale(exifTranslation, 1);
517570
}
518571
}
519572

@@ -569,14 +622,6 @@ static Bitmap transformResult(Request data, Bitmap result, int exifOrientation)
569622
}
570623
}
571624

572-
if (exifOrientation != 0) {
573-
matrix.preRotate(getExifRotation(exifOrientation));
574-
int exifTranslation = getExifTranslation(exifOrientation);
575-
if (exifTranslation != 1) {
576-
matrix.postScale(exifTranslation, 1);
577-
}
578-
}
579-
580625
Bitmap newResult =
581626
Bitmap.createBitmap(result, drawX, drawY, drawWidth, drawHeight, matrix, true);
582627
if (newResult != result) {

picasso/src/test/java/com/squareup/picasso/BitmapHunterTest.java

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -422,6 +422,66 @@ public class BitmapHunterTest {
422422
assertThat(shadowMatrix.getPreOperations()).containsOnly("rotate 90.0");
423423
}
424424

425+
@Test public void exifRotationSizing() throws Exception {
426+
Request data = new Request.Builder(URI_1).resize(5, 10).build();
427+
Bitmap source = Bitmap.createBitmap(10, 10, ARGB_8888);
428+
Bitmap result = transformResult(data, source, ORIENTATION_ROTATE_90);
429+
ShadowBitmap shadowBitmap = shadowOf(result);
430+
assertThat(shadowBitmap.getCreatedFromBitmap()).isSameAs(source);
431+
432+
Matrix matrix = shadowBitmap.getCreatedFromMatrix();
433+
ShadowMatrix shadowMatrix = shadowOf(matrix);
434+
assertThat(shadowMatrix.getPreOperations()).contains("scale 1.0 0.5");
435+
}
436+
437+
@Test public void exifRotationNoSizing() throws Exception {
438+
Request data = new Request.Builder(URI_1).build();
439+
Bitmap source = Bitmap.createBitmap(10, 10, ARGB_8888);
440+
Bitmap result = transformResult(data, source, ORIENTATION_ROTATE_90);
441+
ShadowBitmap shadowBitmap = shadowOf(result);
442+
assertThat(shadowBitmap.getCreatedFromBitmap()).isSameAs(source);
443+
444+
Matrix matrix = shadowBitmap.getCreatedFromMatrix();
445+
ShadowMatrix shadowMatrix = shadowOf(matrix);
446+
assertThat(shadowMatrix.getPreOperations()).contains("rotate 90.0");
447+
}
448+
449+
@Test public void rotation90Sizing() throws Exception {
450+
Request data = new Request.Builder(URI_1).rotate(90).resize(5, 10).build();
451+
Bitmap source = Bitmap.createBitmap(10, 10, ARGB_8888);
452+
Bitmap result = transformResult(data, source, 0);
453+
ShadowBitmap shadowBitmap = shadowOf(result);
454+
assertThat(shadowBitmap.getCreatedFromBitmap()).isSameAs(source);
455+
456+
Matrix matrix = shadowBitmap.getCreatedFromMatrix();
457+
ShadowMatrix shadowMatrix = shadowOf(matrix);
458+
assertThat(shadowMatrix.getPreOperations()).contains("scale 1.0 0.5");
459+
}
460+
461+
@Test public void rotation180Sizing() throws Exception {
462+
Request data = new Request.Builder(URI_1).rotate(180).resize(5, 10).build();
463+
Bitmap source = Bitmap.createBitmap(10, 10, ARGB_8888);
464+
Bitmap result = transformResult(data, source, 0);
465+
ShadowBitmap shadowBitmap = shadowOf(result);
466+
assertThat(shadowBitmap.getCreatedFromBitmap()).isSameAs(source);
467+
468+
Matrix matrix = shadowBitmap.getCreatedFromMatrix();
469+
ShadowMatrix shadowMatrix = shadowOf(matrix);
470+
assertThat(shadowMatrix.getPreOperations()).contains("scale 0.5 1.0");
471+
}
472+
473+
@Test public void rotation90WithPivotSizing() throws Exception {
474+
Request data = new Request.Builder(URI_1).rotate(90,0,10).resize(5, 10).build();
475+
Bitmap source = Bitmap.createBitmap(10, 10, ARGB_8888);
476+
Bitmap result = transformResult(data, source, 0);
477+
ShadowBitmap shadowBitmap = shadowOf(result);
478+
assertThat(shadowBitmap.getCreatedFromBitmap()).isSameAs(source);
479+
480+
Matrix matrix = shadowBitmap.getCreatedFromMatrix();
481+
ShadowMatrix shadowMatrix = shadowOf(matrix);
482+
assertThat(shadowMatrix.getPreOperations()).contains("scale 1.0 0.5");
483+
}
484+
425485
@Test public void exifVerticalFlip() {
426486
Request data = new Request.Builder(URI_1).rotate(-45).build();
427487
Bitmap source = Bitmap.createBitmap(10, 10, ARGB_8888);

0 commit comments

Comments
 (0)