[Back to WIN-OS2 SWAG index] [Back to Main SWAG index] [Original]

    {
    Some days ago someone asked me about the icon file format. I will publish
    these messages just once. So put it in your archives please :-)
    (I don't save my own messages, I never did :).

    Header
    }
    TIconHeader = record
      idReserved: Word; (* Always set to 0 *)
      idType: Word;     (* Always set to 1 *)
      idCount: Word;    (* Number of icon images *)
      (* immediately followed by idCount TIconDirEntries *)
    end;
    {

    A .ICO file can contain several icon images. Each image can differ in size,
    resolution and color format.

    }
    TIconDirEntry = record
      bWidth: Byte;          (* Width *)
      bHeight: Byte;         (* Height *)
      bColorCount: Byte;     (* Nr. of colors used, see below *)
      bReserved: Byte;       (* not used, 0 *)
      wPlanes: Word;         (* not used, 0 *)
      wBitCount: Word;       (* not used, 0 *)
      dwBytesInRes: Longint; (* total number of bytes in images *)
      dwImageOffset: Longint;(* location of image from the beginning of file *)
    end;

    {
    bColorCount refers to the number of palette entries in the image data. For the
    most common icon type (32x32 pixels, 16 colors) the first three fields would be
    32, 32 and 16 resp.

    dwBytesInRes is the total number of bytes in the image data (including palette
    data!). dwImageOffset is an offset (from the beginning of the file) to the
    image data.

    Image data

    The icon file stores image data in the so-called device independent bitmap
    (DIB) format. It's supposed to be fairly device independent :-). The actual
    pixel data is preceded by two "structures": the bitmap info header and the
    palette data.

    First the bitmap info header (pasted from the BP WinSDK help, comments are
    mine):
    }
    TBitmapInfoHeader = record
      biSize: Longint;    (* sizeof(TBitmapInfoHeader *)
      biWidth: Longint;   (* width of bitmap *)
      biHeight: Longint;  (* height of bitmap, see notes *)
      biPlanes: Word;     (* planes, always 1 *)
      biBitCount: Word;   (* number of color bits *)
      biCompression: Longint; (* compression used, 0 *)
      biSizeImage: Longint;   (* size of the pixel data, see notes *)
      biXPelsPerMeter: Longint; (* not used, 0 *)
      biYPelsPerMeter: Longint; (* not used, 0 *)
      biClrUsed: Longint;       (* nr of colors used, set to 0 *)
      biClrImportant: Longint;  (* important colors, set to 0 *)
    end;

    {
    biBitcount contains the number of color bits per pixel. If it's 4, it means a
    pixel can have 16 colors (2 shl 4). biBitcount also refers to how a pixel is
    "coded" in the pixel data. If biBitcount is 4 a pixel takes 4 bits of an image
    byte. If it's 8 (256 possible colors), a pixel is a byte.

    As you perhaps know, icons are created by combining two bitmap masks: the
    XOR-mask and the monochrome AND-mask. To draw an icon you first copy the mask
    to the screen with an AND operator, then you copy the XOR-mask with an XOR
    operator.

    Therefore the biHeight field is set to 2 * TIconDirEntry.bHeight and
    biSizeImage is set to the size of the AND plus the XOR mask (ofcourse in
    bytes). For example, for a 32x32 16 color icon biHeight would be 64 and
    biSizeImage 512 + 128.

    OK. How do you determine the size of the masks?

    XOR mask: (TIconDirEntry.bWidth * TIconDirEntry.bHeight * biBitCount) / 8
    AND mask: (TIconDirEntry.bWidth * TIconDirEntry.bHeight) / 8

    The palette data

    The bitmap info header is followed by a table with palette entries. The actual
    pixel data refer to this table. So when a pixel has color 13, look at palette
    entry number 13 to get the actual RGB color for the pixel. At this moment
    Windows just supports 2 (monochrome), 16 and 256 colors, so there's always a
    palette table.

    An entry in the palette table has the following format:
    }

    TRGBQuad = record
      rgbBlue: Byte;      (* blue component of color *)
      rgbGreen: Byte;     (* green component of color *)
      rgbRed: Byte;       (* red component of color *)
      rgbReserved: Byte;  (* reserved, 0 *)
    end;

    {
    For Windows programmers: this record is *not* equivalent to a TColorRef (or
    COLORREF). If you forget this, you'll get some odd colored icons :-).

    An icon has TIconDirEntry.bColorCount palette entries. So there are
    sizeof(TRGBQuad) * TIconDirEntry.bColorCount bytes in the palette.

    The monochrome AND mask does _not_ have a palette table. A 1 bit in the AND
    mask's pixel data means a _white_ pixel on-screen. A 0 bit means a black pixel.

    On the other hand, the pixel data of monochrome icons _are_ preceded by a
    palette table.

    Pixel data

    Now to the real nitty-gritty. Immediately after the palette data, the pixel
    data follow. Remember: the pixel data contain both the XOR and AND bits.

    There's something odd with the storage of the mask bits: both mask data are
    stored in bottom up format. For example: in a 32 x 32 16 color icon the first
    32 nibbles belong actually to the last pixel row. The second 32 nibbles form
    the last - 1 pixel row. And so on.
    Retrieving pixels is a little bit hard. Just keep track of the biBitCount
    value. Write different functions for monochrome, 16 and 256 color icons or keep
    a running bit mask ready.
    In Windows creating an icon from .ICO file is rather easy, call the
    CreateDIBitmap function twice (for the AND mask/XOR mask). Then call
    GetBitmapBits to retrieve the bitmap data.
    Under DOS you have to do a little more: e.g. translation of RGB colors.
    }

[Back to WIN-OS2 SWAG index] [Back to Main SWAG index] [Original]