Reducing J2ME Size with Advanced PNG Compression

One way to reduce the size of a J2ME application is through better compression of the PNG images you are using.

I currently use the excellent Paint.Net to create my images. Unfortunately, it doesn’t compress PNG output very effectively. It is particularly poor with monochrome images. Ideally, these would be saved in 2-bit color mode, but the best Paint.Net can do is 8-bit color. Surprisingly, this limitation is not unique to Paint.Net: numerous other tools have the same limitation. For example, I have created a monochrome image (containing a bitmapped font) and this was saved by Paint.Net using 8-bit color. It weighed in at 2352 bytes.

One of Paint.Net’s best features is its support for a wide range of plugins. One of these is able to host a PNG compressor called OptiPng. This is able to save 2-bit color and reduce the file down to just 928 bytes. A huge improvement.
Better still, a stand-alone little utility called PngGantlet uses the incredible PNGOOUT compressor to achieve even better results. It was able to shrink this image down to a mere 806 bytes: that’s just 34% of the size of the original image, with no loss of quality.

This is all the more impressive when you consider that the same image as a BMP file comes in at a massive 14,902 bytes (806 = 5.4% of 14902).
Here’s a summary of my results:

File Size (bytes) ~%
BMP 14,902 633%
Original PNG Image 2352 100%
OptiPNG 928 39%
PngGantlet 806 34%

One caveat – these figures don’t take into account any additional compression undertaken when converting the final application into a .jar file. I assume this compression will be less effective on the final 806-byte file than the original 2353-byte file.

Nevertheless, I don’t doubt that applying the compressor to all my images will result in a significantly smaller application.

MIDP 1.0 fillTriangle Method

One of the (many) limitations of MIDP 1.0 is that it lacks the fillTriangle that is present in MIDP 2.0. Below is a replacement method that works on MIDP 1.0 devices. It is based on notes published by Michal Wronski.

Michal’s algorithm depends on floating-point math – also unavailable in MIDP 1.0. With a little refactoring I was able to create an integer-only approximation. Sadly, rounding errors mean that my routine isn’t pixel perfect. An alternative that would give more accurate results would be to use some kind of fixed-point library. Despite its shortcomings, however, my method is good enough for many practical purposes (including my own).

I release this code into the public domain. You can use it as you please.