I just committed some rough source code for, amongst other things, ImageUtil.
You’ll find it in my Google code SVN repository
You need this code to create the colour charts I posted a couple of weeks ago.
It’s inside a Maven project, but you can probably just cherry pick this file and have things work:
And watch out for this possible issue:
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4886732
I haven’t been able to track down all of the situations it occurs in.
In a previous post, I described how I could dynamically generate a continually evolving logo by masking and layering several different bitmaps.
This worked well enough, but failed to look convincing when the rendered texture was light. I overcame this by creating a halo effect, to make brightly textured emblems appear to luminesce. Again, the 2D rendering apis in Android made this very easy.
I start the process with the rendered texture in a Bitmap:

Using a Canvas over a tiny 3x3 Bitmap I produced a scaled copy of the texture.

Using the Bitmap.getPixels() method, I created a SweepGradient through the eight outermost colours.

Finally using a black-to-white-to-black RadialGradient applied with a PorterDuff.Mode of MULTIPLY a circular ring is of compatible colours is created:

This ring can then be overlayed separately onto the existing image, using the useful TransitionDrawable class to smoothly switch halos.
The final effect can be seen in this video
I thought I’d take some time out to write-up some details of how I produced this morphing icon effect that I demonstrated in my previous post. The video is grainy, so it’s a little difficult to tell, but the result is a sharp, glossy looking emblem that appears to switch material periodically.

This is the first emblem that the user sees and it matches the application icon. I want to promote an identity for the application and strengthen its association with the launcher icon. What isn’t visible in the screenshot is the animation with which the emblem first appears. Using an XML anim resource, I combine an AlphaAnimation and a ScaleAnimation to the icon to make it slowly rise-out from the background. At the same time I use another alpha animation, combined with scaling and translation to pop a shadow behind. The aim is to give the impression that the icon sits slightly above the background. It’s also worth remarking that since this activity is the one used to launch the application, the system will probably be animating the activity onto the screen simultaneously. For this reason, I’d say it’s not worth doing anything too complex; any fine details will be missed and flashy animations may be overwhelming when combined with an activity transition.
I have to say at this point that the code isn’t finished yet, there are a number of small flaws that should be fixed, but I don’t know if there’ll be time before the first release. This is demonstrated in the screenshot above; I’m not dithering my bitmaps (which are ARGB_8888 for compositing purposes) for an RGB565 window (which was the default for Android until Gingerbread). You can often get away without dithering, but where bitmaps contain smooth gradients, the artifacts become distracting.
After this first presentation of the emblem, the background of the icon changes and the emblem begins to cycle through any number of different textures.

These textures are actually being rendered by the phone (using a genetically based algorithm) while the previously generated texture is being displayed. This is all done off-screen. Although the texture rendering is pretty efficient (thanks, in large-part, to the efficiency of the Android 2D APIs) it’s more work than one could safely commit to on the main application thread. So I use an AsyncTask, but I am considering switching to a Thread with a Looper because message-passing is probably a better model for what’s going on here, with the UI sending a message (indicating that it wants to update the emblem) to a worker which posts back another message (containing the bitmap). Currently the AsyncTask applies its new emblem in its onPostExecute() method, but this turns out to be a bit ugly if you want precise control over when the new emblem actually appears in the UI.
How the textures are rendered is a whole other post (series of posts probably) but it’s enough to know that that textures are rendered as a square image:

A circular mask has already been created (as a PNG resource this is all white, but with alpha).

And these are combined using the Canvas.drawBitmap() method, and a Paint that controls the composition.

One way to do this is by drawing the texture Bitmap onto the mask bitmap, using the SRC_IN Porter-Duff rule (this basically preserves the alpha channel of the destination image, but replaces the colour channels with those of the source image). But in this case, the texture is being rendered into a fresh Bitmap anyway, so rather than repeatedly producing fresh masks (typically with the Bitmap.copy() method), I draw the mask onto the texture using the DST_IN mode. With the result that all the colour information from the texture is preserved with only the alpha channel being the mask (note that Android has an ALPHA_8 bitmap configuration especially for masking).
There’s a huge amount you can do with the Xfermode options that Android provides and it’s really worth becoming familiar with them.
Now I have got as far as periodically generating a textured disc, but I still need to apply the logo to the emblem and display the result. Android makes this mostly very simple; the emblem is an ImageView with the white “M” as the image, and the disc as a background Drawable. So the disc appears behind the M with the View drawing doing the composition for us.
Simply, this “M” becomes a Bitmap within an ImageView:

which is given this other Bitmap as a background:

to end-up looking like this:

Because any view Animation will be applied to both the ImageView contents and background together, the two can be easily manipulated as one unit in the Java code and layout XML. This ImageView is then overlayed, using a FrameLayout, with another imageView that displays the shadow (I could have applied the shadow as a background on the FrameLayout, but I need to animate it independently in the initial animation).
To give a greater impression of physical depth to the emblem, you can see shading on the image of the “M”, both within it and, more significantly, around it. Creating this image actually proved bothersome. First I used POV-Ray to render the icon at the correct size. Then I needed to separate out the highlights and lowlights in such a way that the lightest and darkest parts of the image had the greatest opacity. At that point I couldn’t find any way of achieving this using GIMP. After 30 minutes of hunting around for the right filter, I wrote a throw-away Java program to do the job in just 5. It simply:
The 2D classes in Java SE aren’t as slick as the corresponding APIs in Android, but they’re more than adequate for tasks like that.
This post has described in broad terms how (with a little assistance from desktop Java), the Android View, Animation and graphics APIs were combined to create this morphing icon effect. But this is only part of the work. I also needed to:
I’ll try to cover these in later posts.
This is a video of an effect I’ve developed for an android application I’m developing that will augment some of my existing applications. This is all done by combining the powerful 2D libraries with the flexible view APIs.
The video quality is poor - I still haven’t worked out how to film a mobile phone.
(Source: youtube.com)
Moseycode is an augmented reality barcode system that combines live camera data and 3D graphics. Due to limitations in the way that live camera data is rendered by the Android framework, if you want to overlay 3D graphics onto live camera data your only option is to convert the camera data into an OpenGL texture.
The method below does just that in Java – and it’s not impossibly slow either; it’s been optimized quite a lot. At the fallback camera preview dimensions of 176x144 it takes approximately 90ms to perform the conversion on my G1.
/**
* Converts semi-planar YUV420 as generated for camera preview into RGB565
* format for use as an OpenGL ES texture. It assumes that both the input
* and output data are contiguous and start at zero.
*
* @param yuvs the array of YUV420 semi-planar data
* @param rgbs an array into which the RGB565 data will be written
* @param width the number of pixels horizontally
* @param height the number of pixels vertically
*/
//we tackle the conversion two pixels at a time for greater speed
private void toRGB565(byte[] yuvs, int width, int height, byte[] rgbs) {
//the end of the luminance data
final int lumEnd = width * height;
//points to the next luminance value pair
int lumPtr = 0;
//points to the next chromiance value pair
int chrPtr = lumEnd;
//points to the next byte output pair of RGB565 value
int outPtr = 0;
//the end of the current luminance scanline
int lineEnd = width;
while (true) {
//skip back to the start of the chromiance values when necessary
if (lumPtr == lineEnd) {
if (lumPtr == lumEnd) break; //we've reached the end
//division here is a bit expensive, but's only done once per scanline
chrPtr = lumEnd + ((lumPtr >> 1) / width) * width;
lineEnd += width;
}
//read the luminance and chromiance values
final int Y1 = yuvs[lumPtr++] & 0xff;
final int Y2 = yuvs[lumPtr++] & 0xff;
final int Cr = (yuvs[chrPtr++] & 0xff) - 128;
final int Cb = (yuvs[chrPtr++] & 0xff) - 128;
int R, G, B;
//generate first RGB components
B = Y1 + ((454 * Cb) >> 8);
if(B < 0) B = 0; else if(B > 255) B = 255;
G = Y1 - ((88 * Cb + 183 * Cr) >> 8);
if(G < 0) G = 0; else if(G > 255) G = 255;
R = Y1 + ((359 * Cr) >> 8);
if(R < 0) R = 0; else if(R > 255) R = 255;
//NOTE: this assume little-endian encoding
rgbs[outPtr++] = (byte) (((G & 0x3c) << 3) | (B >> 3));
rgbs[outPtr++] = (byte) ((R & 0xf8) | (G >> 5));
//generate second RGB components
B = Y2 + ((454 * Cb) >> 8);
if(B < 0) B = 0; else if(B > 255) B = 255;
G = Y2 - ((88 * Cb + 183 * Cr) >> 8);
if(G < 0) G = 0; else if(G > 255) G = 255;
R = Y2 + ((359 * Cr) >> 8);
if(R < 0) R = 0; else if(R > 255) R = 255;
//NOTE: this assume little-endian encoding
rgbs[outPtr++] = (byte) (((G & 0x3c) << 3) | (B >> 3));
rgbs[outPtr++] = (byte) ((R & 0xf8) | (G >> 5));
}
}
Creating an image mask based on intensity is a good way of easily inserting texture behind an image while preserving its hand-drawn character.