PNG files: easy to view, edit, etc
ICO files: seemingly opaque, bitmap-based, and scary
It doesn't have to be this way!
Starting with Windows Vista, ICO files can be created using a handful of PNGs and some fancy file concatenation.
That's right! This newer "PNG type" of ICO file is essentially just PNGs in a trench coat (the trench coat is a file header).
First, budget out space for three 2-byte fields.
dw 0, 1, NUM_IMAGES
- The first field has to be zero. Reserved fields, am I right? :)
- The second field can be either 1 (for ICO files) or 2 (for CUR files). Since we're talking about ICO files, set it to 1.
- The third field is how many images will be in this ICO file.
I feel like the whole point of ICO files is to have multiple images at different resolutions to have better images displayed on the desktop or in UI screens. Thinking thusly, this third field should almost always be greater than 1. Still, you can have an ICO with just one PNG in it and nobody will call you out.
Next comes one sixteen-byte structure for each image in the ICO file.
db WIDTH, HEIGHT, COLORS, 0 dw PLANES, BPP dd SIZE, OFFSET
HEIGHT(in pixels) are interpreted as unsigned bytes and are therefore limited to values 0-255. If the value is 0, it means that the image's dimension is 256 pixels.
COLORSis the number of colors in the color palette of the image. It seems that even if you are using paletted PNG files, this can be set to 0 and Windows will figure out the palette information on its own.
- There's another byte of reserved space :)
PLANESis the number of color planes in the image. I've never set this to anything but 0. Here's an interesting Wikipedia footnote with some more info about this field.
BPPis the bits per pixel of the image. This is another field I've always set to 0. It seems like setting it to 0 will let Windows infer BPP from the PNG itself.
SIZEis the size of the PNG.
OFFSETis the absolute location in this ICO where this PNG is located. Another way of asking "how many bytes into the file can I find this PNG?"
Once you've got each of those structures in place, start concat-ing PNGs onto that file. No, seriously, you can just add PNGs onto the end of the file and so long as you set the
OFFSET fields you're good.
Here's the general template I use.
%define R(x) (x - $$) %macro IMG 2 db %2, %2, 0, 0 dw 0, 0 dd %1.len, R(%1) %endmacro %macro IMGDAT 2 %1: incbin %2 .len equ $ - %1 %endmacro NUM_IMAGES equ 5 dw 0, 1, NUM_IMAGES IMG a, 0 IMG b, 128 IMG c, 64 IMG d, 32 IMG e, 16 IMGDAT a, "256.png" IMGDAT b, "128.png" IMGDAT c, "64.png" IMGDAT d, "32.png" IMGDAT e, "16.png"
If you name that file
x.ico.s, NASM will make
x.ico from it without needing to specify the filename with
-o! Then all you need is a set of PNGs you want to bundle in the same directory and you can generate an ICO out of them.
nasm x.ico.s makes