A minimal PNG encoder for J2ME

(including a minimal ZLIB encoder)

I wrote this in a funny sort of mood when playing around with the limitations of MIDP 1.0. Although I didn't actually have any use for this myself, it has attracted more interest than anything else on my site, so I happily decided to address it as a separate topic here ;-)

A minimal PNG stream consists of a signature followed by a header chunk, a data chunk and a trailer chunk. Each chunk is verified by a CRC checksum. The data chunk contains a ZLIB block representing the actual pixel data. In the spirit of writing a minimal encoder, I used the most simple ZLIB block format containing only uncompressed deflate blocks.

Download: PNG.java

09/22/08 Fixed Adler checksum calculation and byte order for storing length of zlib deflate block. Thanks to Miloslav Růžička for noting this.
05/12/09 Added support for images > 64K by splitting the data into multiple uncompressed deflate blocks. In the process, split PNG and ZLIB functionality into separate classes.

Terms of Use: You may use the PNG encoder free of charge for any purpose you desire, as long as you do not claim credit for the original sources and agree not to hold me responsible for any damage arising out of its use. If you have a suitable location in GUI or documentation for giving credit, I'd appreciate a mention of

   PNG encoder (C) 2006-2009 by Christian Fröschlin, www.chrfr.de

but that's not mandatory. Of course, if you use my PNG encoder in your application, I'd also be happy to hear about it.

Limitations: The image data remains uncompressed, so the encoder may not be suitable for large images.

Extensions: Cody Konior has successfully combined my PNG encoder with JZLib for his Biorhythm application at mobilebio.sourceforge.net, so you might wish to check out his encoder class if you are looking for something with compression.

Related: Helmut Dersch has written a pure Java JPEG decoder.

Back to MIDP page

6 comment(s) have been added to this topic:

rolai wrote on 11/27/2007 (15:6):

I have question regarding PNG.java I would like to convert an Image object, into a byte [] (png format). Do you have any code sample showing how to use PNG.java and make the conversion?


Christian wrote on 5/21/2008 (0:32):
Hi rolai, sorry for not replying earlier, wasn't really active with this website in the last months. In MIDP 1.0 it is not possible to extract pixel information from an image object (although extension such as Nokia UI provide methods). In MIDP 2.0 image object has a getRGB method to obtain pixel data. If you wish to apply my PNG encode on that you need to split the ARGB data array into four separate arrays.

beth wrote on 6/22/2008 (17:19):
Hi, I would like to use your PNG.java in my midlet to write image data on the mobile phone file system as a png file. I do not know how I am using it wrongly that the result still is not in the correct format. I just use the PNG.toPNG() method to create the byte array of the image and then I write the resulting byte array into the file system using FileConnection and OutputStream. What else should I do? Thank you!

Christian wrote on 7/28/2008 (21:49):
The most likely cause would be an image size greater than 64K, a case which is not handled in this minimal encoder.

mieszk3 wrote on 7/29/2008 (8:14):
there was a big mistake in toZLIB method. 4 bytes was write in wrong way.
WRONG part:
//Uncompressed deflate block
zlib.writeByte((byte) 1); //Final flag set, Compression type 0
char length = (char) raw.length;
zlib.writeChar(length); //Length
zlib.writeChar(~length); //Length 1st complement
zlib.write(raw); //Data

RIGHT part:
//Uncompressed deflate block
zlib.writeByte((byte) 1); //Final flag set, Compression type 0
char length = (char) raw.length;
zlib.writeByte((byte)(length & 0xFF)); //Length LSB
zlib.writeByte((byte)((length & 0xFF00) >> 8)); //Length MSB
zlib.writeByte((byte)(~length & 0xFF)); //Length 1st complement LSB
zlib.writeByte((byte)((~length & 0xFF00) >> 8)); //Length 1st complement MSB
zlib.write(raw); //Data

mieszk3 wrote on 7/29/2008 (11:35):
I wrote new toZLIB method with compression using JZlib package:
public static byte[] toZLIB(byte[] raw)
byte[] compr = new byte[raw.length];
ZStream zs = new ZStream();
zs.next_in = raw;
zs.next_in_index = 0;
zs.avail_in = raw.length;
zs.next_out = compr;
zs.next_out_index = 0;
zs.avail_out = compr.length;
byte[] outData = new byte[(int)zs.total_out];
System.arraycopy(compr, 0, outData, 0, outData.length);
return outData;

enjoy :)

Note: Adding comments has been disabled for the time being, as too many bots left their spam and I didn't feel it worthwhile to add a humanity check. Just send me a mail if you wish to contact me.
Copyright (C) 2006-2013 by Christian Fröschlin. Please note the legal disclaimer. If you experience problems with this page, contact webmaster@chrfr.de.