The evolution of the ICO file format, part 2: Now in color!

Last time, we looked at the format of classic monochrome icons. But if you want to include color images, too? (Note that it is legal—and for a time it was common—for a single ICO file to offer both monochrome and color icons. After all, a single ICO file can offer both 16-color and high-color images; why not also 2-color images?)

The representation of color images in an ICO file is almost the same as the representation of monochrome images: All that changes is that the image bitmap is now in color. (The mask remains monochrome.)

In other words, the image format consists of a BITMAPINFOHEADER where the bmWidth is the width of the image and bmHeight is double the height of the image, followed by the bitmap color table, followed by the image pixels, followed by the mask pixels.

Note that the result of this is a bizarre non-standard bitmap. The height is doubled because we have both an image and a mask, but the color format changes halfway through!

Other restrictions: Supported color formats are 4bpp, 8bpp, 16bpp, and 0RGB 32bpp. Note that 24bpp is not supported; you’ll have to convert it to a 0RGB 32bpp bitmap. Supported values for biCompression for color images are BI_RGB and (if your bitmap is 16bpp or 32bpp) BI_BITFIELDS.

The mechanics of drawing the icon are the same as for a monochrome image: First, the mask is ANDed with the screen, then the image is XORed. In other words,

pixel = (screen AND mask) XOR image

On the other hand, XORing color pixels is not really a meaningful operation. It’s not like people say “Naturally, fuchsia XOR aqua equals yellow. Any idiot knows that.” Or “Naturally, blue XOR eggshell equals apricot on 8bpp displays (because eggshell is palette index 56, blue is palette index 1, and palette index 57 is apricot) but is equal to #F0EA29 on 32bpp displays.” The only meaningful color to XOR against is black, in which case you have “black XOR Q = Q for all colors Q”.

mask image result operation
0 Q (screen AND 0) XOR Q = Q copy from icon
1 0 (screen AND 1) XOR 0 = screen nop
1 Q (screen AND 1) XOR Q = screen XOR Q dubious

For pixels you want to be transparent, set your mask to white and your image to black. For pixels you want to come from your icon, set your mask to black and your image to the desired color.

We now have enough information to answer a common question people have about icons. After that break, we’ll return to the evolution of the ICO file format.

For further reading: Icons in Win32.

Comments (26)
  1. Medinoc says:

    Another color that is meaningful to XOR with is white: It produces that nead "color inversion" effect in 32bpp.

    I actually used this for some (cool but impractical) cursors, and Paint XP does so for the "spilling" part of its filling tool cursor.

    [Color inversion isn't as helpful as you might think. -Raymond]
  2. Medinoc says:

    Also, Visual Studio resource editors offer this "negative" color, and it also works in 16bpp and the 4bpp default palette (for others, I have doubts).

  3. Dan Bugglin says:

    "[Color inversion isn't as helpful as you might think. -Raymond]"

    Well the color of the background always has to be kept in mind.  A solid white mouse cursor works great on a black background, but not on white.  Hence it also has a black outline for contrast (at least I assume that is the reason).  Similarly you wouldn't want an icon or cursor composed entirely of "inverse", using it with high-contrast colors (ie white and black) would help keep it visible.

    The way the masking works does explain this inverse "color" which I could never figure out since that plus the screen "color" plus 16 colors seemed to give 4bpp icons 18 colors which never made sense to me!  But now I know about the mask.  So thanks.

  4. Alex Grigoriev says:

    XOR is not "dubious" when it's a cursor.

    [It is still dubious for cursors. Can you see the i-beam cursor in the following text? Some text on|gray background. This is a real problem, as noted in the fourth comment. -Raymond]
  5. Sukru says:

    Was the color palette standard on these bitmaps?

    I remember 256 color Win 95 times where most of the screen would go out of sync with the palette when a new app was open. So much time has passed, I might not even be remembering correctly…

  6. Dan Bugglin says:

    Windows used a standard color bitmap… something like 3 bits for red, 2 bits for green, and 3 bits for blue or something… 8 bits, 256 colors.

    Other apps could set their own palettes though, usually games, which of course caused the desktop to redraw and try and find new "closest" colors to the 24-bit color they wanted.

  7. Dan Bugglin says:

    Wait, it looks like it does… using values of 0-5 for RGB:…/List_of_software_palettes

  8. Tihiy says:

    Now what about new Vista icons with PNG (afaik) compressed data?

    [Dude, we're only on Part 2 (1985). -Raymond]
  9. W says:

    "Was the color palette standard on these bitmaps?"

    As far as I can remember when you ran windows 9x on 8bpp then it would show the 16bpp image. For the 256 color windows had to use at least 16bpp. And I think Win 95 even needed some registry patch to display 256 color icons at all.

  10. DWalker59 says:

    Of COURSE if you XOR fuchsia and aqua you get yellow, that's obvious.  The people who make up color names for house paint are odd ducks; our exterior stucco was redone in colors called … wow, I can't even remember.  Something like Plateau and Sea Mist (but those weren't the exact ones).

    If you XOR ecru with eggshell, what do you get?

  11. Adrian says:

    Not only was it common to include both monochrome and color, for a while it was practically mandatory.

    I remember getting bug reports because some of our icons had only color versions and not monochrome.  We had a bunch of customers (and some developers) using monochrome VGA displays.  Windows would dither the color icons on those systems, but that generally made for a pretty ugly (and sometimes unrecognizable) image.

  12. laonianren says:

    "Was the color palette standard on these bitmaps?"


    Handling palettes was a pain (and still is, but nobody bothers).  When your app is in the foreground you get to choose the palette, but when activation moves away you have to render your app against the new palette as best you can (otherwise you get a hideous false-colour rainbow effect when all the colours change).

  13. Marquess says:

    So if I replace the ANDs with ones, I get a trippy disco-lights cursor?

    Mental note: Write icon editor without silly limitations.

  14. rs says:

    Everything about color palettes:…/en-us…/ms969897

    Bitmaps have a color table.

  15. Skyborne says:

    "(otherwise you get a hideous false-colour rainbow effect when all the colours change)."

    Reminds me of the glorious days of 8-bit X11.  Even better was the day I discovered, somewhere in the 2000s, that I could fire up the X server in grayscale mode… and that zsnes would still be able to render color on such a screen (with rainbow mess on the rest of the desktop.)  I couldn't take a screenshot of the effect, because the X server knows what the color is supposed to be, and sends back TrueColor image data of a color zsnes window on a grayscale screen.

  16. Andreas Rejbrand says:

    @Skyborne: I wish you'd taken a photograph of your monitor.

  17. hagenp says:

    Excellent article (series). Raymond, many thanks again!

  18. RIFF says:

    Why can't mspaint save to opaque ico/cur files?

  19. Medinoc says:

    I learned the hard way that an entirely inverting cursor sucks indeed. I have the hot spot and most important parts in black and white (quite the opposite of the MS Paint filling cursor) so a grey background won't make them unusable… And they are *still* too impractical for professional use. I quickly discovered that the most practical cursors are the most standard ones.

  20. JustSomeGuy says:

    Mate, I want to see the body of the dubiousOperation() function :-)

  21. Neil says:

    I devised some cursors which look like the basic cursors but have no mask bits. However I ran into the grey background issue. I then discovered that that you could set the colour to 0x808080 and although this would only give you 50% contrast it would work on any background. Sadly this "feature" was discontinued in Windows XP, presumably as part of the true colour icon support.

    @Marquess: Yes, but only on Windows 95 to 2000.

    [It works on any solid background. Now try it over an image of static. -Raymond]
  22. Skyborne says:

    @Andreas Rejbrand – well, it's your lucky day!  Since the screenshot includes the clock, I was able to find the lone photo that I took of it: ; and the screenshot I was talking about is .

  23. Vlasta says:

    I encountered really strange things regarding new icons (png-compressed, 32bit) and Windows 2000 Explorer.


    * If the .ico file contains 32bpp, 8bpp, 4bpp images in sizes 16,32,48, Explorer works OK.

    * If the .ico file contains 32bpp, 8bpp, 4bpp images in sizes 16,24,32,48, Explorer fails and shows the stock icon.

    * If the .ico file contains 32bpp, 8bpp, 4bpp images in sizes 16,32,48,256-png, Explorer fails and shows the stock icon.

    * If the .ico file only contains 32bpp (with alpha) images in sizes 16,24,32,48,256-png, Explorer shows 32×32 image although the alpha blending is of course not done properly.

    * If the .ico file contains the above PLUS 8bpp and 4bpp images in all those sizes, Explorer fails and shows the stock icon.

    * If the .ico file contains ONLY 8bpp and 4bpp images in all those sizes, Explorer shows 32×32 image.

    What puzzles me most is that Explorer fails to show the icon only if combination of factors is in effect. If you start with a simple old icon containing 8bpp and 4bpp images in 16,32,48 sizes, you can either add 32bpp color depth images or 24×24 images, but not both if you still want the icon to be visible on Windows 2000 desktop or Start menu…

    It may be that I am writing the .ico files incorrectly, but after re-saving them with VS, the situation is unchanged… and they work fine on newer Windows, so I doubt it.

    This makes it hard to recommend to someone what images to include in an .ico file or what should be the defaults in my icon editor. Right now I am ignoring Windows 2000, but my conscience is not clear…

    I'll be reading this series of articles and see whether Raymond recommends what images a proper .ico file should have in the end :-). Thanks for the information.

    (BTW 24bpp images seem to work without problems at least in W2k and newer.)

  24. yuhong2 says:

    " And I think Win 95 even needed some registry patch to display 256 color icons at all."

    Yea, remember Plus! for Windows 95?

  25. Richard Russell says:

    @Vlasta "24bpp images seem to work without problems at least in W2k and newer"

    This article explicitly states that 'Icons and cursors in Windows XP can be any color depth, to a maximum of 32 Bits-Per-Pixel (BPP)':…/307213

    I'm sure that includes 24 bpp.

Comments are closed.