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:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* 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):
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* 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:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* 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.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* 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 replies on “Creating and Comparing Images on Android”
Hey! The code samples don’t seem to come through on the RSS feed.
[WORDPRESS HASHCASH] The poster sent us ‘0 which is not a hashcash value.
Oh that is annoying – they are gist snippets. I will have a look into it but I’m not sure if I can fix it.
[…] Creating and Comparing Images on Android*. More technical work from Show & Hide (2015) – I replicated my work on iOS to create test images, and compare images against each other in tests. […]