Handling weird png-8 with ImageIO

917 Views Asked by At

I'm working on a tool for Android that takes a png as an input, rescale it for several densities and save them in a directory. (Project that can be found here : https://code.google.com/p/9patch-resizer/

In order to open images, I'm using ImageIO's function readImage (http://docs.oracle.com/javase/6/docs/api/javax/imageio/ImageIO.html#read(java.io.File))

But I've having some trouble with some PNG-8 files, that I shrunk to minimum size thanks to ImageOptim

The thing is, if I open this image with ImageIO, it discards the transparency information and that's annoying. (Meaning, when I rescale it, and save it later, the transparency is discarded)

Here is the image I'm talking about: background and the rescaled output: rescaled background

If I'm using Toolkit's createImage method (http://docs.oracle.com/javase/6/docs/api/java/awt/Toolkit.html#createImage(java.lang.String)) instead of ImageIO's method to get the image, it works correctly, but I don't have get the informations such as color model, etc...

1

There are 1 best solutions below

3
On

Here's a PoC that does the trick for me:

public class TestPNGResampler {
    public static void main(String[] args) throws IOException {
        File file = new File(args[0]);

        ImageInputStream input = ImageIO.createImageInputStream(file);

        try {
            Iterator<ImageReader> readers = ImageIO.getImageReaders(input);

            if (!readers.hasNext()) {
                System.err.println("No reader for " + file);
                System.exit(1);
            }

            // Read image and metadata
            ImageReader reader = readers.next();

            reader.setInput(input);
            IIOMetadata metadata = reader.getImageMetadata(0);

            BufferedImage image = reader.read(0);

            // Rescale the image to 22x66 as in OP (replace as you see fit)
            image = new ResampleOp(22, 66, ResampleOp.FILTER_LANCZOS).filter(image, null);

            // Write image with metadata from original image, to maintain tRNS chunk
            ImageWriter writer = ImageIO.getImageWritersByFormatName("PNG").next();
            ImageOutputStream output = ImageIO.createImageOutputStream(new File(args[0] + "_mod.png"));
            try {
                writer.setOutput(output);
                writer.write(new IIOImage(image, Collections.<BufferedImage>emptyList(), metadata));
            }
            finally {
                output.close();
            }
        }
        finally {
            input.close();
        }
    }
}