Friday, July 20, 2007

Transparent gifs in Java

The people at SUN added gif support in Java 6.0 but they did such a poor job that we all should get some baseball bats and visit their headquarter: Not only did they forget to implement a reasonable quantizer (to reduce millions of colors to the 256 of the gif format) but they also have forgotten to support transparency or the A in RGBA. Additionally treating their IndexColorModel as an unwanted step child doesn't make it better neither...

So here is the code to write transparent gifs out of an RGBA Java image using Java 6.0:


ImageIO.write(convertRGBAToIndexed(sig.getImage()), "gif",);

public static BufferedImage convertRGBAToIndexed(BufferedImage src) {
BufferedImage dest = new BufferedImage(src.getWidth(), src.getHeight(), BufferedImage.TYPE_BYTE_INDEXED);
Graphics g = dest.getGraphics();
g.setColor(new Color(231,20,189));
g.fillRect(0, 0, dest.getWidth(), dest.getHeight()); //fill with a hideous color and make it transparent
dest = makeTransparent(dest,0,0);
dest.createGraphics().drawImage(src,0,0, null);
return dest;
}

public static BufferedImage makeTransparent(BufferedImage image, int x, int y) {
ColorModel cm = image.getColorModel();
if (!(cm instanceof IndexColorModel))
return image; //sorry...
IndexColorModel icm = (IndexColorModel) cm;
WritableRaster raster = image.getRaster();
int pixel = raster.getSample(x, y, 0); //pixel is offset in ICM's palette
int size = icm.getMapSize();
byte[] reds = new byte[size];
byte[] greens = new byte[size];
byte[] blues = new byte[size];
icm.getReds(reds);
icm.getGreens(greens);
icm.getBlues(blues);
IndexColorModel icm2 = new IndexColorModel(8, size, reds, greens, blues, pixel);
return new BufferedImage(icm2, raster, image.isAlphaPremultiplied(), null);
}