Skip to main content

Best Way to Draw Images?

3 replies [Last post]
earamsey
Offline
Joined: 2004-04-15

Hello people, first I list my environment then the question.

Environment -
Device: Nokia E61
OS: Symbian OS v9.1
Platform: S60 3rd Edition
Memory Card: 32MB minimum (I think)

The package "com.nokia.mid.ui.DirectGraphics" and "javax.microedition.lcdui.Graphics" both have methods for drawing images directly from byte arrays;

Nokia: drawPixels(byte[] pixels,
byte[] transparencyMask,
int offset,
int scanlength,
int x,
int y,
int width,
int height,
int manipulation,
int format)

MIDP2.0: drawRGB(int[] rgbData,
int offset,
int scanlength,
int x,
int y,
int width,
int height,
boolean processAlpha)

Now, I was wondering, does it save memory to draw images directly from a byte array rather than from Image objects? I ask because, I have an image intensive application and I have been encountering memory problems. My idea was to convert all of the images to byte arrays and place them into a resource file. The following steps would be carried out to draw a paricular image;

1.open resource file and use index table to offset of image
2.read the size of the byte array
3.create byte array of specified size
4.load image data read into array
5.now draw images using either "drawPixel()" or "drawRGB()" methods

If one were to use the traditional method it would require a call to "Image.createImage(String)" which allocates an Image object. I don't know the overhead for Image objects but i seems like it would need to subclass "Object" inadditon to the actual image data and it has static methods of which I don't know the cost in memory would be. One benefit I know from using byte arrays is that all of the images would be in one resource file which should compress very well. If the file is too large I can always compress it before I jar and decompress it as I read it's contents using a J2ME GZip library, freeware!, that I found on the Internet.

I don't know which of the two methods is better; Nokia's "drawPixel()" or MIDP's "drawRGB", however, I assume that "drawRGB()" pack RGB+Alpha into an integer. Which one is better of the two. When I say better it means requires less memory and draws the fastest?

Thanks!

Reply viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
sfitzjava
Offline
Joined: 2003-06-15

When you say you are running low on memory do you mean the stack/heap when the MIDlet is running or the file system (nvram) where the MIDlet is stored?

If Heap/Stack space is the concern then byte array might help a little but realize that this mode of drawing is paramount to a BMP (bitmap), while what an Image is constitutes a PNG (encoded). So while you would think the array would be smaller due to no overhead of the PNG file format which includes width/height of the image, color, and other specs, and your array doesn't. The PNG encoding will save some of that room through the encoding.

Another alternative is to have 1 big PNG image, and then use the Graphics.drawRegion(); then your code would just need the coordinates of where the part of the image to draw was within the consolidated image object. Again because the image is encoded having more data can (not always) means better compression, and thus less memory use. Will it save enough to notice?!? Only testing can tell.

Now I have been assuming you are using PNG image resources, if you are using JPG for instance then your encoding and thus compression is greater meaning less memory use. However some implementations do not support JPG.

However if you are only speaking of the file size in storage memory (nvram) then using a data file with the bitmap data vs. PNG is most likely not going to help. Making one PNG file with all the images may help a little. However sometimes going through your code and looking for large sections of logic and simplifying them can work wonders. Also (and this is kinda strange) if you try and optimize your code too much I have seen the compiler actually make the resulting class file (and thus entire jar file) noticeably larger.

Oh and back on heap/stack memory, another little trick that some may not know about is not to always directly load a class by using new (); instead use Class.forname().newInstance(); The gives the vm a point at which it can limit the number of classes it loads at startup. In most implementations of JavaME, all the classes that are directly touched in execution are loaded into the jvm classloader (or what serves that function). This can cause long startup times, and can also use up memory that is not going to be used during that execution of your application. This is where the use of interfaces is most valuable in JavaME.

Okay sorry for such a long reply, but when you say how do I save memory, well there are a lot of options. :) Hope one of these helps.

-Shawn

earamsey
Offline
Joined: 2004-04-15

Well, what I am trying to do is reduce the amount of runtime memory so when the application is running it doesn't run out of memory and crash.

I wish I new for sure if using byte arrays instead of images would save memory in both the OS and kvm. Beause, I also read that Nokia S60 keeps and Image objects data in OS memory rather than the heap and palces the reference to the Image objects reference on the local applications heap. This is not good because OS memory is not as large as heap.

I have a large number of images so I don't know if have one large PNG would help me since I have about 500KB of images.

phari2008
Offline
Joined: 2008-04-13

Were you able to get a solution for loading the images efficiently with less memory (runtime)?

I am also facing a similar problem (3KB of PNG image consumes ~130KB runtime memory - using Image.createImage....).

Any suggestions will be very helpful. Thanks in advance.

Regards,
phari