Skip to content
Advertisement

How to create 8-bit PNG from BufferedImage?

I have a Java program that creates composite png images that contain only black pixels and 100% transparent pixels. I am trying to reduce the size of these composites as much as possible and I notice that ImageIO.write always outputs 32 bit PNG’s. I would like to instead save them as 8-bit considering that the images will only have two colors total but I don’t think there is a way to do this with the standard Java functions.

Does anyone know of any pre-built functions that will create an 8-bit png from a BufferedImage? Any other advice to reduce the size of these png’s is welcome too!

Answer

I had to put this in the backseat for a bit, but I came back to it yesterday and figured out how to do it. Basically it came down to using the classes under com.sun.imageio.plugins.png and a custom ImageWriteParam.

I had to build the color tables myself (not too hard, just byte arrays). The color tables were then passed to ImageTypeSpecifier.createIndexed. The resulting ImageTypeSpecifier returned allows you to create a BufferedImage into which I copied the pixels.

Next, I created custom PNG headers by using PNGMetadata (Needed to read up a lot on the PNG specification, but overall very easy). I then created a new IIOImage using said metadata and the BufferedImage.

Finally, I created a PNGImageWriter and got the default ImageWriteParam from it. I then simply passed the ImageTypeSpecifier from before to its setDestinationType method. Last step was to write the PNG to disk by passing the IIOImage and the ImageWriteParam to the PNGImageWriter.

The documentation is very sparse on many of these classes but their functionality is great. By doing this, I created a minimal PNG that contained a bit depth of 1 (since there are only two colors) and this reduced the size of my PNG’s by an average of 78%!!! Very much worth the effort.

Advertisement