The PNGDecoder class is available as a stand alone JAR file and is below 10KB in size.

The usage of this PNG decoder is very simple:

import de.matthiasmann.twl.utils.PNGDecoder;

....

InputStream in = new FileInputStream("white_pixel.png");
try {
   PNGDecoder decoder = new PNGDecoder(in);

   System.out.println("width="+decoder.getWidth());
   System.out.println("height="+decoder.getHeight());

   ByteBuffer buf = ByteBuffer.allocateDirect(4*decoder.getWidth()*decoder.getHeight());
   decoder.decode(buf, decoder.getWidth()*4, Format.RGBA);
   buf.flip();

   while(buf.hasRemaining()) {
      System.out.printf("%02X\n", buf.get() & 255);
   }
} finally {
   in.close();
}

Let's analyze this code step by step.

PNGDecoder decoder = new PNGDecoder(in);
This decodes the header of the PNG files and extracts information like width, height and color format. If the input stream is not a valid PNG file then an IOException is thrown. The following methods can be used to retrieve information about the PNG:
  • getWidth
  • getHeight
  • hasAlpha - returns true if this PNG has either an alpha channel or uses a transparent color
  • isRGB - returns true if this PNG is either true color or uses a palette, and false if it's gray scale
  • decideTextureFormat - adjust the requested color format based on the PNG and the capabilities of the decoder
ByteBuffer buf = ByteBuffer.allocateDirect(4*decoder.getWidth()*decoder.getHeight());
decoder.decode(buf, decoder.getWidth()*4, Format.RGBA);
buf.flip();
This will decode the image data of the PNG. First we need to allocate a ByteBuffer. In this case we want to decode the PNG as RGBA image which uses 4 bytes per pixel. The PNGDecoder has a stride parameter which specifies the distance in bytes from the start of a line to the start of the next line. In this case we set it equal to the number of bytes per line. It will write to the specified ByteBuffer starting at the current position. On return the position will be after the last written byte. If we specified a stride lager then the line length then this additional space is not included in the buffer position. If the remaining space in the ByteBuffer is not enough then a BufferOverflowException will be thrown.

The resulting ByteBuffer can then directly be used to upload the tetxure to OpenGL like this:

GL11.glTexImage2D(GL11.GL_TEXTURE_2D, 0, GL11.GL_RGBA, decoder.getWidth(), decoder.getHeight(), 0, GL11.GL_RGBA, GL11.GL_UNSIGNED_BYTE, buf);

Creator: Matthias Mann on 2010/12/01 06:10
This wiki is licensed under a Creative Commons 2.0 license
XWiki Enterprise 1.8.17790 - Documentation