32

I would like to create .ico icon for my Windows application dynamically (from the SVG file) by using ImageMagick. How do I do that?

Microsoft lists various color depth and size requirements for the icon. ImageMagick has the -depth and -colors options, but I'm not sure how to use them correctly in this case.

Additionaly, it looks like Vista+ supports 256x256 hi-res icon embedded into the very same .ico which can (should? must?) be a compressed PNG. How do I "join" the Windows XP icons and this new Vista icon into a single .ico file?

Tobias Kienzler
  • 25,759
  • 22
  • 127
  • 221
Linas Valiukas
  • 1,316
  • 1
  • 13
  • 23

10 Answers10

35

ImageMagick has a recipe for this in their documentation, see FavIcon Web Page Link Thumbnail

Essentially you run the following:

convert image.png  -bordercolor white -border 0 \
          \( -clone 0 -resize 16x16 \) \
          \( -clone 0 -resize 32x32 \) \
          \( -clone 0 -resize 48x48 \) \
          \( -clone 0 -resize 64x64 \) \
          -delete 0 -alpha off -colors 256 favicon.ico

You can modify this to include larger resolutions as necessary and to change things like border, transparency settings etc.

RobV
  • 28,022
  • 11
  • 77
  • 119
  • 5
    In fact you should be able to omit `-bordercolor white -border 0` if you use `-alpha remove` instead of `-alpha off`. – sschuberth Mar 26 '13 at 12:47
  • 2
    Except the author wants to do this with an SVG. As pointed out in my answer using this command on an SVG will totally destroy the quality of the resulting icon as imagemagick only resizes the SVG after rasterizing. – Malcolm MacLeod Apr 02 '13 at 05:58
  • @MalcolmMacLeod Yes you are quite right, converting direct from SVG using this method gives awful results – RobV Apr 02 '13 at 18:57
  • 4
    to convert from SVG I wonder if you can "convert to a large image" first (like png), or possibly use the density and resize oversampling trick: http://www.imagemagick.org/discourse-server/viewtopic.php?f=1&t=13585 – rogerdpack Jun 20 '13 at 20:04
10

It doesn't seem like ImageMagick alone can do this as it does not handle SVG resizing in a sane way (but instead resizes the SVG only after rasterizing which produces a horrid result)

By using inkscape to do the conversion it appears to be possible though, e.g. The following one liner should give you a usable icon with all icon sizes:

mkdir temp; declare -a res=(16 24 32 48 64 128 256); for f in *.svg; do for r in "${res[@]}"; do inkscape -z -e temp/${f}${r}.png -w $r -h $r $f; done; resm=( "${res[@]/#/temp/$f}" ); resm=( "${resm[@]/%/.png}" ); convert "${resm[@]}" ${f%%.*}.ico; done; rm -rf temp;

The above will not however give you 8 and 4 bit icons within the file (I think these are only needed for older windows versions that are no longer supported) It should be possible with a bit more work to have it do these if you need them.

Malcolm MacLeod
  • 624
  • 7
  • 15
  • 1
    Can this work with 512 px resolution? I've seen elsewhere that ImageMagick doesn't allow for 512 ico sizes. I'm making icons that are going to go on a large 4k screen so I think it's smart to have a 512 resolution just in case. – Aslan French Aug 20 '18 at 22:27
  • @DavidA.French As far as I know yes (several of the modified answers based on mine above also contain a 512px ico); However its probably best to just give it a try and see? – Malcolm MacLeod Sep 04 '18 at 08:39
  • It appears the mac solution relies on tiff2ico and the windows one while setting a 512 size does not actual produce a 512 icon. Anyway thanks for the help! – Aslan French Sep 05 '18 at 20:48
  • 1
    @DavidA.French [ImageMagick doesn't even work with 256x256 icon files](https://github.com/ImageMagick/ImageMagick/issues/1577). I tried and a lot of output files are broken – phuclv Oct 28 '19 at 07:44
  • 1
    ImageMagick can be used instead of inkscape, however you need to use it in a specific way to get the same quality as with inkscape (details are in my [answer](https://stackoverflow.com/questions/11423711/recipe-for-creating-windows-ico-files-with-imagemagick/69487280#69487280)). @phuclv, ImageMagick indeed has issue with 256x256 icons, but there is a workaround for that. Please look at my [answer](https://stackoverflow.com/questions/11423711/recipe-for-creating-windows-ico-files-with-imagemagick/69487280#69487280) for more details – PolarBear Oct 07 '21 at 20:42
  • @PolarBear Interesting thanks, not sure if this worked back when I wrote my answer or not, I don't recall anymore. My recollection is that any kind of SVG downsize imagemagick was creating a large raster image and then downscaling that but perhaps I miss some details. If it works as you describe now then it s a better solution as it avoids needing an extra program to do the job. – Malcolm MacLeod Oct 12 '21 at 06:52
  • @DavidA.French .ico files support only 256 px icons MAX. Only 1 byte is allocated for the image size in ICONDIRENTRY structure of the .ico file! – ScienceDiscoverer Jun 22 '22 at 07:12
10
magick convert in.jpg -define icon:auto-resize=16,48,256 -compress zip out.ico

http://imagemagick.org/script/command-line-options.php#define

icc97
  • 11,395
  • 8
  • 76
  • 90
  • 2
    I would add the 32 and 64 to the size list as well - then I think this is perfect for all Windows OS:s – Jouni Aro Apr 06 '16 at 10:15
  • 1
    I didn't notice any difference with or without '-compress zip', though – Jouni Aro Apr 06 '16 at 10:18
  • “convert.im6: width or height exceeds limit” — fixed by first resizing the input image to be 256 × 256 pixels. But the transparent parts in the original pngs turned white. – Smylers Mar 31 '17 at 14:25
9

I cleaned up Malcolm's solution, fixed a bug, and also made the script output tiffs so you can run tiff2icns in osx.

#! /bin/bash
# converts the passed-in svgs to tiff and ico

if [[ $# -eq 0 ]]; then
    echo "Usage: $0 svg1 [svg2 [...]]"
    exit 0
fi

temp=$(mktemp -d)
declare -a res=(16 24 32 48 64 128 256 512)
for f in $*; do
    mkdir -p $temp/$(dirname $f)
    for r in "${res[@]}"; do
        inkscape -z -e $temp/${f}${r}.png -w $r -h $r $f
    done
    resm=( "${res[@]/#/$temp/$f}" )
    resm=( "${resm[@]/%/.png}" )
    for filetype in ico tiff; do
        convert "${resm[@]}" ${f%%.*}.$filetype
    done
done
rm -rf $temp
Tobias Kienzler
  • 25,759
  • 22
  • 127
  • 221
hnasarat
  • 191
  • 1
  • 7
6

I have been struggling with the same problem. I have an SVG with the image of my icon and I need to create an icon.ico file from it. Let me describe the solutions I found:

Step 1: Determine what resolutions to include inside the icon.ico file.

There are no clear guidelines about that. Even Microsoft ships its software with inconsistent icon resolutions. There is a question about that. Therefore, I think the best we can do about it is to use IconsExtract from Nirsoft. With such tool, you can check the resolutions included in icons of popular modern Windows programs.

Step 2: Create .png files for every resolution you want to include inside your icon.ico file.

Many answers suggest to use Inkscape, but you can do everything with ImageMagick in the following way (just in case, I checked that the resulted images are the same as if you used inkscape):

magick.exe convert -size 16x16 -background transparent -depth 8 MyIconImage.svg 16.png
...
magick.exe convert -size 256x256 -background transparent -depth 8 MyIconImage.svg 256.png

However, if you still want to use Inkscape, here's the command:

inkscape.exe MyIconImage.svg -w 16 -h 16 -o 16.png

Some answers also suggest using ImageMagick's icon:auto-resize command line argument to avoid creating separate PNG files for every resolution. I don't recommend using it because to get the best quality it is better to avoid resizing as it is less accurate than rendering SVG file into each resolution separately.

Step 3: Assemble your icon.ico file.

magick.exe convert 16.png 20.png 24.png 32.png 40.png 48.png 64.png 256.png -compress jpeg icon.ico

-compress jpeg is used as a workaround for a specific issue in ImageMagick, as described in the following comment.
You can see details about created icon.ico file using the following command:

magick.exe identify icon.ico

Powershell script "CreateIcoFromSvg.ps1"

Let me provide a powershell script which automates above-mentioned steps:

# You can download ImageMagick from: https://imagemagick.org/script/download.php
$imageMagick = "$PSScriptRoot/ImageMagick-7.1.0-portable-Q16-x64/magick.exe"

$svgIcon = "MySvgIcon.svg"
$iconResolutions = 16,20,24,32,40,48,64,256

# Create 16.png, ..., 256.png image files
$pngImages = @()
Foreach($r in $iconResolutions) {
    & $imageMagick convert -size "${r}x${r}" -background transparent -depth 8 $svgIcon "${r}.png"
    $pngImages += "${r}.png"
}

# Combine all PNG image files into an icon.ico file
& $imageMagick convert $pngImages -compress jpeg "icon.ico"

# Remove PNG files
Foreach($image in $pngImages) {
    Remove-Item $image
}
PolarBear
  • 1,117
  • 15
  • 24
  • Thank you for taking the time to also include the PS script. The only thing missing is that there is no antialiasing and the sizing is, therefore, too rough. –  Jun 08 '22 at 20:55
4

Here's the standard recipe from the FAQ, modified to have all the resolutions mentioned in the msdn link (except those under "Additional sizes...") (the other answer didn't have all resolutions desired)

 convert input.png -bordercolor white -border 0 ( -clone 0 -resize 16x16 ) ( -clone 0 -resize 24x24 ) ( -clone 0 -resize 32x32 ) ( -clone 0 -resize 40x40 ) ( -clone 0 -resize 48x48 ) ( -clone 0 -resize 64x64 ) ( -clone 0 -resize 256x256 ) -delete 0 -alpha off -colors 256 output.ico
rogerdpack
  • 62,887
  • 36
  • 269
  • 388
3

Update in 2022

I recently realized that using by using convert you actually can't solve this task because convert turns all the input images into bmps and change the color depth of the images.

I have thus updated my script to use icotool (sudo apt install icoutils):

#!/bin/bash

for size in 16 24 32 48 64 96 128 256; do
    inkscape --export-filename $size.png -w $size -h $size logo.svg >/dev/null 2>/dev/null
done

for size in 16 24 32 48; do

  convert -colors 256 +dither $size.png png8:$size-8.png
  convert -colors 16  +dither $size-8.png $size-4.png

done

convert 16.png 24.png 32.png 48.png 16-8.png 24-8.png 32-8.png 48-8.png 16-4.png 24-4.png 32-4.png 48-4.png 64.png 96.png 128.png 256.png logo.ico

icotool -c -o logo.ico 16.png 24.png 32.png 48.png 16-8.png 24-8.png 32-8.png 48-8.png 16-4.png 24-4.png 32-4.png 48-4.png 64.png 96.png -r 128.png -r 256.png

rm 16.png 24.png 32.png 48.png 16-8.png 24-8.png 32-8.png 48-8.png 16-4.png 24-4.png 32-4.png 48-4.png 64.png 96.png 128.png 256.png

Original Answer

Building on all previous answers and correcting the following mistakes:

  • Don't use -color=256, as you need 32-bit color versions for all sizes with modern Windows versions (Vista+)
  • Necessary sizes in Windows are 16, 24, 32, 48, 64, 128, 256. Most scripts forgot those. I am unsure if 96 is really needed, but it doesn't hurt.
  • You need to include 4-bit and 8-bit palette versions for the sizes 16, 24, 32 and 48 (apparently to support Remote Desktop applications in particular)

All in one bash script (starting from logo.svg and producing logo.ico):

#!/bin/bash

for size in 16 24 32 48 64 96 128 256; do
    inkscape --export-filename $size.png -w $size -h $size logo.svg >/dev/null 2>/dev/null
done

for size in 16 24 32 48; do

  convert -colors 256 +dither $size.png png8:$size-8.png
  convert -colors 16  +dither $size-8.png $size-4.png

done

convert 16.png 24.png 32.png 48.png 16-8.png 24-8.png 32-8.png 48-8.png 16-4.png 24-4.png 32-4.png 48-4.png 64.png 96.png 128.png 256.png logo.ico

rm 16.png 24.png 32.png 48.png 16-8.png 24-8.png 32-8.png 48-8.png 16-4.png 24-4.png 32-4.png 48-4.png 64.png 96.png 128.png 256.png 
Christopher Oezbek
  • 23,994
  • 6
  • 61
  • 85
2

Bash one-liner to convert logo.svg into logo.ico, using Inkscape to export the png images at various sizes:

eval convert \
  '<(inkscape -e /dev/stderr logo.svg -w '{16,24,32,48,64,128,256}' 2>&1 > /dev/null)' \
  logo.ico

Inspired by Malcolm MacLeod's answer, but avoiding the explicit loop and the temporary files.

The stderr and redirection is to avoid Inkscape's success message on stdout (“Bitmap saved as: /dev/stdout”) ending up in the image data.

Christopher Oezbek
  • 23,994
  • 6
  • 61
  • 85
Smylers
  • 1,673
  • 14
  • 18
1

Modifying hnasarat's answer for windows users. The easiest way to is install InkScape and ImageMagick using Chocolatey and then run the following in a batch file. (It is not as flexible as the other answers you just pass in one svg but it pumps out all the favicons recommended in Favicon Cheat Sheet.

@ECHO off

IF "%1"=="" (
    ECHO You must provide an svg file
    EXIT /b
) 

IF NOT EXIST favicons MD favicons

SET "sizes=16 24 32 48 57 64 72 96 120 128 144 152 195 228 256 512"

FOR %%s IN (%sizes%) DO (
    inkscape -z -e favicons/favicon-%%s.png -w %%s -h %%s %1
)

convert favicons/favicon-16.png favicons/favicon-24.png favicons/favicon-32.png favicons/favicon-48.png favicons/favicon-64.png favicons/favicon.ico
Simon Woodhead
  • 561
  • 5
  • 9
0

To create an ICO file from a SVG while keeping aspect ratio:

  1. look for SVG proportions (eg. 1920x1080)
  2. for a max 256px wide icon, do the proportion: [1920:1080=256:x] -> x=(1080*256)/1920=144
  3. finally, use ImageMagick convert command:

    convert -background none -resize 256x144 -gravity center -extent 256x144 image.svg image.ico

Riccardo Volpe
  • 1,471
  • 1
  • 16
  • 30