In an effort to make our gate camera images visible on a ridiculously small cellphone screen, I spent the past couple of days learning about the process of image Quantization. GDI+ will allow you to take a full-color 32 bpp image and save it as a .gif file! This turns out to be quite simple, and you can even re-size the image before saving it, by using the CreateThumnailImage method.
System.Drawing.Bitmap b = new System.Drawing.Bitmap(“c:\\original_image.gif“);
System.Drawing.Image thmbnail = b.GetThumbnailImage(100,75,null,new IntPtr());
thmbnail.Save(“c:\\thumnail.gif“, System.Drawing.Imaging.ImageFormat.Gif);
“Cool!“ You're thinking to yourself, but don't think too soon. You may be less-than-impressed by the dithery, grainy image produced by this technique. Here's the output of this method with one of our gate camera images:
So, what accounts for the grainy image? It has to do with color quantization, sometimes called “palettization” or simply, the process of slapping a 256 color palette onto a full-color image, thereby reducing the total colors (and file-size). The image is grainy because GDI+ by default uses the windows 256-color palette, and doesn't take into account the colors in the actual image. When I found this out I went in search of a better color quantization technique for saving .GIF images...
Personally I've found that almost all GIF images should be saved with an adaptive palette. These days, forget about the Web Palette, unless you're doing icons or big areas of solid color. Most everyone will be running in at least 16K colors, and if by some small chance they're still running 256 colors, the browser will dither an adaptive image to a reasonable version anyhow. An adaptive palette contains the 256 most frequently used colors in the image. Well, um sort of anyway. (As an aside, I tried to write my own “popularity palette” algorithm which used the most frequently used colors to build the palette, but my images looked worse than before!) A good quantization algorithm also takes into account spacing between colors and stores colors that are, say blue and very-nearly-blue as one color, freeing up more space for colors that the eye sees as separate. One such adaptive palette algorithm is called the “Octree“ algorithm.
I found two articles from Microsoft that helped out a great deal, KB 319061 and Optimizing Color Quantization for ASP.NET Images by Morgan Skinner at MS. Morgan's article had some great code samples, and really useful base class which will allow you to plug in your own algorithm to quantize images. I ended up pulling bits and pieces of code from the two articles to create a library of objects used for creating Octree and Grayscale palettes. Using the OctreeQuantizer object was easy, as you can see in this code snippet:
System.Drawing.Bitmap b = new System.Drawing.Bitmap(“c:\\original_image.gif“);
System.Drawing.Image thmbnail = b.GetThumbnailImage(100,75,null,new IntPtr());
OctreeQuantizer quantizer = new OctreeQuantizer ( 255 , 8 ) ;
using ( Bitmap quantized = quantizer.Quantize ( thmbnail ) )
{
quantized.Save(“c:\\thumnail.gif“, System.Drawing.Imaging.ImageFormat.Gif);
}
OctreeQuantizer grayquantizer = new GrayscaleQuantizer ( ) ;
using ( Bitmap quantized = grayquantizer.Quantize ( thmbnail ) )
{
quantized.Save(“c:\\thumnail.gif“, System.Drawing.Imaging.ImageFormat.Gif);
}
This code produced the following beautiful (In this case, beauty truly is in the eye of the guy who just spent three days trying to get it to work!) thumbnails, one with an adaptive palette, and one in grayscale.

If you've got a cellphone with web capabilities, go to http://mobile.vit.org/ and see the image in all its 100 X 75 pixel glory.
UPDATE:
See this post here for the latest version of this library
-Brendan