tags:

views:

3078

answers:

4

I am trying to write out a png file from a java.awt.image.BufferedImage. Everything works fine but the resulting png is a 32-bit file.

Is there a way to make the png file be 8-bit? The image is grayscale, but I do need transparency as this is an overlay image. I am using java 6, and I would prefer to return an OutputStream so that I can have the calling class deal with writing out the file to disk/db.

Here is the relevant portion of the code:

 public static ByteArrayOutputStream createImage(InputStream originalStream)
            throws IOException {

        ByteArrayOutputStream oStream = null;

        java.awt.Image newImg = javax.imageio.ImageIO.read(originalStream);
        int imgWidth = newImg.getWidth(null);
        int imgHeight = newImg.getHeight(null);
        java.awt.image.BufferedImage bim = new java.awt.image.BufferedImage(imgWidth,
                imgHeight, java.awt.image.BufferedImage.TYPE_INT_ARGB);

        Color bckgrndColor = new Color(0x80, 0x80, 0x80);

        Graphics2D gf = (Graphics2D)bim.getGraphics();

        // set transparency for fill image
        gf.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.3f));
        gf.setColor(bckgrndColor);
        gf.fillRect(0, 0, imgWidth, imgHeight);

        oStream = new ByteArrayOutputStream();
        javax.imageio.ImageIO.write(bim, "png", oStream);
        oStream.close();

        return oStream;
    }
A: 

It is an interesting question... It is late, I will experiment tomorrow. I will first try and use a BufferedImage.TYPE_BYTE_INDEXED (perhaps after drawing) to see if Java is smart enough to generate an 8bit PNG.
Or perhaps some image library can allow that.

PhiLho
+2  A: 

The build in imageio png writer will write 32bit png files on all the platforms I have used it on, no matter what the source image is. You should also be aware that many people have complained that the resulting compression is much lower than what is possible with the png format. There are several independent png libraries available that allow you to specify the exact format, but I don't actually have any experience with any of them.

kasperjj
A: 

Thanks for responding, I was going to try an TYPE_BYTE_INDEXED with an IndexColorModel and may still but if ImageIO writes out 32-bit regardless it appears that I may be wasting my time there.

The image I am trying to write out can be very large (up to 8000x4000) but is just a simple mask for the image underneath, so will only have a ~30% transparent gray and a 100% transparent cutout. I would use a GIF but IE6 seems to have trouble with displaying one that large.

It only gets generated once and in an internal set-up type screen, so performance isn't an issue either, but it does have to be done within the java code and not by an offline utility.

The libraries that you specified might be used to transform it while writing... I am going to go check that out.

If anyone has a better way, please let me know!!

Thanks!

+1  A: 

I found the answer as to how to convert RGBA to Indexed here: http://www.eichberger.de/2007/07/transparent-gifs-in-java.html

However, the resulting 8-bit png file only has 100% or 0% transparency. You could probably tweak the IndexColorModel arrays, but we have decided to make the generated file (what was an overlay mask) into an underlay jpg and use what was the static base as the transparent overlay.

Instead of tacking on answers to your post, you can actually add information to your original question by clicking edit. Users can see what's been changed and it doesn't just keep adding onto the answers column.
Jason Coco