gm identify syntax get image width and height - graphicsmagick

I am trying to get the height and width of a jpeg image in the commandline.
I typed
gm identify img300.jpg
and get a long line that outputs JPEG 3264x2448+0+0 DirectClass 8-bit 1.8Mi 0.000u 0m:0.000002s
I looked in the manual for the gm command and it says I can get just the image dimensions with the -density option.
http://www.graphicsmagick.org/identify.html#ident-opti
So I tried
gm identify -density img300.jpg
[Option requires an arguement]
gm identify img300.jpg -density
[no such file or directory]
debian 9, latest graphicsmagick package is the environment.

You can get the width like this:
gm identify -format %w image.png
256
And the height like this:
gm identify -format %h image.png
80
If you want height in a variable:
h=$(gm identify -format %h image.png)
If you want both in variables in one go:
read w h < <(gm identify -format "%w %h" image.png )
echo $w, $h

Related

Need multiple -format info:-

I need resize image and clean exif data, but outputs exif data from source image big.jpg, and output transformed image sizes for small.jpg.
That not outputs exif data:
gm convert big.jpg -format "%w %h %[exif:DateTime]" -strip -resize "250x250>" -write small.jpg info:-
That not outputs transformed image sizes (small.jpg):
gm convert big.jpg -format "%w %h %[exif:DateTime]" -write info:- -strip -resize "250x250>" small.jpg
How to do it correctly?
Thank.
I have two solutions for you - one ugly one, and one very ugly one! :-)
The first extracts the EXIF data, writes it to stderr so it doesn't get passed through the pipe, then pipes the image (in internal MIFF => Magick Image File Format) into a second convert that does the resize and prints the resized sizes:
gm convert big.jpg -format "%[exif:DateTime]" -write info:/dev/fd/2 miff:- | gm convert miff:- -strip -resize "250x250>" -format "%w %h" -write info:- small.jpg
2017:04:06 09:12:02
250 107
The second method is maybe more efficient as it only loads the original image once and stores it in an MPR (Magick Persistent Register) between the two processing steps. The two steps are run inside a single GraphicsMagick batch process:
cat - <<EOF | gm batch -prompt off
convert big.jpg -write mpr:orig -format "%[exif:DateTime]" info:-
convert mpr:orig -strip -resize "250x250>" -format "%w %h" -write small.jpg info:-
EOF
Both of these contain "bashisms" so you would need to run them under bash.

How to colorize a black-transparent PNG icon with ImageMagick

How do I a colorize a black PNG image that has a transparent background using ImageMagick?
Use case:
You have several PNG images like this:
And I want to colorize them like this:
I want to use ImageMagick's convert command, allowing for scripting to process hundreds of icons at a time.
You can use one of the following commands:
$ convert input.png +level-colors "red", output.png
$ convert input.png +level-colors "rgb(255,0,0)", output.png
$ convert input.png +level-colors "#ff0000", output.png
Note that the , character is important here. On the left side of the , character we tell convert which color should replace black and on right side what color should replace white. Therefore nothing should be given after the , character.
Source
... how do I colorize black & transparent PNG images [...] to colorize them like this [...] using ImageMagick
The -fill <COLOR> option works fantastic for this purpose. You can replace "#1bbfc9" with a human-readable name (e.g. "red") or an HTML color code.
convert target-black.png -fill "#1bbfc9" -colorize 100 target-blue.png
... allowing to script and process hundreds of icons at a time
Using the find command, you can recurse hundreds.
Warning: This will replace the originals.
find path/to/files -iname '*.png' -exec convert "{}" -fill "#1bbfc9" -colorize 100 "{}" \;
With ImageMagick, you can process a whole folder of images at one time with mogrify rather than convert if you want all the same color. Create a new output directory to hold the colorized files. Then cd to the folder holding your images.
cd path_to/image_folder
mogrify -format png -path path_to/new_folder -fill "cyan" -colorize 100 *.png
Where replace path_to with your actual path.
You may use color names, hex colors or rgb(...) colors in the fill command, but enclose them in quotes on Linux/Mac OSX. Quotes are not needed for Windows, but should not cause any issues if double quotes.
See mogrify

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

Recipe for creating Windows ICO files with ImageMagick?

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

Convert ImageMagick’s output from scientific to decimal?

I have a small one-liner in terminal which is to write the pixel count of many JPEG files to a text file:
find . -name *.jpg -exec convert {} -format "%[fx:w*h]" info: \; > sizes.txt
It actually does, but some of the numbers are in scientific notation, like here:
949200
960000
1.098e+06
1.038e+06
1.1664e+06
1.0824e+06
831600
What is the most robust / elegant way to have the commands output just in decimal notation, like in the following lines?
949200
960000
109806
103806
1166406
1082406
831600
I was wondering if you would do this within the ImageMagick fx part or rather pipe the output to another command for conversion. Thanks!
According to http://www.imagemagick.org/script/escape.php
there is no obvious way to get other number formats with the %fx:
directive, so a command line solution is necessary.
Converting the w*h scientific notation output will lose you significant
digits, so better output w and h separately and multiply.
Using bc this would be:
find . -name '*.jpg' -exec convert {} -format "%w*%h" info: \; |bc
To have ImageMagick print numbers larger than one million without truncating them to exponential (scientific) notation, use the -precision n option. The default precision is 6. I suggest setting it to 12, which allows numbers up to 1e+12 (a 1 followed by twelve zeros).
$ convert xc: -precision 12 -format '%[fx:1000*1000]\n' info:-
1000000
$ convert xc: -precision 6 -format '%[fx:1000*1000]\n' info:-
1e+06
This modification to the shell command seems to work:
find . -name *.jpg -exec convert {} -format "%[fx:w*h]" info: \; | xargs printf "%0.0f\n" > sizes.txt
Adjust the formatting directives printf "%0.0f\n" to suit your needs.
Just for demonstration purposes (this works the same with find etc and .jpg files found on my system):
$ cat data.txt
949200
960000
1.098e+06
1.038e+06
1.1664e+06
1.0824e+06
831600
$ cat data.txt | xargs printf "%0.0f\n"
949200
960000
1098000
1038000
1166400
1082400
831600

Resources