PNG compression in Android… (You have got to be kidding)
Over the last few weeks, I’ve been learning the Android SDK in an effort to bring Layers to Android devices. It’s going pretty well, but every once and a while I run into a truly WTF moment.
Tonight I was importing some images from the iPhone version of Layers when I noticed that Android seems to visibly reduce the quality of PNG files at compile time. In images with fine gradients, smooth color transitions, or very light shadows you tend to get banding. It almost looks like the image were being converted to a GIF file.
I figured it’d be easy to fix. Go into Eclipse, right click on everything, look in menus… repeat… profit! Unfortunately, it seems there’s no way to turn off compression for specific file or choose a non-lossy compression method. However, I found this gem of a solution in the Android Widget Design Guidelines:
“To reduce banding when exporting a widget, apply the following Photoshop Add Noise setting to your graphic.”
Um… what now?
It turns out, you can get around the compression algorithm by adding a small amount of pixel noise to your images. It’s mostly invisible, and it prevents the compression from producing obvious bands.
It’s an instant fix, but I almost laughed out loud. Seriously? This is the documented solution? *sigh*.


Keni
Hi Ben,
Glad to see that you’re taking Layers to other platforms.
Jan 22nd, 2010
Cyril Mottier
Nice article ! Unfortunately, you’re not understanding the problem in the correct way. Actually, Android is not compressing graphic resources at all. The problem comes from the fact most (I think all for now :() Android devices are based on a display that uses a 16-bits color palette to render colors. As a result, you get banding effects with simple gradient.
I’ve wrote an article dealing with that problem (http://android.cyrilmottier.com/?p=196) : it’s in French but I’m sure Google Translate will help you :).
Good luck and welcome to the Android world !
Feb 2nd, 2010
lailai
Android fail haha
Apr 6th, 2010
Jay
You might want to try inserting images into the res/raw/ directory.
http://developer.android.com/guide/topics/graphics/2d-graphics.html
May 19th, 2010
Andrew Lundin
Hi! I’m just getting into Android development, and I happened to run across your article yesterday. This morning I read about something that may provide a better solution to this problem. The following “Note” comes from this page:
http://developer.android.com/guide/topics/graphics/2d-graphics.html
Note: Image resources placed in res/drawable/ may be automatically optimized with lossless image compression by the aapt tool. For example, a true-color PNG that does not require more than 256 colors may be converted to an 8-bit PNG with a color palette. This will result in an image of equal quality but which requires less memory. So be aware that the image binaries placed in this directory can change during the build. If you plan on reading an image as a bit stream in order to convert it to a bitmap, put your images in the res/raw/ folder instead, where they will not be optimized.
I guess the noise they suggested to add is probably chromatic noise, which would expand the palette beyond the 256 colors eligible for 8-bit compression, meaning it probably won’t be recompressed at all. But if you don’t mind the hassle of reading the image as a bit stream, you can prevent the recompression without altering the image. I have not tried this, but it looks promising. I hope it helps!
Aug 30th, 2010
Reply to 'PNG compression in Android… (You have got to be kidding)'