Custom Palette GIFs in c#
Today, I spent some time investigating a common problem that
comes up over and over. Most of the time image manipulation in .net involves working
with 24 or 32 bit images, but when you go to save one of these images as a GIF
file you run into problems because the GIF codec used by GDI+ is not smart
enough to create a palette for the image you are saving, it just uses its
default. This is especially annoying when you purposely use less than 256
colors, and they end up being dithered because they aren’t in the default
palette.
If you search on Google, you can find some sample code from
Microsoft that works.
http://support.microsoft.com/kb/319061/EN-US/
DO NOT USE THE TECHNIQUE THAT MS SUGGESTS IN THE ARTICLE. You
would expect that the company that wrote the classes would be able to tell you
how to properly use them, but here they don’t.
After some experimenting with the code provided and using
Reflector to decompile the classes involved, I have figured out how to create a
custom palette properly. In the article they suggest that you should create a
temporary bitmap and “steal” its palette. For starters the very
idea is a waste of resources, and second, this just seems stupid.
When you access the Image.Palette property you get a
ColorPalette object, and you expect that if you modified this object, you would
update the palette of the image, but this is not the case. Every time you get
the property, the Image object creates a new ColorPalette object. So the
following code does nothing!
for (int x = 0; x < 256; x++)
img.Palette.Entries[x]
= Color.FromArgb(255, x,x,x);
In fact the code above will create 256 ColorPalette objects,
each with one color modified, and then toss them all to the garbage collector. GRRR!
Once we know that it creates a new ColorPalette object, we don’t have to “steal”
anything, and we can write the correct version.
ColorPalette pal = img.Palette;
for (int x = 0; x < 256; x++)
pal.Entries[x]
= Color.FromArgb(255, x,x,x);
img.Palette = pal;
Unfortunately, it is not the most intuitive design, but it
is simple to use. Many hours of wasted programming would have been saved had Microsoft
usability tested this one property, but alas they didn’t. I hope that
someone else can find this useful and avoid wasting hours of productivity.
–Stefan