Recipe for creating Windows ICO files with ImageMagick? - icons
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?
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.
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.
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
magick convert in.jpg -define icon:auto-resize=16,48,256 -compress zip out.ico
http://imagemagick.org/script/command-line-options.php#define
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
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 solution which I have 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 or similar to check what resolutions are included in icons of the most popular and modern Windows programs.
Step 2: Create .png files for every resolution you want to include inside your icon.ico file.
A lot of answers propose 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, that is the command:
inkscape.exe MyIconImage.svg -w 16 -h 16 -o 16.png
Also some answers propose to use 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 to workaround the following issue in ImageMagick as it is 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
}
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
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.
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
To create an ICO file from a SVG while keeping aspect ratio:
look for SVG proportions (eg. 1920x1080)
for a max 256px wide icon, do the proportion: [1920:1080=256:x] -> x=(1080*256)/1920=144
finally, use ImageMagick convert command:
convert -background none -resize 256x144 -gravity center -extent 256x144 image.svg image.ico
Related
Batch blur images using multiple cores
I'm trying to blur the bottom section of thousands (>50,000) of images using imagemagick. Image resolution is 800x600. The command line code (below) works, but takes a long time. Is there any way that this can be run in parallel, and hopefully called from within R using system()? I got this code off the internet, so I'm not sure if it's the best way to even achieve this objective? Any help would be greatly appreciated. Thanks in advance! (OS = OSX El Capitan) cd /Users/Desktop/test_images list=$(ls *.jpg) for img in $list; do convert $img \ \( -size 800x525 xc:black -size 800x75 xc:white -append \) \ -compose blur -define compose:args=6 -composite \ cd /Users/Desktop/test_images/results/$img done cd
I think this command does something very similar to what you are doing but is FAR quicker. See if you like the effect: convert start.jpg \( +clone -crop +0+525 -blur x4 \) -gravity south -composite result.jpg If that works, you can use GNU Parallel just as before: parallel 'convert {} \( +clone -crop +0+525 -blur x4 \) -gravity south -composite results/{}' ::: *.jpg You can also put that lot in a script called BlurTitle like this: #!/bin/bash parallel 'convert {} \( +clone -crop +0+525 -blur x4 \) -gravity south -composite results/{}' ::: *.jpg and then make it executable with: chmod +x BlurTitle and call it from R with: system("./BlurTitle") or from the Terminal with: ./BlurTitle If you get "Argument list too long", you can express it the other way around like this by sending the arguments on stdin rather than after the command: cd /path/to/images find . -name \*.jpg -print0 | parallel -0 'convert {} \( +clone -crop +0+525 -blur x4 \) -gravity south -composite results/{}'
image -> video -> image not lossless using avconv
I'm trying to test the amount of information lost with some different video codecs. I've got a python script which uses PyPNG to write a series of 8 bit RGB images. I then encode it using avconv, for instance avconv -r 1 -i ../frames/data%03d.png -c:v ffv1 -qscale:v 0 -r 1 outffv1.avi I then decode this back into pngs like so avconv -r 1 -i outffv1.avi -r 1 ./outffv1/frame%03d.png But when I compare the images before and after the video compression, they are different (mean absolute error of ~~15%). The thing that is confusing me is that this is true (give or take) independent of the codec. For instance, I get similar answers for libtheora for a range of qscale values. The png encoding i.e. write to png, and immediately load back in without and video compression step, is lossless. UPDATE - more precise worked example: Single input frame here: https://www.dropbox.com/s/2utk1xs2t8heai9/data001.png?dl=0 Encoded to video like this: avconv -r 1 -i ./frames/data%03d.png -c:v ffv1 -qscale:v 0 -r 1 outffv1.avi resultant video here: https://www.dropbox.com/s/g1babae2a41v914/outffv1.avi?dl=0 decoded to a png again here: https://www.dropbox.com/s/8i8zg1qn7dxsgat/out001.png?dl=0 using this command: avconv -r 1 -i outffv1.avi -qscale:v 31 -r 1 out%03d.png and image magick differenced like this compare out001.png ./frames/data001.png diff.png to give this (non-zero) diff https://www.dropbox.com/s/vpouk54p0dieqif/diff.png?dl=0
Your video file most likely uses the YUV color format. PNG uses RGB. The conversion of the color is not a lossless process.
In graphicsmagick, how can I specify the output file on a bulk of files?
I want to convert a group of files, but not overwrite the existing file. How can I use mogrify to specificy the final file format? For example, firstpic.png -> firstpic-thumbnail.png, secondpic.png -> secondpic-thumbnail.png, etc. gm mogrify -size 150x150 *.png -resize 150x150 +profile "*" "%f-thumbnail.png" Is there any way to do this?
I don't know if there's a way to specify output file format from mogrify but I would use convert with simple bash loop instead: for f in *.jpg; do convert "$f" -resize 150x150 +profile "*" "${f%.jpg}-thumbnail.jpg"; done; Or if you really want to use mogrify you can use -output-directory (more on this option here) to put new files into separate directory and then take care of renaming: mkdir tmp; gm mogrify -output-directory tmp -size 150x150 -resize 150x150 +profile "" "*.jpg"; for f in tmp/*.jpg; do mv "$f" "${f%.jpg}-thumbnail.jpg"; done; mv tmp/* .; rm -rf tmp; I like the first method better ;)
If the output format (extension) is different from the input format, the files won't get overwritten. If they are the same, you can use this trick, that makes them appear to be "different" for this purpose but are really the same but differ in the case of the extension: gm mogrify -resize 150x150 -format PNG +profile "*" *.png EDIT: I don't know of a facility within "mogrify" to rename the output files other than specifying a different directory or a different extension. So fragphace's answer is correct; you will need to use a script to rename them. In combination with my answer: gm mogrify -resize 150x150 -format PNG +profile "*" *.png for file in *.PNG do basename=`echo $file | sed -e "s/.PNG//"` mv $basename.PNG $basename-thumbnail.png done
How to colorize diff on the command line
When I have a diff, how can I colorize it so that it looks good? I want it for the command line, so please no GUI solutions.
Man pages for diff suggest no solution for colorization from within itself. Please consider using colordiff. It's a wrapper around diff that produces the same output as diff, except that it augments the output using colored syntax highlighting to increase readability: diff old new | colordiff or just: colordiff old new Installation: Ubuntu/Debian: sudo apt-get install colordiff OS X: brew install colordiff or port install colordiff
Use Vim: diff /path/to/a /path/to/b | vim -R - Or better still, VimDiff (or vim -d, which is shorter to type) will show differences between two, three or four files side-by-side. Examples: vim -d /path/to/[ab] vimdiff file1 file2 file3 file4
Actually there seems to be yet another option (which I only noticed recently, when running into the problem described above): git diff --no-index <file1> <file2> # output to console instead of opening a pager git --no-pager diff --no-index <file1> <file2> If you have Git around (which you already might be using anyway), then you will be able to use it for comparison, even if the files themselves are not under version control. If not enabled for you by default, then enabling color support here seems to be considerably easier than some of the previously mentioned workarounds.
diff --color option (added to GNU diffutils 3.4 in 2016-08-08) This is the default diff implementation on most distributions, which will soon be getting it. Ubuntu 18.04 (Bionic Beaver) has diffutils 3.6 and therefore has it. On 3.5 it looks like this: Tested with: diff --color -u \ <(seq 6 | sed 's/$/ a/') \ <(seq 8 | grep -Ev '^(2|3)$' | sed 's/$/ a/') Apparently added in commit c0fa19fe92da71404f809aafb5f51cfd99b1bee2 (Mar 2015). Word-level diff Like diff-highlight. It is not possible it seems, but there is a feature request: https://lists.gnu.org/archive/html/diffutils-devel/2017-01/msg00001.html Related questions: Using 'diff' (or anything else) to get character-level diff between text files https://unix.stackexchange.com/questions/11128/diff-within-a-line https://superuser.com/questions/496415/using-diff-on-a-long-one-line-file ydiff does it though. See below. ydiff side-by-side word level diff https://github.com/ymattw/ydiff Is this nirvana? python3 -m pip install --user ydiff diff -u a b | ydiff -s Outcome: If the lines are too narrow (default 80 columns), fit to the screen with: diff -u a b | ydiff -w 0 -s Contents of the test files: a 1 2 3 4 5 the original line the original line the original line the original line 6 7 8 9 10 11 12 13 14 15 the original line the original line the original line the original line 16 17 18 19 20 b 1 2 3 4 5 the original line the original line the original line the original line 6 7 8 9 10 11 12 13 14 15 the original line the original line the original line the original line 16 17 18 19 20 ydiff Git integration ydiff integrates with Git without any configuration required. From inside a Git repository, instead of git diff, you can do just: ydiff -s and instead of git log: ydiff -ls See also: How can I get a side-by-side diff when I do "git diff"? Tested on Ubuntu 16.04 (Xenial Xerus), Git 2.18.0, and ydiff 1.1.
And for those occasions when a yum install colordiff or an apt-get install colordiff is not an option due to some insane constraint beyond your immediate control, or you're just feeling crazy, you can reinvent the wheel with a line of sed: sed 's/^-/\x1b[41m-/;s/^+/\x1b[42m+/;s/^#/\x1b[34m#/;s/$/\x1b[0m/' Throw that in a shell script and pipe unified diff output through it. It makes hunk markers blue and highlights new/old filenames and added/removed lines in green and red background, respectively.1 And it will make trailing space2 changes more readily apparent than colordiff can. 1 Incidentally, the reason for highlighting the filenames the same as the modified lines is that to correctly differentiate between the filenames and the modified lines requires properly parsing the diff format, which is not something to tackle with a regex. Highlighting them the same works "well enough" visually and makes the problem trivial. That said, there are some interesting subtleties. 2 But not trailing tabs. Apparently tabs don't get their background set, at least in my xterm. It does make tab vs. space changes stand out a bit though.
Coloured, word-level diff ouput Here's what you can do with the the below script and diff-highlight: #!/bin/sh -eu # Use diff-highlight to show word-level differences diff -U3 --minimal "$#" | sed 's/^-/\x1b[1;31m-/;s/^+/\x1b[1;32m+/;s/^#/\x1b[1;34m#/;s/$/\x1b[0m/' | diff-highlight (Credit to #retracile's answer for the sed highlighting)
You can change the Subversion configuration to use colordiff: ~/.subversion/config.diff ### Set diff-cmd to the absolute path of your 'diff' program. ### This will override the compile-time default, which is to use ### Subversion's internal diff implementation. -# diff-cmd = diff_program (diff, gdiff, etc.) +diff-cmd = colordiff via: https://gist.github.com/westonruter/846524
I use grc (Generic Colouriser), which allows you to colour the output of a number of commands including diff. It is a Python script which can be wrapped around any command. So instead of invoking diff file1 file2, you would invoke grc diff file1 file2 to see colourised output. I have aliased diff to grc diff to make it easier.
Here is another solution that invokes sed to insert the appropriate ANSI escape sequences for colors to show the +, -, and # lines in red, green, and cyan, respectively. diff -u old new | sed "s/^-/$(tput setaf 1)&/; s/^+/$(tput setaf 2)&/; s/^#/$(tput setaf 6)&/; s/$/$(tput sgr0)/" Unlike the other solutions to this question, this solution does not spell out the ANSI escape sequences explicitly. Instead, it invokes the tput setaf and tput sgr0 commands to generate the ANSI escape sequences to set an appropriate color and reset terminal attributes, respectively. To see the available colors for each argument to tput setaf, use this command: for i in {0..255}; do tput setaf $i; printf %4d $i; done; tput sgr0; echo Here is how the output looks: Here is the evidence that the tput setaf and tput sgr0 commands generate the appropriate ANSI escape sequences: $ tput setaf 1 | xxd -g1 00000000: 1b 5b 33 31 6d .[31m $ tput setaf 2 | xxd -g1 00000000: 1b 5b 33 32 6d .[32m $ tput setaf 6 | xxd -g1 00000000: 1b 5b 33 36 6d .[36m $ tput sgr0 | xxd -g1 00000000: 1b 28 42 1b 5b 6d .(B.[m
Since wdiff accepts arguments specifying the string at the beginning and end of both insertions and deletions, you can use ANSI color sequences as those strings: wdiff -n -w $'\033[30;41m' -x $'\033[0m' -y $'\033[30;42m' -z $'\033[0m' file1 file2 For example, this is the output of comparing two CSV files: Example from 2.2 Actual examples of wdiff usage.
I would suggest you to give diff-so-fancy a try. I use it during my work and it sure seems great as of now. It comes packed with many options and it's really easy to configure your diffs the way you want. You can install it by: sudo npm install -g diff-so-fancy or on Mac: brew install diff-so-fancy Afterwards, you can highlight your diffs like this: diff -u file1 file2 | diff-so-fancy
Character-level color diff: Install ccdiff ccdiff -r /usr/share/dict/words /tmp/new-dict
No one has mentioned delta so far. It supports syntax colored diff view with syntax highlighting.
With the bat command: diff file1 file2 | bat -l diff
On recent versions of Git on Ubuntu, you can enable diff-highlighting with: sudo ln -s /usr/share/doc/git/contrib/diff-highlight/diff-highlight /usr/local/bin sudo chmod a+x /usr/share/doc/git/contrib/diff-highlight/diff-highlight And then adding this to your .gitconfig file: [pager] log = diff-highlight | less show = diff-highlight | less diff = diff-highlight | less It's possible the script is located somewhere else in other distributions. You can use locate diff-highlight to find out where.
My favorite choice is vdiff <file1> <file2> function (I forgot from where I got it). It will open two windows in Vim side-by-side, to see clearly see the difference between the two files. vdiff () { if [ "${#}" -ne 2 ] ; then echo "vdiff requires two arguments" echo " comparing dirs: vdiff dir_a dir_b" echo " comparing files: vdiff file_a file_b" return 1 fi local left="${1}" local right="${2}" if [ -d "${left}" ] && [ -d "${right}" ]; then vim +"DirDiff ${left} ${right}" else vim -d "${left}" "${right}" fi } Put this script in your (.alias) or (.zshrc), and then call it using vdiff <file1> <file2>. Example The results are:
diff --color=always file_a file_b | less works for me
For me I found some solutions: it is a working solution #echo off Title a game for YouTube explorer "https://thepythoncoding.blogspot.com/2020/11/how-to-echo-with-different-colors-in.html" SETLOCAL EnableDelayedExpansion for /F "tokens=1,2 delims=#" %%a in ('"prompt #$H#$E# & echo on & for %%b in (1) do rem"') do ( set "DEL=%%a" ) echo say the name of the colors, don't read call :ColorText 0a "blue" call :ColorText 0C "green" call :ColorText 0b "red" echo( call :ColorText 19 "yellow" call :ColorText 2F "black" call :ColorText 4e "white" goto :Beginoffile :ColorText echo off <nul set /p ".=%DEL%" > "%~2" findstr /v /a:%1 /R "^$" "%~2" nul del "%~2" > nul 2>&1 goto :eof :Beginoffile
ImageMagik/UNIX: How to recursively process a nested directory of photos?
Question: How do I recursively process, using Imagemagik (convert), a nested directory of photos? I have the following directory structure: / ..2008/ ....a.jpg ....b.jpg ..2009/ .....c.jpg And I want to run the following ImageMagik command on each file, to clean/resize up the images, and then save the resulting image out as the exact same filename as the original file. Basically, I want to replace the original file with the generated resized file created. // from unix command line convert FILENAME.jpg -resize 100x100 -sharpen 1.5 -strip -profile "*" -sampling-factor 4x1 -quality 80 FILENAME.jpg;
Try using find -exec. For instance: find dirname -type f -iname "*.jpg" -exec convert \{\} -resize 100x100 -sharpen 1.5 -strip -profile "*" -sampling-factor 4x1 -quality 80 \{\} \; By the way, I don't recommend in-place editing. It's generally a bad idea, especially with storage so cheap. Why not be safe?