Assembling an ICO file with icons in PNG format using FASM

  • Tutorial
Sometimes I write small programs in C ++, and often it turns out that the program icon “weighs” more than the program itself. The same happened when writing Sound Keeper : the program - 14KB, the icon 16 × 16 + 32 × 32 + 48 × 48 pixels - 15KB. What a waste! Fortunately, it turned out that Windows (starting with Vista) supports PNG inside ICO. This is just what you need! But for some reason there was no program that would allow you to optimize PNG files yourself and compile an ICO file from them. Since ICO files have a very simple format, let's compile it using FASM . This non-standard use of the “flat” assembler shows that it can be used in the most unexpected situations, and it works!

Let's get started


1. Create images for the icons in PNG format. For example, we’ll make two images with sizes of 16 × 16 and 32 × 32 pixels. Save them to the icon16.png and icon32.png files, respectively. We optimize to your taste with your favorite tools.

2. Following the documentation , create the icopng.asm file with approximately the following contents:
dw 0 ; reserved, must be 0
dw 1 ; icon type, must be 1
dw 2 ; number of images in file
; 1st icon header
db 32 ; width
db 32 ; height
db 0 ; no color palette
db 0 ; reserved, must be 0
dw 1 ; planes
dw 32 ; bits per pixel
dd icon32_end-icon32_start ; length
dd icon32_start ; offset
; 2nd icon header
db 16 ; width
db 16 ; height
db 0 ; no color palette
db 0 ; reserved, must be 0
dw 1 ; planes
dw 32 ; bits per pixel
dd icon16_end-icon16_start ; length
dd icon16_start ; offset
; 1st icon body
icon32_start:
file 'icon32.png'
icon32_end:
; 2nd icon body
icon16_start:
file 'icon16.png'
icon16_end:
Empirically, it was found that it is better to connect the images in the reverse order, from large to smaller. When adding more icons, do not forget to correct the field with the total number of images in the header. A mistake here can lead to the most unexpected consequences.

3. Assemble the icon with the command:
fasm icopng.asm icopng.ico

4. As a result, we got an icon with PNG images. Instead of 15KB, I got a file that is only 3KB in size.

PNG8 support with alpha


According to meager documentation , only PNG32 format images should be supported. In practice, the system decodes PNG8 images without problems even with an alpha channel. Unless only the Windows image viewer understands PNG8 in icons, apparently it does not use system functions to decode and render the icon. But you do not make icons in order to watch them in the image viewer, right? :) Everywhere where standard Windows functions are used to load and display icons - PNG8 with alpha channel is displayed in the same way as PNG32.

Important note: even for PNG8 images, the header should indicate a lack of a palette, because the PNG decoder outputs a TrueColor image with an alpha channel, where any color can be found. That is, in the example, you will only need to change the width and height fields. You don’t need to touch the rest.

Problem in PNG system decoder


PNG support for icons in Windows Vista and newer is used by default to save only large 256 × 256 icons. Apparently, PNG support inside the ICO was poorly tested, so there are some problems and workarounds for them.

Some error was detected in the PNG system decoder, due to which a particular icon file may not be displayed correctly in some places (for example, in the file properties dialog). Moreover, a minimal change in compression parameters easily solves the problem.

I did a little research on the icon file that did not display correctly in the file properties dialog. The DrawIconEx system function has 3 icon rendering modes: DI_NORMAL (with alpha), DI_IMAGE (without alpha) and DI_MASK (mask only).



In this image you can see how the same icon was displayed in different modes, and under the name RESULT shows how this icon looks in the file properties. It can be seen that in the DI_NORMAL and DI_IMAGE modes, the system renders the icon correctly. However, in DI_MASK mode, for some reason, the mask calculated for compatibility was shifted three pixels to the right, and some garbage appeared in the first column of pixels - probably due to incorrect operation with the buffer. The icon in the file properties, as you can see, has serious artifacts just according to the outlines of the incorrect mask. It would be nice to report this problem to Microsoft developers, but unfortunately, I did not find any open bug tracker.

PNG optimization tips


I recommend using the Color Quantizer program to convert files from PNG32 to PNG8 with an alpha channel. The resulting file, among other things, is compressed by a very efficient algorithm, so usually additional optimization is not required.



In the screenshot, the block with the choice of the number of colors and the coefficient of allowable quantization errors is highlighted in red. If the problem described above arises with incorrect display of the icon in the file properties dialog, just change the quantization parameters. For example, slightly change the value of the coefficient of permissible quantization errors.

That's all


Now your compact programs can be with colorful icons of all necessary sizes. No need to sacrifice transparency or the number of options for the icon. There is only one drawback - Windows XP users will not see such an icon. But given that official support for Windows XP has long ended, and fewer computers are running this operating system, it’s not so bad. Moreover, authors of small programs often do not add an icon at all to save money.

Also popular now: