Java GIF transparency stuff

Still alive.

At work last week we had a problem with transparent GIFs. Our Java program needed to be able to resize images. However, the approach taken worked with all tested formats except transparent GIFs.

After searching the internet for a while, I was able to piece together a solution that a) worked and b) avoided unnecessarily allocating memory (which was a “feature” of most other solutions I found). It appears this is a relatively common problem, maybe some lost soul in a similar situation will find it helpful.

The nature of our program was that the image content was loaded, transformed and saved. The loading and saving was performed by the Java ImageIO class, and it is possible that these steps are unnecessary if you are using a custom image codec library. I didn’t look into it too deeply.

This is the solution, minus the details of our image manipulation. It lives in a static Image Utility class.

/**
 * The ever problematic GIF format needs special handling. 
 * If the background colour is not cleared to the transparent colour the image loses transparency.
 */
private static void handleGifTransparency(
	BufferedImage output,
	ColorModel colourModel,
	Graphics2D graphics) throws IOException
{
	if(colourModel instanceof IndexColorModel)
	{
		IndexColorModel indexed = (IndexColorModel)colourModel;

		int index = indexed.getTransparentPixel();
		if(index == -1)
		{
			// Should never happen, caller checks if image is opaque.
			throw new IOException("no alpha pixel with transparent PNG");
		}
		int r = indexed.getRed(index);
		int b = indexed.getBlue(index);
		int g = indexed.getGreen(index);
		Color c = null;
		if(indexed.hasAlpha())
		{
			int a = indexed.getAlpha(index);
			c = new Color(r,g,b,a);
		}
		else
		{
			c = new Color(r,g,b);
		}
		graphics.setBackground(c);
		graphics.clearRect(0, 0, output.getWidth(), output.getHeight());
	}
}

private static BufferedImage modify(
	BufferedImage input,
	int width,
	int height,
	String format) throws IOException
{
	
	ColorModel colourModel = input.getColorModel();
	
	BufferedImage output = new BufferedImage(colourModel, colourModel.createCompatibleWritableRaster(width, height), input.isAlphaPremultiplied(), null);
	
	Graphics2D graphics = output.createGraphics();
	
	try
	{
		if(format.equals("gif") && output.getTransparency() != Transparency.OPAQUE)
		{
			handleGifTransparency(output, colourModel, graphics);
		}

		// Whatever you want to do here
		doModifications(graphics);
	}
	finally
	{
		graphics.dispose();
	}
	return output;
}

If you happen to know a less ugly method, let me know!

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: