Search code examples
htmlimagecompressionimagemagickfavicon

How to compress ico file on imagemagick or other


I created a 32x32 png in photoshop exported as 500bytes.

favicon

Converted to ico using

magick convert .\favicon.png favicon.ico

And it became 5kb.
Question? Is there there a compression flag in imagemagick or anoter way to compress favicon.ico?


Solution

  • I just tried @dan-mašek's suggestion and it definitely works better than ImageMagick.

    With the PNGs I was working with, ImageMagick gave me a 5.4K .ico file despite asking for it to use .ico's support for embedded PNGs for the compression (apparently it ignores you for sizes under 256x256) while Pillow got it down to 1.8K.

    Here's how I went about crunching down my favicons based on an existing PNG-optimizing shell script I cooked up years ago:

    #!/bin/sh
    
    optimize_png() {
        for X in "$@"; do
            echo "---- Using pngcrush to strip irrelevant chunks from $X ----"
            # Because I don't know if OptiPNG considers them all "metadata"
            pngcrush -ow -q -rem alla -rem cHRM -rem gAMA -rem iCCP -rem sRGB \
                -rem time "$X" | egrep -v '^[ \|]\|'
        done
    
        echo "---- Using OptiPNG to optimize delta filters ----"
        # ...and strip all "metadata"
        optipng -clobber -o7 -zm1-9 -strip all -- "$@" 2>&1 | grep -v "IDAT size ="
    
        echo "---- Using AdvanceCOMP to zopfli-optimize DEFLATE ----"
        advpng -z4 "$@"
    }
    
    optimize_png 16.png 32.png
    
    python3 << EOF
    from PIL import Image
    
    i16 = Image.open('16.png')
    i32 = Image.open('32.png')
    i32.save('src/favicon.ico', sizes=[(16, 16), (32, 32)], append_images=[i16])
    EOF
    

    Just be aware that:

    1. pngcrush and advpng don't take -- as arguments, so you have to prefix ./ onto relative paths which might start with -.
    2. .save in PIL must be called on the largest image so, if you have a dynamic list of images, you probably want something like this:
    images.sort(key=lambda x: x.size)
    images[-1].save('favicon.ico', sizes=[x.size for x in images], append_images=images)