The evolution of the ICO file format, part 3: Alpha-blended images


Windows XP introduced the ability to provide icon images which contain an 8-bit alpha channel. Up until this point, you had only a 1-bit alpha channel, represented by a mask.

The representation of an alpha-blended image in your ICO file is pretty straightforward. Recall that the old ICO format supports 0RGB 32bpp bitmaps. To use an alpha-blended image, just drop in a ARGB 32bpp bitmap instead. When the window manager sees a 32bpp bitmap, it looks at the alpha channel. If it's all zeroes, then it assumes that the image is in 0RGB format; otherwise it assumes it is in ARGB format. Everything else remains the same as for the non-alpha version.

Note carefully that everything else remains the same. In particular, you are still required to provide a mask. I've seen some people be a bit lazy about providing a meaningful mask and just pass in all-zeroes. And everything seems to work just fine, until you hit a case where it doesn't work. (Read on.)

There are basically three ways of drawing an alpha-blended icon image.

  1. Draw­Icon(DI_NORMAL): This is by far the most common way icons are drawn. In the alpha-blended case, this is done by blending the image with the destination according to the alpha channel.
  2. Draw­Icon(DI_IMAGE): This draws the image portion of the icon image, completely overwriting the destination.
  3. Draw­Icon(DI_MASK): This draws only the mask portion of the icon image, completely overwriting the destination.

The DI_IMAGE and DI_MASK flags let an application draw just one of the two images contained in an icon image. Applications do this if they want finer control over the icon-drawing process. For example, they might ask for the mask so they can build a shadow effect under the icon. The mask tells them which parts of the icon are opaque and therefore should cast a shadow.

If you understand this, then you can see how people who set their mask image to all-zeroes managed to get away with it most of the time. Since most programs just use DI_NORMAL to draw icons, the incorrect mask is never used, so the error never shows up. It's only when the icon is used by a program that wants to do fancy icon effects and asks for DI_MASK (or calls Get­Icon­Info and looks at the hbmMask) that the incorrect mask results in an ugly icon.

The ironic thing is that the people who incorrectly set the mask to all-zeroes are probably the same people who will then turn around and say, "When I try to use alpha-blended icons, the result is hideously ugly under conditions X and Y. Those Microsoft programmers are such idiots. More proof that Windows is a buggy pile of manure." What they don't realize is that the hideous ugliness was caused by their own error.

Comments (20)
  1. Pierre B. says:

    Or, or, or… the guys doing the fancy processing could just upgrade their code to take into account the alpha. I guess that even with a proper mask, given that if someone uses alpha it's because their icon has semi-transparent regions, doing a drop shadow based solely on the mask will still look ugly in many cases.

    The ARGB icon format basically has two places where masking information is kept. Ignoring proper alpha processing is no better than ignoring to need for a mask.

    (Yes, I'm being unfair and ignoring backward compatibility. In my mind, as a user, if a program requires backward compatibility it's because it's being poorly maintained and is probably not evolving with the new OS releases, and I'll vote with my feet and move on to something that keeps up with the days.)

    [Translation: Every application vendor who does not issue an update to their program the same day the OS is released is a lazy bum. -Raymond]
  2. Joshua says:

    I've been wondering how this worked.

    I used to use a downscaler program to make icons from 24bit bitmaps that made Win95 compatible (actually wouldn't surprise me if they were Win31 compatible) icons that did a pretty good job of mimicking the WinXP style.

    The hard part was always un-antialiasing the icons before generation as otherwise they'd look ugly when on the wrong color background.

    I suppose the ARGB format was intended to do away with the need to do that, although you wouldn't believe how many people do it wrong by antialiasing to white and then transforming the outside white to transparent with something like paint's bucket tool. The correct way to do it is to extend your base colors over the entire antialias range and ARGB blend those pixels according to what the antialias algorithm would say you do.

  3. Adrian says:

    Ah, I never understood how the mask was used when the icon had an alpha channel.  Good info, thanks.

  4. Medinoc says:

    Does this mean that when icons include an alpha-blended drop shadow, it's better to make this shadow transparent in the mask?

  5. blah says:

    On one hand, The Real WTF was the failure of the OS to use the alpha channel as the mask.

    On the other, a zero mask would work favorably for creating dynamic shadows. XP's very own 32-bit icons bake in a shadow. You want ugly? Try generating a shadow for an icon that already has one!

  6. WndSks says:

    I remember lots of Borland VCL based apps would show ARGB icons (XP folder icon etc) with a ugly all black fat shadow, I'm guessing they painted them just like older icons and the XP gdx designers included all of the shadow in the mask (instead of just 1 pixel, or 0 pixel shadow)

  7. WndSks says:

    While I don't use Delphi/C++ builder these days, using a 24bpp imagelist looks very much like the thing I'm talking about: img834.imageshack.us/…/wndsksontico3shadow.png

  8. Dan Bugglin says:

    That's because you're using 24bpp… so the alpha channel is discarded and only the mask is used.

    At least that's how I assume it's doing it.  I never knew WHY some apps did this before but now I do.  They're converting to 24bpp first.

  9. WndSks says:

    @Dan Bugglin: Yes, I know I'm using a 24bpp imagelist, but that was just to reproduce the issue. I have no clue if that is what the older apps did or if they draw the icons with custom code. Either way, the fault is with the icon designer for not checking the mask.

  10. Joe says:

    I think I remember running into issues on XP where GetIconInfo didn't preserve the alpha channel in the image portion of the icon. I was using trying to use SHGetFileInfo to get an icon and then GetIconInfo to extract the image and mask for serialization. To preserve alpha, I eventually had to create a dib and copy the bitmap with alpha channel from the imagelist bitmap. It seems like most of the icon and bitmap functions are not aware of the alpha channel.

  11. Mike Dunn says:

    Looks like I have some code to fix today.

  12. Anonymous Coward says:

    Blah is right. The bug isn't in the icon files missing the mask, since they have already got a mask (in the form of the alpha channel) but in Windows for using the 1bpp mask for icons, which looks ugly even if it is present, since the 32bpp icon is probably anti-aliased while the 1bpp mask cannot be. (Note: I've had to do some special processing on icons in the past, and I had to let go of DrawIcon(DI_MASK) since it's unusable even for icons shipped with Windows.)

    @Joshua: Microsoft's own ‘artists’ have been doing this on occasion… with bright magenta as the background colour. An example of the horror that can result is in Windows XP's file copy dialogue. Apparently the author of that animation didn't even look at it before sending it in.

    [Magenta is correct for common control animations since transparency is expressed via color-key. -Raymond]
  13. Gabe says:

    I thought the mask was to control hit testing. I.e. you would set the alpha channel to set whatever visibility you wanted, but the mask indicated which pixels you actually intended to be part of the icon. Fortunately Explorer only requires that you click on the icon's rectangle, but you could use the mask to implement a system that requires you to click on one of the foreground pixels of the icon (like Mac Finder used to).

  14. Miral says:

    I suspect that for most apps that suffered from incorrect icons, the fault can be laid at the feet of the icon-creation tools.  One of the drawbacks of not providing "official" resource editors with the OS/SDK.  (Although no doubt if you did, there'd be cries of "monopoly abuse"… despite Apple including ResEdit as standard in older versions.)

    @Gabe: That was actually a really useful feature, at times.  I remember making "labels" that could be moved around on the desktop or in a folder, which were created by creating a file with an invisible icon.  It could be dragged about by its name and renamed as desired, and it didn't show an icon (or hitbox for an icon), allowing them to be stacked closely together without interference.

  15. ender says:

    Interestingly, while Windows 2000 did not support alpha-blended icons, alpha-blended cursors worked just fine.

  16. Pierre B. says:

    Proper translation: Microsoft offers long beta period for each of their new OS. If a company can't be bothered to test their software during that period, then it is probably not actively well maintained. It's not like Microsoft drop new Windows versions on the unsuspecting world.

    [It was nine months between Windows 7 beta and general availability. Is that a "long" beta period? (Are you going to suspend development on the next version of your product for nine months in order to address compatibility issues in your older products? And since it's just a beta, how do you know the bug isn't really in Windows?) -Raymond]
  17. Wallice says:

    Quote: "The ironic thing is that the people who incorrectly the mask to all-zeroes are probably the same people who will then turn around and say, "When I try to use alpha-blended icons, the result is hideously ugly under conditions X and Y. Those Microsoft programmers are such idiots. More proof that Windows is a buggy pile of manure." What they don't realize is that the hideous ugliness was caused by their own error."

    Actually these are probably the people that open up MSDN and cannot find any useful documentation on the subject so fire up Google for a solution, and end up finding a solution that people have found to work through trial and error, all of which takes many hours longer than it should.

    [Hm, because the documentation on the icon file format (and what the pieces mean) has been around since 1995. That document is correct even for Windows XP alpha-blended icons. -Raymond]
  18. Anonymous Coward says:

    Raymond, you haven't read my post or Joshua's post carefully enough. The point isn't that the background colour is magenta (as you said, it gets colour keyed) but that the ‘artist’ anti-aliased the image to magenta. And apparently never previewed his animation before sending it in; that's what's unforgivable. Everyone makes mistakes, so handing in your work without looking it over is a sin, although in his defence apparently no one else at Microsoft checked his work either.

    [I stand corrected. -Raymond]
  19. Ian Boyd says:

    i never understood (and still don't after reading the last 3 blog entries and the linked Technical Article) what a 1-bit mask is supposed to represent in an alpha-blended world. It can't be used to determine "where icon stuff is, since there isn't a binary "inside" verses "outside". It could be used for hit-testing, but is not documented as such. It could be used to help generate a drop-shadow, but with an alpha-blended image that drop-shadow would not be accurate (e.g. a half-transparent folder would not cast a fully darkened shadow). i guess i would have to understand why someone would choose to ever call Draw Icon(DI_MASK), or GetIconInfo and look at the hbmMask member. (If they are expecting the mask to contain something useful then they are mistaken).

    [The mask is not very useful in an alpha-blended world. It only exists for backward compatibility with the non-alpha-blended world where the mask was useful. -Raymond]

Comments are closed.