Creating and Comparing Images on Android

IMG_8440

A while ago, I wrote this blog post on creating and comparing UIImages. That code allowed me to develop the image processing part of the app against my unit tests, which was really, really helpful given that I rewrote it about four times to make it performant enough.

So, when I started writing Android code it was one of the first things I ported. Firstly let me say – way easier on Android than iOS. A tiny difference in the API was a gotcha, iOS takes arguments x, y, width, height, and a comparable function on Android takes x1, y1, x2, y2. But other than that it was much more straightforward, basically because of how much easier it is to delve into the pixels.

To create a one color image, you can just set the color and draw to the canvas:

/**
* A one color image.
* @param width
* @param height
* @param color
* @return A one color image with the given width and height.
*/
public static Bitmap createImage(int width, int height, int color) {
Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
Paint paint = new Paint();
paint.setColor(color);
canvas.drawRect(0F, 0F, (float) width, (float) height, paint);
return bitmap;
}


But if you want to set individual pixels you can just call setPixel(). So to create a 3×3 2-color-alternating image (I find this a really useful test image):

/**
* A 3×3 2-color image.
* @param color1
* @param color2
* @return A 3×3 image alternating the two colors.
*/
public static Bitmap createTwoColorImage(int color1, int color2) {
Bitmap bitmap = Bitmap.createBitmap(3, 3, Bitmap.Config.ARGB_8888);
bitmap.setPixel(0, 0, color1);
bitmap.setPixel(2, 0, color1);
bitmap.setPixel(1, 1, color1);
bitmap.setPixel(0, 2, color1);
bitmap.setPixel(2, 2, color1);
bitmap.setPixel(1, 0, color2);
bitmap.setPixel(0, 1, color2);
bitmap.setPixel(2, 1, color2);
bitmap.setPixel(1, 2, color2);
return bitmap;
}

This is similar to the way we can create an image from an array of colors:

/**
* A image from an array of colors.
* @param width
* @param height
* @param colors
* @return image of given width and height filled with the given color array.
*/
public static Bitmap createImage(int width, int height, int[] colors) {
Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
int x = 0;
int y = 0;
for (int color : colors) {
bitmap.setPixel(x, y, color);
x++;
if (x == width) {
x = 0;
y++;
}
}
return bitmap;
}

On iOS creating from an array was sufficiently complicated that I felt like the simpler creation methods were also worthwhile. On Android I’m less certain! I may refactor them to just call the array function.

But now we have made our test images, we need to be able to compare them. As before, I’m defining two images as the same iff (if and only if) they have the same width, height, and the pixels are the same color. For now I’m able to do an exact comparison, but I may add some kind of tolerance here as the code evolves.

/**
* Compare two images.
* @param bitmap1
* @param bitmap2
* @return true iff both images have the same dimensions and pixel values.
*/
public static boolean compareImages(Bitmap bitmap1, Bitmap bitmap2) {
if (bitmap1.getWidth() != bitmap2.getWidth() ||
bitmap1.getHeight() != bitmap2.getHeight()) {
return false;
}
for (int y = 0; y < bitmap1.getHeight(); y++) {
for (int x = 0; x < bitmap1.getWidth(); x++) {
if (bitmap1.getPixel(x, y) != bitmap2.getPixel(x, y)) {
return false;
}
}
}
return true;
}

These helper methods have been a really important part of my testing strategy on both platforms – the image processing is the core of the app, and I want to be sure it works really well.

3 thoughts on “Creating and Comparing Images on Android

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.