Marty
Marty

Reputation: 2165

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!

Upvotes: 2

Views: 2471

Answers (2)

Marty
Marty

Reputation: 2165

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.

Upvotes: 1

lynks
lynks

Reputation: 5689

Im not sure, but I would guess that ImageIO uses whatever type the BufferedImage uses. Try playing with the different types available. TYPE_CUSTOM and TYPE_BYTE_BINARY look promising.

Upvotes: 2

Related Questions