Cheat sheet for Image Magick
Image Magick is a command line tool that allows manipulations and conversations of (mainly) image files. For scaling tasks (e.g. do the same over and over again), Image Magick and some shell programming can help alot to accelerate tasks. The following list contains some command that I have used in the past for my work especially when dealing with quiz data.
One liners to convert an image file
Shrink an image down to 30% of it's original size:
convert image.jpg -resize 30% image.jpg
When performing a conversion you may write out the result to a different format, in this case shrink the jpeg and save the shinked file as a png:
convert image.jpg -resize 30% image.png
Resize image to dimensions of 100x100 and keep aspect ratio:
convert image.jpg -resize 100x100 image.jpg
Shrink an image to maximum dimensions 100x100, the image will be resized only when it's larger (keep aspect ratio):
convert image.jpg -resize 100x100\> image.jpg
Resize image to a width of 100 pixels, height will be ajusted automatically to keep aspect ratio:
convert image.jpg -resize 100x image.jpg
Resize image to a height of 50 pixels, width will be adjusted automatically to keep aspect ratio:
convert image.jpg -resize x50 image.jpg
Resize image exactly to 100x100 pixels, aspect ratio is not preserved when the original image is not in a quadrat shape:
convert image.jpg -resize 100x100\! image.jpg
Rotate the image 90 degrees counter clockwise:
convert image.png -rotate 270 image.png
Turn image upside down (rotate image 180 degrees):
convert upside-down.png -rotate 180 rightside-up.png
Flip image at the X-axis:
convert upside-down.png -flip downside-up.png
Flip image at the Y-axis:
convert left-right.png -flop right-left.png
Manipulating color values
Switch colors (create a negative):
convert black-white.png -negate white-black.png
Get a grayscaled image:
convert image.jpg -monochrome image2.jpg
Create a 32x32 pixels transparent image:
convert -size 32x32 xc:transparent blank.png
Create a white image of 320x240 pixels:
convert -size 320x240 xc:white white.jpg
Make image lighter:
convert image.jpg -level 0%,100%,2.0 lighter.jpg
Set an color to transparent in the image (in this case the color white is set to transparent). Since jpg's don't have transparency the result must be stored as a png or gif. With the -fuzz argument you can control which similar colors of white - or whathever color you choose - will be taken into account and set these to
transparent as well.
$ convert image.jpg -fuzz 5% -transparent white image.png
Convert a CMYK image into an RGB image (color profiles are usually obtained a printer's shop):
convert cmyk.jpg -colorspace RGB rgb.jpg
convert -profile CMYKprofile.icc -profile RGBprofile.icc cmyk.jpg rgb.jpg
Crop and merge images
Crop image (new image size will be 120x200, the crop will be done with an offset of 20 pixels from the left side and 10 pixels from the top):
$ convert img.png -crop 120x200+20+10 +repage img_smaller.png
During online sessions with a shared screen and slides I somethimes take screenshots to "store" the slides. While the screenshot contains the entire screen, the slides can be easily extracted by cropping the image to contain the slide only. This can be done with the following command:
for i in Screenshot\ from\ 2024-05-09\ 10-*
do k="${i/Screenshot from /slide_}"
convert "$i" -crop 1056x624+720+393 +repage "$k"
done
In this example my screenshot had a dimension of 1920x1080, as you can see:
identify ~/Pictures/Screenshot\ from\ 2024-05-09\ 09-00-41.png
/home/canjanix/Pictures/Screenshot from 2024-05-09 09-00-41.png PNG 1920x1080 1920x1080+0+0 8-bit sRGB 374541B 0.000u 0:00.000
The slide had a dimension of 1056x624 and was rather on the right side of the sceeenshot (720 pixels from the left and 393 pixels from the top).
Merge two images (a smaller one at the left corner of the big one):
convert big.jpg small.jpg -composite result.jpg
Merge the smaller image at the top right corner:
convert big.jpg small.jpg -gravity NorthEast -composite result.jpg
Other gravity arguments are NorthWest, North, NorthEast, West, Center, East, SouthWest, South, SouthEast.
To add some spacing when the smaller image is embedded into the big one (20 pixels from the edge) use:
convert big.jpg small.jpg -gravity NorthEast -geometry +20+20 -composite result.jpg
Add a frame around an image:
convert -border 10x10 -bordercolor '#9A9B98' old.jpg new_with_frame.jpg
Note that this enlarges the image by 20 pixels on each side (because the border is added on top, left, bottom, and right). When you want to preserve the original size of the image and only need the frame at the edge of the image (overwriting some of the pixels at this edge), then use the following command:
convert -shave 10x10 -border 10x10 -bordercolor '#9A9B98' old.jpg new_with_frame.jpg
Here is a script that generates 15 png images. Each image has the size of 40x40, consists of a black circle with the curren
for i in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
do
convert -size 40x40 xc:none -fill white -stroke black -strokewidth 2 \
-draw "circle 20,20 20,2" -pointsize 25 -gravity center \
-fill black -annotate 0x0+0+2 "$i" \
-trim +repage -gamma 2.2 ${i}.png
done
EPS files
EPS files are vector graphics. To use them on the Internet you might want to convert it into a png, gif or jpeg. The following example, in my case I had a 180x180 eps Image, that was converted it into a 3500x3500 size jpeg. The density parameter is especially important for the target size of the image. If the density is too low, the resulting image will not be of the desired size but smaller. If the density is very high, the image might result in an enormous size.
convert -colorspace RGB -density 1600 image.eps image_3500px.jpg
In case you get an error message like the following when trying to convert an EPS file:
convert-im6.q16: attempt to perform an operation not allowed by the security policy `PS' @ error/constitute.c/IsCoderAuthorized/426.
convert-im6.q16: no images defined `image_3500px.jpg' @ error/convert.c/ConvertImageCommand/3229.
then you need to adapt the Image Magick policies in e.g. /etc/ImageMagick-6/policy.xml (the exact location of
the file depends on the Image Magick version and maybe the system that you use). From the error message
above we see that the Postscript policy (PS) needs to be adjusted. In the policy.xml I have the following
line:
<policy domain="coder" rights="none" pattern="PS" />
that should be changed to:
<policy domain="coder" rights="read|write" pattern="PS" />
These policies exist because EPS (as well as other files) might propose a vulnerability to your system.
I have tried the conversation also with a svg image, without geting any good results. However, inkscape seems to do a good job:
inkscape -z -e logo.png logo.svg
This will do a conversion. At the console you see something link this:
Background RRGGBBAA: ffffff00
Area 0:0:124,54:64,67 exported to 125 x 65 pixels (90 dpi)
Bitmap saved as: logo.png
To get a larger PNG image just do the export again and use multiples of with and height. So to get an PNG of the double size use:
inkscape -z -e logo.png -w 250 -h 130 logo.svg
The problem that I have had with the logo is that the console output also contained warnings like ** (inkscape:7101): WARNING **: attribute 'clip-path' given as CSS. That means the styling is not entirely done in the SVG itself but the SVG uses CSS style information from the website where it is embedded.
So far I did not find a solution that made the conversion be possible entirely on the command line.
The Image Magick Docu: https://www.imagemagick.org/script/convert.php
Resizing images: https://www.imagemagick.org/Usage/resize/
Resize image and keep orientation
The following script makes use of Image Magick. The script does a resize (acutally a shrink only) of the image to the given geometry. The purpose of this script is to keep the orientatin of the image. If you desire a size of 80x60, a vertical image of the size e.g. 666x913 is shrinked to 58x80.
If an image is already smaller that the desired size, it will not be modified, to avoid artefacts when upscaling the image.
#!/bin/bash
# Resize (shrink) image but keep orientation and aspect ratio
# Usage: ./resizeImage.sh WIDTHxHEIGH image output
# some error handling
if [ "$(which identify) " == " " ] || [ "$(which convert) " == " " ]; then
echo "Image Magick seems not to be installed"
exit 1
fi
if [ -z $1 ]; then
echo "No geometry given"
exit 2
fi
if [ -z $2 ] || [ ! -e $2 ]; then
echo "Input file not given or not accessible"
exit 3
fi
if [ -z $3 ]; then
echo "Output file not given"
exit 4
fi
# start here getting the geometry from the argument
read WIDTH HEIGHT <<<$(IFS="x"; echo $1)
if [ -z $WIDTH ] || [ $WIDTH -lt 1 ] || [ -z $HEIGHT ] || [ $HEIGHT -lt 1 ]; then
echo "invalid geometry"
exit 5
fi
# get information about input file and it's size
fileInfo=($(identify $2))
if [ $? -ne 0 ]; then
echo "Could not determine image size for file $2"
exit 6
fi
read SIZE_X SIZE_Y <<<$(IFS="x"; echo ${fileInfo[2]})
# do the resize depending on the orientation of the image
if [ $SIZE_X -gt $SIZE_Y ]; then
convert $2 -resize ${WIDTH}x${HEIGHT}\> $3
else
convert $2 -resize ${HEIGHT}x${WIDTH}\> $3
fi
if [ $? -ne 0 ]; then
echo "error converting image file"
exit 7
fi
exit 0
The script makes use of the identify command to get information about the image before actually converting it.
Create Sprites with Image Magick
Sprites were used in former times to display icons, when Fontawesome and the like didn't exist yet or were not commonly used. A sprite is a single image file that contains all the icons used by the application. When an icon should be displayed, the size of the element is defined as the icon size, the background is set as the sprite image and the offset that should be displayed is the position of the left upper corner of that icon within the sprite image. As a result from the whole sprite, this single icon is displayed only.
The advantage of using a sprite is that there is only one request for the whole image, no matter how many times the icons are used at the page. Ideally the sprite image is cached. This reduces download time and data. The disadvantage is that you need to create the sprite manually and also define the css classes accordingly.
This shell script should make the sprite creation a lot easier and also helps to create the required css. Image Magick is used to get the dimensions of the single images that are used, to compose the sprite image and place the parts at the correct position.
#!/bin/bash
#
# Create an sprite image from given image files.
# Usage: create_sprite.sh < options > < file list >
# An option can be set by --optionname value
# The following options can be set:
# --offsetx number of pixels from left where image
# is inserted, default 0
# --offsety number of pixels from top in each block
# where image is inserted, default 0
# --width total width of the sprite (should be larger
# than the width of the input files), default
# is max width of input files + offsetx
# --height the height of a block where one image
# is embedded vertically, default is maximum
# height of input files + offsety
# --output file name where to write the output,
# default is output.png in the working directory
# --background background color for the sprite image. By
# default this is transparent, whenever you
# set the output file to be jpg you should also
# set a different backgound color such as white.
# --cssfile write some css style information into this
# file, default empty - no css file is written
# --cssselect prefix for css selector that is used for each
# image in the sprite. By default this is "." so
# that the selector will be a class name (base name
# of input image without file extension).
# --cssimgpath path for backgound image that prepends the output
# file name
script=$0
offsetx=0
offsety=0
width=0
height=0
background=transparent
output='output.png'
cssfile=''
cssselect='.'
cssimgpath=''
files=()
# evaluate command line args
while (( "$#" ))
do
cmd="$1"
shift
if [[ "$cmd " == "--offsetx " || "$cmd " == "--offsety " || "$cmd " == "--width " || "$cmd " == "--height " ]]; then
if [ ${#} -gt 0 ]; then
C='eval "${cmd:2}=\$1"'
eval "$C"
shift
else
echo "error: $cmd needs numeric argument"
exit 1
fi
continue
elif [ "$cmd " == "--output " ]; then
if [ ${#} -gt 0 ]; then
output="$1"
shift
else
echo "error: --output needs file name where sprite image is written to"
exit 1
fi
continue
elif [ "$cmd " == "--background " ]; then
if [ ${#} -gt 0 ]; then
background="$1"
shift
else
echo "error: --background needs valid color that is used as background in sprite image"
exit 1
fi
continue
elif [ "$cmd " == "--cssfile " ]; then
if [ ${#} -gt 0 ]; then
cssfile="$1"
shift
else
echo "error: $cmd needs file name where css information is written to"
exit 1
fi
continue
elif [[ "$cmd " == "--cssselect " || "$cmd " == "--cssimgpath " ]]; then
if [ ${#} -gt 0 ]; then
C='eval "${cmd:2}=\$1"'
eval "$C"
shift
else
echo "error: $cmd needs valid string as an argument"
exit 1
fi
continue
elif [ "$cmd " == "--help " ]; then
usage=$(head -32 ${script} | tail -30 | tr -d '#')
printf "$usage" ${script}
echo
exit 0
elif [ -e $cmd ]; then
files[${#files[*]}]=$cmd
fi
done
# check if any input files (that exist) have been submitted
if [ "${#files} " == "0 " ]; then
echo "no input files specified"
exit 2
fi
# evaluate width and height from images when a desired width or height is not given
if [[ $height -eq 0 || $width -eq 0 ]]; then
fheight=0
fwidth=0
for ((i=0; i<${#files[*]}; i++)); do
format=$(identify ${files[$i]} | cut -d " " -f3)
if [ "$format " == " " ]; then
echo "image height of ${files[$i]} count not be estimated. Is this an image?"
exit 3
fi
# casting to int
cheight=$(( ${format##*x} + 0 ))
cwidth=$(( ${format%%x*} + 0 ))
if [ $cheight -gt $fheight ]; then
fheight=$cheight
fi
if [ $cwidth -gt $fwidth ]; then
fwidth=$cwidth
fi
done
if [ $height -eq 0 ]; then
if [ $fheight -eq 0 ]; then
echo "height was not submitted and could not be extracted from images"
exit 4
else
height=$(( ${fheight} + ${offsety} ))
fi
fi
if [ $width -eq 0 ]; then
if [ $fwidth -eq 0 ]; then
echo "width was not submitted and could not be extracted from images"
exit 4
else
width=$(( ${fwidth} + ${offsetx} ))
fi
fi
fi
# total height of image that will be composed
totalHeight=$(( $height * ${#files[*]} ))
# create the image
convert -size ${width}x${totalHeight} xc:${background} ${output}
# if a css file should be generated, create an empty css file
if [ "$cssfile " != " " ]; then
echo > $cssfile
outbasename=${output##*/}
fi
for ((i=0; i<${#files[*]}; i++)); do
# create a copy of the already composed sprite image and compose a new one from the
# given copy by inserting the current image into the composed sprite
mv $output ${output}.bk
offy=$(( ${offsety} + ($i * $height) ))
convert ${output}.bk ${files[$i]} -gravity NorthWest -geometry +${offsetx}+${offy} -composite $output
if [ $? -ne 0 ]; then
echo "an error occurred when executing convert on file ${files[$i]}"
exit 5
fi
rm ${output}.bk
# if the css file is written, do it
if [ "$cssfile " != " " ]; then
# get current image base name without path and also without extension
if [[ "${files[$i]}" == */* ]]; then
basename=${files[$i]##*/}
else
basename=${files[$i]}
fi
fileclass=${basename%%.*}
# get width and height of current image
format=$(identify ${files[$i]} | cut -d " " -f3)
# write the css information
echo "$cssselect$fileclass {" >> $cssfile
echo " background: url(\"${cssimgpath}${outbasename}\") no-repeat scroll -${offsetx}px -${offy}px;" >> $cssfile
echo " width: ${format%%x*}px;" >> $cssfile
echo " height: ${format##*x}px;" >> $cssfile
echo "}" >> $cssfile
fi
done
The documentation can be seen with --help.
Assuming that you have e.g. two small flag images representing the english and the dutch language, a typicall call might look like:
./create-sprite.sh --width 100 --height 40 \
--offsetx 10 --offsety 10 \
--output /var/www/sprite.png \
--cssfile /var/www/mystyle.css \
--cssimgpath /images/icons/ \
--cssselect .flag_ \
dutch_flag.jpg english_flag.jpg
- Arguments have no specific order. You can mix image names with optional switches.
- Each switch (identified by the leading --) will require a concrete value as the succeeding argument.
- Files that are provided at the command line but are not found at the given location will be skipped without further notice.
- if a file is not an image file (usually when image magick returns an error) an error message is shown and the processing will be stopped.
- Mandatory arguments are the input images only.
The above call would do:
- Create the sprite file at
/var/www/sprite.png. - Create the css file at
/var/www/mystyle.css. - The sprite.png will have the size 100x80.
- Each icon in the sprite is located in a block of 40 pixels height and embedded 10 pixels from the left and top inside the block.
- The single images have the sizes 44x13 dutch_flag.jpg and 51x13 english_flag.jpg (identified by Image Magick).
- The css contains the following content:
.flag_dutch_flag {
background: url("/imgages/icons/sprite.png") no-repeat scroll -10px -10px;
width: 44px;
height: 13px;
}
.flag_english_flag {
background: url("/imgages/icons/sprite.png") no-repeat scroll -10px -50px;
width: 51px;
height: 13px;
}
The resulting sprite image should be optimized with tools like png crush or similar programs.