views:

1887

answers:

6

The standard way to load an image in a J2ME application is using the Image.createImage method and the recommended image format is PNG.

Now, the J2ME specs dont lay down any restrictions on the implementation of this method or the in memory representation of an Image so, each vendor has a different implementation.

Motorola in particular has this really crappy implementation where in the PNG is completely decoded into ARGB byte array at the time of image creation. This means that an 8K png with dimensions 176x208 takes up a peak memory of about 170K to load and the memory utilized by the Image object itself is about 145K! On other phones like Nokia, Sony Ericsson etc, the same image only takes about 16K to load and store in memory.I dont know what smart optimizations they use, but for some incomprehensible reason, Motorola's JVM does not.

This is wreaking havoc in my J2ME app, making it almost impossible to run a decent version of it on Motorola phones. I tried various workarounds like using a gzip'd ARGB byte array of the image and deflating it during paint, but that causes the paint to slow down by a factor of 10!

Anyone know of a workaround to this issue? An open source PNG image decoder for J2ME with the smarts that Motorola lacks? Or is there something that can be done to the PNG image to reduce its in memory footprint? (I currently used Indexed mode PNG) Any pointers at all would be welcome..

Gowri

A: 

PNG's tend to be bloaty.

Why not use gif instead.

http://www.ddj.com/mobile/184406435;jsessionid=SBUQN2ECITM5OQSNDLOSKHSCJUNN2JVN?_requestid=76071

mugafuga
PNG is the only format guaranteed support by the J2ME spec. Anything else cannot be relied upon. I've heard tale of one motorola supporting JPEG and another identical one not supporting it, both claiming to be the same firmware revision. J2ME is a minefield.
izb
True, but if its possible to have your own GIF decoder and use that to display GIF images, it may work out. I will give this a shot. Thanks mugafuga.
Gowri
Well, turns out its not so much the decoding process but the "native image format" of Motorola jvm that is causing the problem - ie, the native image format here is a raw ARGB integer array leading to a 176x208 image taking 176*208*4=143kb. So, unfortunately, the GifDecoder doesnt help :(
Gowri
+1  A: 

Well, the way I see it, if all image formats are immediatly decoded into an ARGB array when you create the images, the only thing you can really do is create an upper bound to the amount of memory you will use to display things on the screen.

You can create an Image cache that will know how much heap memory each image is using for that specific device, loading and unloading Images are they are needed. Of course that means relying on the Grabage Collector maybe too much to keep your application responsive.

Cache management would probably need to happen in a dedicated Thread.

Keeping only one screen worth of images loaded at any given time could work if your application screens are static enough not to require too much animation.

Also remember that MIDP Canvas usually don't reset themselves. If you use 2 different calls to Canvas.paint() to paint 2 different Images in 2 different areas of the screen, you should be able to keep both images displayed long after the actual Image Objects have been garbage collected as lond as you don't paint anything on top of them.

From a purely commercial standpoint, you need to ability to tell your customers that some phones just have an implementation of Java so bad that you are not going to support them.

QuickRecipesOnSymbianOS
A: 

The motorola developer's forum suggests that you cut larger images down to smaller strips and load these smaller strips instead of the whole large image at one shot. Note that this does not reduce the in memory footprint of the images. That still needs sum(width * height * bytes-per-pixel) of all the strips. But it does reduce the memory needed to decode the png image and load it up. So thats what I am doing for now. It has helped some. But the overall memory usage is still a problem.

Gowri
+2  A: 

One thing on Sony Ericsson. Don't give them so much credit. They take (image_width x image_height x bytes_per_pixel) of memory as well when loading images.

From the SE J2ME developer doc, "All images are stored in phone memory in a 16-bit per pixel RGB format, possibly with a 1-bit or 8-bit per pixel alpha channel." So, at least 2 bytes. The difference is that Sony Ericsson phones (I can't speak for Nokia) have a separate memory block for images that gets filled first before loading images in the heap (you can see this by wrapping the load with Runtime.getRuntime().freeMemory()...the heap size will increase by only a couple of bytes, which is the size of the new Object).

This isn't defending Motorola's as I certain had my troubles porting from SE phones to Motorola's, but it's not because SE was able to figure out a way to store images in heap in a much more optimized way. Motorola just stores everything in the heap, and that's why you run out faster.

The smaller images is a good idea, not only during the decoder part, but from a heap fragmentation point of view. It will allow the images to fit in smaller blocks of memory instead of a large continuous block.

Fostah
You are right about the Sony Ericsson. The same with Nokia as well.
Gowri
A: 

The better solution would be is to store the ARGB as data (use some kind of indexing for compressing it) with advantanges of changing palette etc/ no PNG Header/ . instead of storing different PNG images and use createImage function to create the image.

Azlam
A: 

One way to diminish a png image would be to run them through a program like png gauntlet to reduce its size.

Decio Lira