Skip to content

Commit

Permalink
Merge pull request getodk#2020 from shobhitagarwal1612/FileUtils-tests
Browse files Browse the repository at this point in the history
Adds some tests for bitmap scaling utility method and code refactoring
  • Loading branch information
lognaturel authored Apr 2, 2018
2 parents 9496043 + f81bf9d commit 4059ed1
Show file tree
Hide file tree
Showing 9 changed files with 143 additions and 94 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
package org.odk.collect.android.utilities;

import android.graphics.Bitmap;
import android.support.test.runner.AndroidJUnit4;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.odk.collect.android.application.Collect;

import java.io.File;

import static org.junit.Assert.assertEquals;


@RunWith(AndroidJUnit4.class)
public class BitmapScaledToDisplayTest {

@Test
@SuppressWarnings("ParenPad")
public void scaleDownBitmapWhenPossible() {
runScaleTest(1000, 1000, 500, 500, 500, 500, false);
runScaleTest( 600, 800, 600, 200, 150, 200, false);
runScaleTest( 500, 400, 250, 200, 250, 200, false);
runScaleTest(2000, 800, 300, 400, 333, 133, false);
}

@Test
@SuppressWarnings("ParenPad")
public void doNotScaleDownBitmapWhenNotPossible() {
runScaleTest(1000, 1000, 2000, 2000, 1000, 1000, false);
runScaleTest( 600, 800, 600, 800, 600, 800, false);
runScaleTest( 500, 400, 600, 600, 500, 400, false);
runScaleTest(2000, 800, 4000, 2000, 2000, 800, false);
}

@Test
@SuppressWarnings("ParenPad")
public void accuratelyScaleBitmapToDisplay() {
runScaleTest(1000, 1000, 500, 500, 500, 500, true);
runScaleTest( 600, 800, 600, 200, 150, 200, true);
runScaleTest( 500, 400, 250, 200, 250, 200, true);
runScaleTest(2000, 800, 300, 400, 300, 120, true);
runScaleTest(1000, 1000, 2000, 2000, 2000, 2000, true);
runScaleTest( 600, 800, 600, 800, 600, 800, true);
runScaleTest( 500, 400, 600, 600, 600, 480, true);
runScaleTest(2000, 800, 4000, 2000, 4000, 1600, true);
}

private void runScaleTest(int imageHeight, int imageWidth, int windowHeight, int windowWidth, int expectedHeight, int expectedWidth, boolean shouldScaleAccurately) {
new ScaleImageTest()
.createBitmap(imageHeight, imageWidth)
.scaleBitmapToDisplay(windowHeight, windowWidth, shouldScaleAccurately)
.assertScaledBitmapDimensions(expectedHeight, expectedWidth);
}

private static class ScaleImageTest {
private final File cache = Collect.getInstance().getApplicationContext().getExternalCacheDir();
private final File imageFile = new File(cache, "testImage.jpeg");
private Bitmap scaledBitmap;

ScaleImageTest createBitmap(int imageHeight, int imageWidth) {
Bitmap bitmap = Bitmap.createBitmap(imageWidth, imageHeight, Bitmap.Config.ARGB_8888);
FileUtils.saveBitmapToFile(bitmap, imageFile.getAbsolutePath());
return this;
}

ScaleImageTest scaleBitmapToDisplay(int windowHeight, int windowWidth, boolean shouldScaleAccurately) {
scaledBitmap = FileUtils.getBitmapScaledToDisplay(imageFile, windowHeight, windowWidth, shouldScaleAccurately);
return this;
}

void assertScaledBitmapDimensions(int expectedHeight, int expectedWidth) {
assertEquals(expectedHeight, scaledBitmap.getHeight());
assertEquals(expectedWidth, scaledBitmap.getWidth());
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -71,19 +71,12 @@ public static String getMimeType(String fileUrl) throws IOException {
}

public static boolean createFolder(String path) {
boolean made = true;
File dir = new File(path);
if (!dir.exists()) {
made = dir.mkdirs();
}
return made;
return dir.exists() || dir.mkdirs();
}

public static byte[] getFileAsBytes(File file) {
byte[] bytes = null;
InputStream is = null;
try {
is = new FileInputStream(file);
try (InputStream is = new FileInputStream(file)) {

// Get the size of the file
long length = file.length();
Expand All @@ -93,7 +86,7 @@ public static byte[] getFileAsBytes(File file) {
}

// Create the byte array to hold the data
bytes = new byte[(int) length];
byte[] bytes = new byte[(int) length];

// Read in the bytes
int offset = 0;
Expand Down Expand Up @@ -123,15 +116,9 @@ public static byte[] getFileAsBytes(File file) {
} catch (FileNotFoundException e) {
Timber.d(e, "Cannot find file %s", file.getName());
return null;

} finally {
// Close the input stream
try {
is.close();
} catch (IOException e) {
Timber.e(e, "Cannot close input stream for file %s", file.getName());
return null;
}
} catch (IOException e) {
Timber.e(e, "Cannot close input stream for file %s", file.getName());
return null;
}
}

Expand All @@ -149,7 +136,7 @@ public static String getMd5Hash(File file) {
return getMd5Hash(is);
}

public static String getMd5Hash(InputStream is) {
private static String getMd5Hash(InputStream is) {
try {
MessageDigest md = MessageDigest.getInstance("MD5");
final byte[] buffer = new byte[bufSize];
Expand All @@ -162,13 +149,13 @@ public static String getMd5Hash(InputStream is) {
md.update(buffer, 0, result);
}

String md5 = new BigInteger(1, md.digest()).toString(16);
StringBuilder md5 = new StringBuilder(new BigInteger(1, md.digest()).toString(16));
while (md5.length() < 32) {
md5 = "0" + md5;
md5.insert(0, "0");
}

is.close();
return md5;
return md5.toString();

} catch (NoSuchAlgorithmException e) {
Timber.e(e);
Expand All @@ -180,69 +167,66 @@ public static String getMd5Hash(InputStream is) {
}
}


public static Bitmap getBitmapScaledToDisplay(File f, int screenHeight, int screenWidth) {
// Determine image size of f
BitmapFactory.Options o = new BitmapFactory.Options();
o.inJustDecodeBounds = true;
getBitmap(f.getAbsolutePath(), o);

int heightScale = o.outHeight / screenHeight;
int widthScale = o.outWidth / screenWidth;

// Powers of 2 work faster, sometimes, according to the doc.
// We're just doing closest size that still fills the screen.
int scale = Math.max(widthScale, heightScale);

// get bitmap with scale ( < 1 is the same as 1)
BitmapFactory.Options options = new BitmapFactory.Options();
options.inInputShareable = true;
options.inPurgeable = true;
options.inSampleSize = scale;
Bitmap b = getBitmap(f.getAbsolutePath(), options);
if (b != null) {
Timber.i("Screen is %dx%d. Image has been scaled down by %d to %dx%d",
screenHeight, screenWidth, scale, b.getHeight(), b.getWidth());
}
return b;
public static Bitmap getBitmapScaledToDisplay(File file, int screenHeight, int screenWidth) {
return getBitmapScaledToDisplay(file, screenHeight, screenWidth, false);
}

/**
* With this method we do not care about efficient decoding and focus
* more on a precise scaling to maximize use of space on the screen
* Scales image according to the given display
*
* @param file containing the image
* @param screenHeight height of the display
* @param screenWidth width of the display
* @param upscaleEnabled determines whether the image should be up-scaled or not
* if the window size is greater than the image size
* @return scaled bitmap
*/
public static Bitmap getBitmapAccuratelyScaledToDisplay(File f, int screenHeight,
int screenWidth) {
// Determine image size of f
BitmapFactory.Options o = new BitmapFactory.Options();
o.inJustDecodeBounds = true;
getBitmap(f.getAbsolutePath(), o);

// Load full size bitmap image
public static Bitmap getBitmapScaledToDisplay(File file, int screenHeight, int screenWidth, boolean upscaleEnabled) {
// Determine image size of file
BitmapFactory.Options options = new BitmapFactory.Options();
options.inInputShareable = true;
options.inPurgeable = true;
Bitmap bitmap = getBitmap(f.getAbsolutePath(), options);

// Figure out scale
double heightScale = ((double) (o.outHeight)) / screenHeight;
double widthScale = ((double) o.outWidth) / screenWidth;
double scale = Math.max(widthScale, heightScale);
options.inJustDecodeBounds = true;
getBitmap(file.getAbsolutePath(), options);

double newHeight = Math.ceil(o.outHeight / scale);
double newWidth = Math.ceil(o.outWidth / scale);

bitmap = Bitmap.createScaledBitmap(bitmap, (int) newWidth, (int) newHeight, false);
Bitmap bitmap;
double scale;
if (upscaleEnabled) {
// Load full size bitmap image
options = new BitmapFactory.Options();
options.inInputShareable = true;
options.inPurgeable = true;
bitmap = getBitmap(file.getAbsolutePath(), options);

double heightScale = ((double) (options.outHeight)) / screenHeight;
double widthScale = ((double) options.outWidth) / screenWidth;
scale = Math.max(widthScale, heightScale);

double newHeight = Math.ceil(options.outHeight / scale);
double newWidth = Math.ceil(options.outWidth / scale);

bitmap = Bitmap.createScaledBitmap(bitmap, (int) newWidth, (int) newHeight, false);
} else {
int heightScale = options.outHeight / screenHeight;
int widthScale = options.outWidth / screenWidth;

// Powers of 2 work faster, sometimes, according to the doc.
// We're just doing closest size that still fills the screen.
scale = Math.max(widthScale, heightScale);

// get bitmap with scale ( < 1 is the same as 1)
options = new BitmapFactory.Options();
options.inInputShareable = true;
options.inPurgeable = true;
options.inSampleSize = (int) scale;
bitmap = getBitmap(file.getAbsolutePath(), options);
}

if (bitmap != null) {
Timber.i("Screen is %dx%d. Image has been scaled down by %f to %dx%d",
screenHeight, screenWidth, scale, bitmap.getHeight(), bitmap.getWidth());
}

return bitmap;
}


public static String copyFile(File sourceFile, File destFile) {
if (sourceFile.exists()) {
String errorMessage = actualCopy(sourceFile, destFile);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,9 +87,8 @@ public void reset() {

public void resetImage(int w, int h) {
if (backgroundBitmapFile.exists()) {
bitmap = FileUtils.getBitmapAccuratelyScaledToDisplay(
backgroundBitmapFile, h, w).copy(
Bitmap.Config.ARGB_8888, true);
bitmap = FileUtils.getBitmapScaledToDisplay(backgroundBitmapFile, h, w, true)
.copy(Bitmap.Config.ARGB_8888, true);
canvas = new Canvas(bitmap);
} else {
bitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ public class MediaLayout extends RelativeLayout implements OnClickListener {
private MediaPlayer player;
private AudioPlayListener audioPlayListener;
private int playTextColor;

private Context context;

private CharSequence originalText;
Expand Down Expand Up @@ -230,8 +230,7 @@ public void onClick(View v) {
DisplayMetrics metrics = context.getResources().getDisplayMetrics();
int screenWidth = metrics.widthPixels;
int screenHeight = metrics.heightPixels;
Bitmap b = FileUtils.getBitmapScaledToDisplay(imageFile, screenHeight,
screenWidth);
Bitmap b = FileUtils.getBitmapScaledToDisplay(imageFile, screenHeight, screenWidth);
if (b != null) {
imageView = new ImageView(getContext());
imageView.setPadding(2, 2, 2, 2);
Expand All @@ -246,7 +245,7 @@ public void onClick(View v) {
this, "onClick",
"showImagePromptBigImage" + MediaLayout.this.selectionDesignator,
MediaLayout.this.index);

try {
File bigImage = new File(ReferenceManager
.instance()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -179,8 +179,7 @@ public GridMultiWidget(Context context, FormEntryPrompt prompt, int numColumns)
imageFilename = ReferenceManager.instance().DeriveReference(imageURI).getLocalURI();
final File imageFile = new File(imageFilename);
if (imageFile.exists()) {
Bitmap b = FileUtils.getBitmapScaledToDisplay(imageFile,
screenHeight, screenWidth);
Bitmap b = FileUtils.getBitmapScaledToDisplay(imageFile, screenHeight, screenWidth);
if (b != null) {

if (b.getWidth() > maxColumnWidth) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -185,10 +185,7 @@ public GridWidget(Context context, FormEntryPrompt prompt, int numColumns,

final File imageFile = new File(imageFilename);
if (imageFile.exists()) {
Bitmap b =
FileUtils
.getBitmapScaledToDisplay(imageFile, screenHeight,
screenWidth);
Bitmap b = FileUtils.getBitmapScaledToDisplay(imageFile, screenHeight, screenWidth);
if (b != null) {

if (b.getWidth() > maxColumnWidth) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,9 +106,7 @@ public LabelWidget(Context context, FormEntryPrompt prompt) {
DisplayMetrics metrics = context.getResources().getDisplayMetrics();
int screenWidth = metrics.widthPixels;
int screenHeight = metrics.heightPixels;
b =
FileUtils.getBitmapScaledToDisplay(imageFile, screenHeight,
screenWidth);
b = FileUtils.getBitmapScaledToDisplay(imageFile, screenHeight, screenWidth);
} catch (OutOfMemoryError e) {
Timber.e(e);
errorMsg = "ERROR: " + e.getMessage();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -166,9 +166,7 @@ public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
DisplayMetrics metrics = context.getResources().getDisplayMetrics();
int screenWidth = metrics.widthPixels;
int screenHeight = metrics.heightPixels;
b =
FileUtils.getBitmapScaledToDisplay(imageFile, screenHeight,
screenWidth);
b = FileUtils.getBitmapScaledToDisplay(imageFile, screenHeight, screenWidth);
} catch (OutOfMemoryError e) {
errorMsg = "ERROR: " + e.getMessage();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -137,9 +137,7 @@ public ListWidget(Context context, FormEntryPrompt prompt, boolean displayLabel)
DisplayMetrics metrics = context.getResources().getDisplayMetrics();
int screenWidth = metrics.widthPixels;
int screenHeight = metrics.heightPixels;
b =
FileUtils.getBitmapScaledToDisplay(imageFile, screenHeight,
screenWidth);
b = FileUtils.getBitmapScaledToDisplay(imageFile, screenHeight, screenWidth);
} catch (OutOfMemoryError e) {
errorMsg = "ERROR: " + e.getMessage();
}
Expand Down

0 comments on commit 4059ed1

Please sign in to comment.