Converting icons from 32bit to 16bit

The story behind this post

Last week I ran into an interesting bug at work. We were extracting icons on one windows machine and saving them on an another windows machine as part of one of our features. This was a mechanism developed a while ago and it worked fine so far. Recently though, we began to notice certain icons on the target machine had variations of pinkish overlay clearly visible. Upon closer inspection of the icons and comparison to the originals it became clear that semi-transparent areas of the icon did not retain their transparency property at all. Instead, the color used for transparency marking (traditionally cyan) was saved to the colors layer; creating a visible pink-like overlay in the relevant areas of the icon.

A little more testing and we found the culprit, sort of. We know it has something to do with moving an icon from a 16bit color depth machine to a 32bit one. Normally, we would investigate further and try to pin-point the root of this problem. However, since we are planning to move both systems to 32 bit color depth soon (before the product is released) we just needed something that would work for now, and that would be easy to cancel out once we make the move to 32bit. In short, a band aid.

How we got to downgrading the color bit depth of an icon

Now, if you read the previous section, you’d be a bit surprised to find out we want to downgrade the icon from 32bit to 16bit. Wasn’t it the other way around? you ask. And you’re right, we are extracting the icon on the 16bit machine, and my instinct was converting 16bit to 32bit. However, on our specific configuration (which is a bit non-standard) we need to do the exact opposite. We extract the icon from whatever resource file it is in (exe, dll, icon file, icon library) and convert it to 16bit. When we send this converted icon to the 32bit machine – the pink overlay is gone! As simple as that.

I’d like to add some final disclaimer note here though: Like I mentioned before, the configuration on the source machine is rather not-standard and there might be some bit depth duality in that system where several processes or even sessions run a different color bit depth at the same time. This might have caused that pink overlay anomaly but we’re not sure, and as I said in the previous section, it is not worth pursuing at the moment.

Converting an icon using the Bitmap class

It’s really quite easy. The Bitmap class contains a clone method which allows you to control the result’s bit depth as well as other useful parameters. The following code is a simplification of what we did in production code, done for clarity.

 

    1:  using System.Drawing;
    2:  using System.Drawing.Imaging;
    3:  using System.IO;
    4:   
    5:  class Sample {
    6:      public void ConvertIcon() {
    7:   
    8:          // Loading the original icon
    9:          Icon icon = new Icon("originalIcon.ico");
   10:   
   11:          // Converting it to bitmap, to allow image manipulation
   12:          Bitmap bitmap = icon.ToBitmap();
   13:   
   14:          // This rectangle has no meaning for us, it just has to encompass the entire image
   15:          Rectangle r = new Rectangle(0, 0, bitmap.Width, bitmap.Height);
   16:   
   17:          // Using the clone method to convert the icon
   18:          Bitmap bmp = bitmap.Clone(r, PixelFormat.Format16bppArgb1555);
   19:   
   20:          // And we claim back the icon (to retain the ico format) and save it.
   21:          icon = Icon.FromHandle(bmp.GetHicon());
   22:          FileStream stream = new FileStream("convertedIcon.ico", FileMode.Create);
   23:          icon.Save(stream);
   24:          stream.Close();
   25:      }
   26:  }