diff --git a/RapidFTR-Android/src/main/java/com/rapidftr/adapter/ImageAdapter.java b/RapidFTR-Android/src/main/java/com/rapidftr/adapter/ImageAdapter.java index 1b0fa247..69d69145 100644 --- a/RapidFTR-Android/src/main/java/com/rapidftr/adapter/ImageAdapter.java +++ b/RapidFTR-Android/src/main/java/com/rapidftr/adapter/ImageAdapter.java @@ -15,7 +15,9 @@ public class ImageAdapter extends BaseAdapter { - private final Child child; + public static final int NO_PADDING = 0; + + private final Child child; private final boolean enabled; private final PhotoCaptureHelper photoCaptureHelper; private final Context context; @@ -53,7 +55,7 @@ public View getView(int position, View convertView, ViewGroup parent) { try { bitmap = photoCaptureHelper.getThumbnailOrDefault(photoKeys.get(position).toString()); imageView = new ImageView(context); - imageView.setPadding(0,0,0,0); + imageView.setPadding(NO_PADDING, NO_PADDING, NO_PADDING, NO_PADDING); imageView.setAdjustViewBounds(true); imageView.setImageBitmap(bitmap); } catch (JSONException e) { diff --git a/RapidFTR-Android/src/main/java/com/rapidftr/utils/PhotoCaptureHelper.java b/RapidFTR-Android/src/main/java/com/rapidftr/utils/PhotoCaptureHelper.java index 0fdf1099..dbc9c431 100644 --- a/RapidFTR-Android/src/main/java/com/rapidftr/utils/PhotoCaptureHelper.java +++ b/RapidFTR-Android/src/main/java/com/rapidftr/utils/PhotoCaptureHelper.java @@ -22,7 +22,13 @@ public class PhotoCaptureHelper extends CaptureHelper { - public PhotoCaptureHelper(RapidFtrApplication context) { + public static final int THUMBNAIL_WIDTH = 96; + public static final int THUMBNAIL_HEIGHT = 96; + public static final int JPEG_QUALITY = 85; + public static final int PHOTO_WIDTH = 475; + public static final int PHOTO_HEIGHT = 635; + + public PhotoCaptureHelper(RapidFtrApplication context) { super(context); } @@ -90,24 +96,41 @@ public Bitmap getDefaultThumbnail() { } public void savePhoto(Bitmap bitmap, int rotationDegree, String fileNameWithoutExtension) throws IOException, GeneralSecurityException { - save(rotateBitmap(scaleImageTo(bitmap, 475, 635), rotationDegree), fileNameWithoutExtension); + Bitmap rotated = rotateBitmap(bitmap, rotationDegree); + Bitmap scaled = scaleImageTo(rotated, PHOTO_WIDTH, PHOTO_HEIGHT); + save(scaled, fileNameWithoutExtension); } - protected Bitmap scaleImageTo(Bitmap image, int width, int height) { + protected Bitmap resizeImageTo(Bitmap image, int width, int height) { return Bitmap.createScaledBitmap(image, width, height, false); } + protected Bitmap scaleImageTo(Bitmap image, int maxWidth, int maxHeight) { + double givenWidth = image.getWidth(), givenHeight = image.getHeight(); + double scaleRatio = 1.0; + + if (givenWidth > maxWidth || givenHeight > maxHeight) { + if (givenWidth > givenHeight) { + scaleRatio = maxWidth / givenWidth; + } else { + scaleRatio = maxHeight / givenHeight; + } + } + + return resizeImageTo(image, (int) (givenWidth * scaleRatio), (int) (givenHeight * scaleRatio)); + } + protected void save(Bitmap bitmap, String fileNameWithoutExtension) throws IOException, GeneralSecurityException { fileNameWithoutExtension = fileNameWithoutExtension.contains(".jpg")? fileNameWithoutExtension : fileNameWithoutExtension + ".jpg"; File file = new File(getDir(), fileNameWithoutExtension); if (!file.exists()) file.createNewFile(); @Cleanup OutputStream outputStream = getCipherOutputStream(file); - bitmap.compress(Bitmap.CompressFormat.JPEG, 85, outputStream); + bitmap.compress(Bitmap.CompressFormat.JPEG, JPEG_QUALITY, outputStream); } public void saveThumbnail(Bitmap bitmap, int rotationDegree, String fileNameWithoutExtension) throws IOException, GeneralSecurityException { - save(rotateBitmap(scaleImageTo(bitmap, 96, 96), rotationDegree), fileNameWithoutExtension + "_thumb"); + save(resizeImageTo(rotateBitmap(bitmap, rotationDegree), THUMBNAIL_WIDTH, THUMBNAIL_HEIGHT), fileNameWithoutExtension + "_thumb"); } public Bitmap loadThumbnail(String fileNameWithoutExtension) throws IOException, GeneralSecurityException { diff --git a/RapidFTR-Android/src/test/java/com/rapidftr/utils/PhotoCaptureHelperTest.java b/RapidFTR-Android/src/test/java/com/rapidftr/utils/PhotoCaptureHelperTest.java index 9df2fa7f..66776509 100644 --- a/RapidFTR-Android/src/test/java/com/rapidftr/utils/PhotoCaptureHelperTest.java +++ b/RapidFTR-Android/src/test/java/com/rapidftr/utils/PhotoCaptureHelperTest.java @@ -25,6 +25,7 @@ import static org.hamcrest.core.StringStartsWith.startsWith; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; +import static org.mockito.BDDMockito.given; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.*; @@ -122,8 +123,8 @@ public void testReturnOriginalThumbnail() throws Exception { @Test public void testSaveThumbnailShouldResizeAndSave() throws Exception { Bitmap original = mock(Bitmap.class), expected = mock(Bitmap.class); - doReturn(expected).when(photoCaptureHelper).scaleImageTo(original, 96, 96); - doReturn(expected).when(photoCaptureHelper).rotateBitmap(expected, 90); + doReturn(expected).when(photoCaptureHelper).rotateBitmap(original, 90); + doReturn(expected).when(photoCaptureHelper).resizeImageTo(expected, 96, 96); doNothing().when(photoCaptureHelper).save(expected, "random_file_thumb"); photoCaptureHelper.saveThumbnail(original, 90, "random_file"); @@ -133,8 +134,8 @@ public void testSaveThumbnailShouldResizeAndSave() throws Exception { @Test public void testSaveActualImageShouldResizeAndSave() throws Exception { Bitmap original = mock(Bitmap.class), expected = mock(Bitmap.class); - doReturn(expected).when(photoCaptureHelper).scaleImageTo(original, 475, 635); - doReturn(expected).when(photoCaptureHelper).rotateBitmap(expected, 180); + doReturn(expected).when(photoCaptureHelper).rotateBitmap(original, 180); + doReturn(expected).when(photoCaptureHelper).scaleImageTo(expected, 475, 635); doNothing().when(photoCaptureHelper).save(expected, "random_file"); photoCaptureHelper.savePhoto(original, 180, "random_file"); verify(photoCaptureHelper).save(expected, "random_file"); @@ -161,6 +162,66 @@ public void testShouldReturnRotationInfoOfPicture() throws IOException { assertEquals(90, rotation); } + @Test + public void testScaleImagePreserveAspectRatioHorizontally() throws Exception { + Bitmap bitmap = mock(Bitmap.class); + int maxWidth = 100, maxHeight = 100; + int givenWidth = 300, givenHeight = 200; + int expectedWidth = 100, expectedHeight = 66; + + given(bitmap.getWidth()).willReturn(givenWidth); + given(bitmap.getHeight()).willReturn(givenHeight); + doReturn(bitmap).when(photoCaptureHelper).resizeImageTo(bitmap, expectedWidth, expectedHeight); + + // If you get exception here - then it means resizeImageTo was not called with proper passing arguments + assertThat(bitmap, equalTo(photoCaptureHelper.scaleImageTo(bitmap, maxWidth, maxHeight))); + } + + @Test + public void testScaleImagePreserveAspectRatioVertically() throws Exception { + Bitmap bitmap = mock(Bitmap.class); + int maxWidth = 100, maxHeight = 100; + int givenWidth = 200, givenHeight = 300; + int expectedWidth = 66, expectedHeight = 100; + + given(bitmap.getWidth()).willReturn(givenWidth); + given(bitmap.getHeight()).willReturn(givenHeight); + doReturn(bitmap).when(photoCaptureHelper).resizeImageTo(bitmap, expectedWidth, expectedHeight); + + // If you get exception here - then it means resizeImageTo was not called with proper passing arguments + assertThat(bitmap, equalTo(photoCaptureHelper.scaleImageTo(bitmap, maxWidth, maxHeight))); + } + + @Test + public void testScaleImagePreserveAspectRatioHorizontally2() throws Exception { + Bitmap bitmap = mock(Bitmap.class); + int maxWidth = 100, maxHeight = 100; + int givenWidth = 200, givenHeight = 50; + int expectedWidth = 100, expectedHeight = 25; + + given(bitmap.getWidth()).willReturn(givenWidth); + given(bitmap.getHeight()).willReturn(givenHeight); + doReturn(bitmap).when(photoCaptureHelper).resizeImageTo(bitmap, expectedWidth, expectedHeight); + + // If you get exception here - then it means resizeImageTo was not called with proper passing arguments + assertThat(bitmap, equalTo(photoCaptureHelper.scaleImageTo(bitmap, maxWidth, maxHeight))); + } + + @Test + public void testScaleImagePreserveAspectRatioVertically2() throws Exception { + Bitmap bitmap = mock(Bitmap.class); + int maxWidth = 100, maxHeight = 100; + int givenWidth = 50, givenHeight = 200; + int expectedWidth = 25, expectedHeight = 100; + + given(bitmap.getWidth()).willReturn(givenWidth); + given(bitmap.getHeight()).willReturn(givenHeight); + doReturn(bitmap).when(photoCaptureHelper).resizeImageTo(bitmap, expectedWidth, expectedHeight); + + // If you get exception here - then it means resizeImageTo was not called with proper passing arguments + assertThat(bitmap, equalTo(photoCaptureHelper.scaleImageTo(bitmap, maxWidth, maxHeight))); + } + @After public void resetSharedDirectory() { try {