skip to content

ImageMagick — Image Manipulation

Comprehensive ImageMagick 7 reference covering magick, identify, mogrify, composite, montage, format conversion, resize, crop, rotate, color adjustments, effects, drawing, text, PDF operations, policy.xml hardening, and batch processing.

27 min read 32 snippets deep dive

ImageMagick — Image Manipulation#

What it is#

ImageMagick is a free, open-source suite of command-line tools — maintained at imagemagick.org — for creating, editing, compositing, and converting raster and vector images across 200+ formats including JPEG, PNG, TIFF, WebP, HEIC, SVG, and PDF. It handles tasks ranging from a simple format conversion to complex multi-layer compositing and batch transformations that would otherwise require a GUI editor. Reach for ImageMagick when you need scriptable, server-side, or batch image processing; for interactive editing, a GUI tool like GIMP is more practical.

IM 6 vs IM 7: ImageMagick 7 uses a single magick binary as the unified entry point. IM 6 ships separate commands (convert, identify, mogrify, …). On IM 7 the legacy names are deprecated shims and are omitted in some 7.x packaging configs (Fedora/RHEL ImageMagick7, Alpine, several Docker images) — scripts that hard-code convert will fail with “command not found” on those systems. Always prefer magick <subcommand> for new work. The current series at the time of writing is 7.1.2-23 (May 2026); 7.2 has not been released. This guide uses IM 7 syntax with IM 6 equivalents noted.

Installation#

# macOS
brew install imagemagick

# Ubuntu / Debian
sudo apt install imagemagick

# Arch
sudo pacman -S imagemagick

# Fedora
sudo dnf install ImageMagick

# Verify
magick --version                   # IM 7
convert --version                  # IM 6

# Policy file (Ubuntu/Debian) — may need to allow PDF processing:
# Edit /etc/ImageMagick-6/policy.xml or /etc/ImageMagick-7/policy.xml
# Change <policy domain="coder" rights="none" pattern="PDF" />
# to     <policy domain="coder" rights="read|write" pattern="PDF" />

Output:

# magick --version
Version: ImageMagick 7.1.1-15 Q16-HDRI x86_64 21910 https://imagemagick.org
Copyright: (C) 1999 ImageMagick Studio LLC
License: https://imagemagick.org/script/license.php
Features: Cipher DPC HDRI OpenMP(4.5)
Delegates (built-in): bzlib fontconfig freetype heic jng jp2 jpeg lcms lqr lzma openexr png tiff webp xml zlib

# convert --version
Version: ImageMagick 6.9.12-98 Q16 x86_64 18115 https://legacy.imagemagick.org
Copyright: (C) 1999 ImageMagick Studio LLC

Configuration#

ImageMagick reads its XML configuration files at startup from a system-wide directory and an optional per-user override. The system path is /etc/ImageMagick-7/ (or /etc/ImageMagick-6/ on IM 6); the per-user override is ~/.config/ImageMagick/. Files in the user directory take precedence over the system ones with the same name, which lets you loosen or tighten settings without sudo.

# Locate the config files actually being used
magick -list configure | grep -E '^(CONFIGURE_PATH|SHARE_PATH)'
magick -debug Configure -list policy 2>&1 | grep Searching | head -10

# System-wide config directory (Linux/macOS Homebrew varies)
ls /etc/ImageMagick-7/
# colors.xml      english.xml      log.xml          policy.xml       type.xml
# delegates.xml   locale.xml       mime.xml         thresholds.xml   type-ghostscript.xml

# Per-user override (highest precedence) — create as needed
mkdir -p ~/.config/ImageMagick
cp /etc/ImageMagick-7/policy.xml ~/.config/ImageMagick/policy.xml

# Verify which policy file is loaded
magick -list policy | head -20

Output:

# magick -list policy | head -20
Path: /etc/ImageMagick-7/policy.xml
  Policy: Resource
    name: memory
    value: 256MiB
  Policy: Resource
    name: disk
    value: 1GiB
  Policy: Coder
    rights: None
    pattern: PDF
  Policy: Coder
    rights: None
    pattern: PS
FilePurpose
policy.xmlSecurity policy — coder/resource/path/module limits (most-edited file)
delegates.xmlExternal commands used to read/write formats (Ghostscript, librsvg, …)
colors.xmlNamed color aliases
type.xml / type-ghostscript.xmlFont search paths and aliases
thresholds.xmlDither and posterise threshold maps
log.xmlLog event filters and output format
mime.xmlMIME-type → format mapping
locale.xml, english.xmlMessage catalogues

policy.xml — security hardening#

policy.xml is the gatekeeper between user input and ImageMagick’s coder/delegate machinery. Each <policy> element scopes a rule to a domain (coder, delegate, module, filter, path, resource, cache) and either grants rights (read, write, read|write, none) or sets a value for a resource limit. The last matching rule wins, so put broad denies first and exceptions afterwards.

Starting with 7.1.1-16, the upstream tarball ships four pre-built templates you can select at build time with --with-security-policy={open,limited,secure,websafe}, or copy from config/ directly:

TemplateIntent
open (default)Permissive — assumes ImageMagick runs behind a firewall or in a container
limitedDisables high-risk coders (PS, PDF, MVG, MSL) and HTTP, keeps common formats
secureTight resource limits + most coders disabled; flip on only what you need
websafeRead/write restricted to GIF, JPEG, PNG, WebP; no filters or indirect reads
<!-- /etc/ImageMagick-7/policy.xml — hardened example for a web-facing service -->
<policymap>
  <!-- Resource ceilings: starve a malicious upload of memory/CPU -->
  <policy domain="resource" name="memory"   value="256MiB"/>
  <policy domain="resource" name="map"      value="512MiB"/>
  <policy domain="resource" name="width"    value="16KP"/>
  <policy domain="resource" name="height"   value="16KP"/>
  <policy domain="resource" name="area"     value="128MP"/>
  <policy domain="resource" name="disk"     value="1GiB"/>
  <policy domain="resource" name="time"     value="60"/>      <!-- seconds -->
  <policy domain="resource" name="thread"   value="2"/>
  <policy domain="resource" name="throttle" value="0"/>

  <!-- Coders: block scriptable / delegate-heavy formats -->
  <policy domain="coder" rights="none" pattern="PS"/>
  <policy domain="coder" rights="none" pattern="PS2"/>
  <policy domain="coder" rights="none" pattern="PS3"/>
  <policy domain="coder" rights="none" pattern="EPS"/>
  <policy domain="coder" rights="none" pattern="PDF"/>
  <policy domain="coder" rights="none" pattern="XPS"/>
  <policy domain="coder" rights="none" pattern="MSL"/>
  <policy domain="coder" rights="none" pattern="MVG"/>
  <policy domain="coder" rights="none" pattern="SVG"/>
  <policy domain="coder" rights="none" pattern="LABEL"/>

  <!-- Delegates: block shell-level external commands -->
  <policy domain="delegate" rights="none" pattern="HTTPS"/>
  <policy domain="delegate" rights="none" pattern="HTTP"/>
  <policy domain="delegate" rights="none" pattern="URL"/>
  <policy domain="delegate" rights="none" pattern="SHOW"/>
  <policy domain="delegate" rights="none" pattern="WIN"/>

  <!-- Paths: block stdin/stdout/fd pseudo-files and @-prefixed indirect reads -->
  <policy domain="path"   rights="none" pattern="@*"/>
  <policy domain="path"   rights="none" pattern="|*"/>
  <policy domain="path"   rights="none" pattern="-"/>
  <policy domain="path"   rights="none" pattern="fd:*"/>     <!-- IM 7.1.2 advisory, Feb 2026 -->

  <!-- Module: forbid loading user-provided coder modules -->
  <policy domain="module" rights="none" pattern="{PS,PDF,XPS}"/>
</policymap>

Feb 2026 advisory (GHSA-xwc6-v6g8-pw2h): The shipped secure template did not block fd: pseudo-filenames (e.g. fd:0, fd:1), letting an attacker read from stdin or write to stdout through coder paths. Add <policy domain="path" rights="none" pattern="fd:*"/> even if you start from policy-secure.xml.

# Re-enable PDF only (e.g. to rasterise trusted internal documents)
# Edit /etc/ImageMagick-7/policy.xml, change the PDF coder line to:
# <policy domain="coder" rights="read|write" pattern="PDF" />

# Confirm a coder is blocked
magick -list policy | grep -A1 PDF
# Coder
#   rights: None
#   pattern: PDF

# Validate the live policy against an external evaluator (Doyensec)
# Upload your policy.xml to https://imagemagick-secevaluator.doyensec.com/
# or run the open-source evaluator locally:
#   git clone https://github.com/doyensec/imagemagick-security-policy-evaluator
#   python3 imagemagick-security-policy-evaluator/evaluator.py /etc/ImageMagick-7/policy.xml

Output: (none — exits 0 on success)

delegates.xml — external commands#

delegates.xml defines the shell command lines ImageMagick uses to hand off formats it cannot decode natively — Ghostscript for PostScript/PDF, librsvg or Inkscape for SVG, dcraw for camera RAW, and so on. Override an entry (for example to swap rsvg-convert for inkscape) by copying the relevant <delegate> block into ~/.config/ImageMagick/delegates.xml and editing the command= attribute.

# List active delegates
magick -list delegate | head -20

# Find which external binary handles PDF
magick -list delegate | grep -A1 -i pdf

Output: (none — exits 0 on success)

Core commands (IM 7)#

IM 7IM 6 equivalentPurpose
magick input … outputconvertConvert / process images
magick identifyidentifyRead image metadata
magick mogrifymogrifyIn-place batch processing
magick compositecompositeOverlay images
magick montagemontageCreate contact sheets
magick comparecompareVisual diff between images
magick streamstreamStream raw pixels
magick importimportScreen capture (X11)

Identify — inspect images#

magick identify reads an image’s metadata — format, dimensions, color depth, colorspace, and profile information — without fully decoding pixel data. Use it to audit a batch of images or extract specific properties via format strings for scripting.

magick identify image.png              # format, size, depth
magick identify -verbose image.png     # full metadata dump
magick identify -ping image.png        # fast: dimensions only, no decode

# Specific properties
magick identify -format "%f: %wx%h %[colorspace]\n" *.jpg
magick identify -format "%i %m %wx%h %[fx:w*h]\n" *.png

# Multi-frame (GIF, TIFF, PDF)
magick identify animation.gif          # shows each frame
magick identify 'document.pdf[0]'      # first page only

# Useful format codes:
# %f filename   %m format    %w width    %h height
# %z depth      %r type      %b filesize  %n number of frames
# %[colorspace] colorspace   %[profile:icc] ICC profile
# %[fx:expr]    evaluated expression

# Check if image has transparency
magick identify -format "%[channels]\n" image.png

Output:

# magick identify image.png
image.png PNG 1920x1080 1920x1080+0+0 8-bit sRGB 2.34MB 0.000u 0:00.001

# magick identify -verbose image.png
Image: image.png
  Format: PNG (Portable Network Graphics)
  Mime type: image/png
  Class: DirectClass
  Geometry: 1920x1080+0+0
  Resolution: 72x72
  Print size: 26.6667x15
  Units: PixelsPerInch
  Colorspace: sRGB
  Type: TrueColor
  Depth: 8-bit
  Channel depth:
    Red: 8-bit
    Green: 8-bit
    Blue: 8-bit
  Filesize: 2.34MB
  Number pixels: 2073600


# magick identify -format "%f: %wx%h %[colorspace]\n" *.jpg
photo1.jpg: 4032x3024 sRGB
photo2.jpg: 3840x2160 sRGB
photo3.jpg: 1920x1080 sRGB

# magick identify -ping image.png
image.png PNG 1920x1080 1920x1080+0+0 8-bit sRGB 0.000u 0:00.000

# magick identify -format "%[channels]\n" image.png
rgba

Format conversion#

ImageMagick auto-detects the input format from the file header and writes the output format based on the output file’s extension, so a simple magick input.png output.jpg is all that’s needed for most conversions. For multi-page sources like PDFs and GIFs, each page or frame becomes a separate numbered output file unless you select specific pages with bracket notation.

# Basic: input format auto-detected from extension
magick input.png output.jpg
magick input.jpg output.png
magick input.png output.webp
magick input.tiff output.png
magick input.heic output.jpg         # HEIC → JPEG (macOS)
magick input.svg output.png          # SVG → PNG (needs librsvg or inkscape)

# Multi-page / animation
magick input.pdf output.png          # all pages → output-0.png, output-1.png …
magick 'input.pdf[0]' output.png     # first page only
magick 'input.pdf[0-2]' out.png      # pages 0, 1, 2
magick *.jpg animation.gif           # images → animated GIF
magick frame*.png -delay 10 animation.gif  # with frame delay (10/100s)

# Force format (regardless of extension)
magick -format PNG input.dat output.out

# Specify quality
magick input.png -quality 85 output.jpg     # JPEG/WebP quality (0-100)
magick input.png -quality 9  output.png     # PNG compression (0-9)

# Strip metadata (EXIF, profiles) — smaller file size
magick input.jpg -strip output.jpg

Output: (none — exits 0 on success)

Geometry syntax#

Many options accept a geometry string WxH+X+Y:

SyntaxMeaning
800x600Fit within 800×600, preserve aspect ratio
800x600!Exact 800×600, ignore aspect ratio
800x600>Only shrink if larger than 800×600
800x600<Only enlarge if smaller than 800×600
800x600^Fill 800×600, may crop
50%Scale to 50% of original
800xWidth 800, height proportional
x600Height 600, width proportional
+50+30Offset: 50px from left, 30px from top
800x600+10+20Resize and position

Resize & scale#

-resize resamples the image to a new size using a configurable filter (Lanczos by default), preserving the aspect ratio unless you append !. -thumbnail is faster for generating small previews because it skips some processing steps, while -scale and -sample do nearest-neighbor scaling with no filtering, which is ideal for pixel art or when speed matters more than quality.

# Fit within bounding box (preserves aspect ratio)
magick input.jpg -resize 800x600 output.jpg

# Exact size (distorts if aspect ratio differs)
magick input.jpg -resize 800x600! output.jpg

# Width only, height proportional
magick input.jpg -resize 800x output.jpg

# Height only, width proportional
magick input.jpg -resize x600 output.jpg

# Only shrink (never enlarge)
magick input.jpg -resize '1920x1080>' output.jpg

# Only enlarge (never shrink)
magick input.jpg -resize '800x600<' output.jpg

# Fill and crop to exact size
magick input.jpg -resize 800x600^ -gravity center -extent 800x600 output.jpg

# Scale (fast, no filtering — pixel art / thumbnails)
magick input.png -scale 200% output.png
magick input.png -scale 128x128 icon.png

# Sample (nearest-neighbor, fastest)
magick input.png -sample 50% output.png

# High-quality resize filters
magick input.jpg -filter Lanczos -resize 800x output.jpg
magick input.jpg -filter Mitchell -resize 800x output.jpg

# Percentage
magick input.jpg -resize 50% output.jpg
magick input.jpg -resize 150% output.jpg

# Pixel count limit
magick input.jpg -resize '2000000@' output.jpg  # max 2 megapixels

Output: (none — exits 0 on success)

Crop#

-crop WxH+X+Y extracts a rectangular region of width W and height H starting at pixel offset (X, Y) from the top-left corner. Combine with -gravity to anchor the crop to a named position (Center, SouthEast, etc.) instead of calculating absolute offsets, and always follow with +repage if you’re piping the result into further operations so the canvas offset is reset.

# Crop to WxH from offset X,Y
magick input.jpg -crop 400x300+50+100 output.jpg

# Crop centered (gravity + extent)
magick input.jpg -gravity center -crop 400x300+0+0 output.jpg

# Crop from corners
magick input.jpg -gravity NorthWest -crop 400x300+0+0 output.jpg  # top-left
magick input.jpg -gravity SouthEast -crop 400x300+0+0 output.jpg  # bottom-right
magick input.jpg -gravity North     -crop 400x0+0+0   output.jpg  # top strip

# Trim whitespace / border
magick input.png -trim output.png              # auto-trim edges
magick input.png -fuzz 10% -trim output.png   # with fuzz tolerance
magick input.png -trim +repage output.png     # trim + reset canvas

# Tile / split into tiles
magick input.jpg -crop 200x200 tiles_%d.jpg   # tiles at 200x200 grid

# Shave (remove N pixels from all edges)
magick input.jpg -shave 10x10 output.jpg      # remove 10px all sides

Output: (none — exits 0 on success)

Rotate & flip#

-rotate turns the image by an arbitrary angle, expanding the canvas to fit the rotated content and filling corners with the background color. -flip mirrors vertically (top-to-bottom) while -flop mirrors horizontally (left-to-right); -auto-orient reads the EXIF orientation tag and applies the correct rotation, which is the right first step when processing camera photos.

magick input.jpg -rotate 90  output.jpg       # 90° clockwise
magick input.jpg -rotate -90 output.jpg       # 90° counter-clockwise
magick input.jpg -rotate 180 output.jpg       # 180°
magick input.jpg -rotate 45  output.jpg       # 45° (canvas expands, corners filled)
magick input.jpg -rotate 45 -background black -flatten output.jpg  # black corners

magick input.jpg -flip   output.jpg           # flip vertically (top↔bottom)
magick input.jpg -flop   output.jpg           # flip horizontally (left↔right)
magick input.jpg -transpose  output.jpg       # transpose (flip along main diagonal)
magick input.jpg -transverse output.jpg       # transverse flip

# Auto-rotate from EXIF orientation
magick input.jpg -auto-orient output.jpg

Output: (none — exits 0 on success)

Color adjustments#

These options alter pixel values after the image is decoded, letting you correct exposure, shift white balance, or convert colorspace without touching the source file. -brightness-contrast is the simplest lever; -modulate gives independent control over lightness, saturation, and hue; -level and -normalize stretch or compress the tonal range.

# Brightness / contrast (-100 to +100)
magick input.jpg -brightness-contrast 10x20 output.jpg   # +10 brightness, +20 contrast

# Levels (black-point, gamma, white-point)
magick input.jpg -level 10%,90% output.jpg               # stretch levels
magick input.jpg -level 0%,100%,1.5 output.jpg           # gamma 1.5

# Normalize (auto-stretch levels to full range)
magick input.jpg -normalize output.jpg
magick input.jpg -auto-level output.jpg                   # per-channel normalize

# Gamma
magick input.jpg -gamma 1.5 output.jpg        # lighten
magick input.jpg -gamma 0.7 output.jpg        # darken

# Hue / saturation / lightness
magick input.jpg -modulate 100,150,100 output.jpg   # brightness,saturation,hue
# 100=no change, 150=50% more saturation
magick input.jpg -modulate 110,80,100 output.jpg    # slightly brighter, less saturated

# Colorize
magick input.jpg -colorize 10,0,0 output.jpg        # tint red
magick input.jpg -tint 80 output.jpg                # tint with fill color

# Grayscale
magick input.jpg -colorspace Gray output.jpg
magick input.jpg -colorspace Gray -type Grayscale output.jpg  # force gray type

# Sepia
magick input.jpg -sepia-tone 80% output.jpg

# Invert
magick input.jpg -negate output.jpg

# White balance / color correction
magick input.jpg -white-balance output.jpg

# Curves (via fx)
magick input.jpg -function Polynomial "0.5,0,0.5" output.jpg

Output: (none — exits 0 on success)

Filters & effects#

ImageMagick’s filter and effect options modify pixel neighborhoods rather than individual pixel values, producing blur, sharpening, noise, and artistic transformations. -blur 0xS and -gaussian-blur 0xS are controlled by their sigma value; -unsharp is the standard choice for sharpening because it avoids the halos that -sharpen can introduce at high strengths.

# Blur
magick input.jpg -blur 0x3 output.jpg           # Gaussian, sigma=3
magick input.jpg -blur 0x8 output.jpg           # stronger blur
magick input.jpg -gaussian-blur 0x5 output.jpg  # explicit Gaussian
magick input.jpg -radial-blur 20 output.jpg     # radial motion blur
magick input.jpg -motion-blur 0x10+45 output.jpg  # motion blur at 45°

# Sharpen
magick input.jpg -sharpen 0x1.5 output.jpg      # moderate sharpen
magick input.jpg -unsharp 0x1+1+0.05 output.jpg # unsharp mask (best quality)
# -unsharp radius x sigma + amount + threshold

# Noise
magick input.jpg +noise Gaussian output.jpg     # add Gaussian noise
magick input.jpg +noise Impulse output.jpg      # add salt-and-pepper noise
magick input.jpg -noise 3 output.jpg            # reduce noise (median filter)

# Edge detection
magick input.jpg -edge 1 output.jpg
magick input.jpg -emboss 0x1 output.jpg         # emboss effect
magick input.jpg -charcoal 1 output.jpg         # charcoal sketch

# Artistic
magick input.jpg -paint 3 output.jpg            # oil painting effect
magick input.jpg -sketch 0x20+120 output.jpg    # pencil sketch
magick input.jpg -swirl 90 output.jpg           # swirl distortion
magick input.jpg -wave 10x100 output.jpg        # wave distortion
magick input.jpg -implode 0.5 output.jpg        # implode
magick input.jpg -implode -1 output.jpg         # explode

# Vignette
magick input.jpg -vignette 0x20+5+5 output.jpg

# Pixelate (mosaic)
magick input.jpg -scale 5% -scale 2000% output.jpg  # pixelate trick

# Posterize
magick input.jpg -posterize 4 output.jpg        # reduce color levels

# Solarize
magick input.jpg -solarize 50% output.jpg

# Spread (random pixel displacement)
magick input.jpg -spread 5 output.jpg

Output: (none — exits 0 on success)

Drawing & shapes#

The -draw option accepts an MVG (Magick Vector Graphics) mini-language for placing geometric primitives — circles, rectangles, lines, polygons, and ellipses — directly onto an image or a freshly created canvas. Set -fill and -stroke before -draw to control interior and outline colors; use -strokewidth to adjust line thickness.

# Draw on existing image (no canvas needed)
magick input.jpg -fill red -draw "circle 100,100 100,150" output.jpg

# Rectangle
magick input.jpg -fill blue -draw "rectangle 10,10 200,100" output.jpg

# Line
magick input.jpg -stroke red -strokewidth 3 -draw "line 0,0 200,200" output.jpg

# Polygon
magick input.jpg -fill yellow -draw "polygon 100,10 150,80 50,80" output.jpg

# Ellipse (cx,cy rx,ry start_angle,end_angle)
magick input.jpg -fill none -stroke green -strokewidth 2 \
  -draw "ellipse 200,200 100,60 0,360" output.jpg

# Create a new canvas with shapes
magick -size 400x400 xc:white \
  -fill red   -draw "circle 200,200 200,300" \
  -fill blue  -draw "rectangle 50,50 150,150" \
  output.png

# Rounded rectangle
magick -size 300x200 xc:white \
  -fill skyblue -draw "roundrectangle 20,20 280,180 20,20" \
  output.png

Output: (none — exits 0 on success)

Text annotations#

-annotate renders text onto an image using the current font, point size, fill, and gravity settings; it’s the higher-level alternative to -draw "text …" because it supports rotation, gravity alignment, and offset placement in a single option. For watermarking or captioning, pair -gravity with -annotate to position text relative to an edge rather than computing absolute pixel coordinates.

# Add text to image
magick input.jpg -font Arial -pointsize 40 -fill white \
  -draw "text 20,50 'Hello World'" output.jpg

# With gravity
magick input.jpg -gravity South -font Arial -pointsize 36 \
  -fill white -annotate +0+20 "Caption" output.jpg

# With background box
magick input.jpg -gravity South \
  -background '#0008' -fill white -font Arial -pointsize 28 \
  -annotate +0+10 " My Caption " output.jpg

# Stroke (outline text)
magick input.jpg -gravity Center -font Arial -pointsize 60 \
  -stroke black -strokewidth 2 -fill white \
  -annotate 0 "WATERMARK" output.jpg

# Transparent watermark (no input image, just create)
magick -size 800x600 xc:white \
  -font Helvetica -pointsize 72 \
  -fill "rgba(128,128,128,0.5)" \
  -gravity center -annotate 30 "DRAFT" \
  watermark.png

# List available fonts
magick -list font | grep -i "Font:"

Output:

# magick -list font | grep -i "Font:"
  Font: Arial
  Font: Arial-Black
  Font: Arial-Bold
  Font: Arial-BoldItalic
  Font: Arial-Italic
  Font: Courier
  Font: Courier-Bold
  Font: Helvetica
  Font: Times-Roman

Composite — overlay images#

magick composite (or -composite in a pipeline) layers one image on top of another using a compositing operator such as Over, Multiply, Screen, or Dissolve. -gravity and -geometry control where the overlay lands; the compose mode determines how overlapping pixels are blended, from simple alpha-over to photoshop-style blend modes.

# Overlay logo on image
magick composite -gravity SouthEast logo.png input.jpg output.jpg

# With offset
magick composite -geometry +10+10 overlay.png background.jpg output.jpg

# With compose modes
magick composite -compose Multiply  overlay.png base.jpg output.jpg
magick composite -compose Screen    overlay.png base.jpg output.jpg
magick composite -compose Overlay   overlay.png base.jpg output.jpg
magick composite -compose Dissolve -dissolve 50 fg.png bg.jpg output.jpg

# Mask compositing
magick composite -compose CopyOpacity mask.png input.png output.png

# IM 7 equivalent
magick base.jpg overlay.png -gravity SouthEast -composite output.jpg
magick bg.jpg fg.png -geometry +10+10 -compose Screen -composite out.jpg

Output: (none — exits 0 on success)

Montage — contact sheets#

magick montage arranges multiple images into a grid (contact sheet), with each thumbnail scaled to fit the geometry you specify. -tile controls the column×row layout, -geometry sets the thumbnail size and inter-image spacing, and -label adds a filename or custom caption beneath each thumbnail.

# Simple grid from multiple images
magick montage *.jpg output.jpg

# Control tile layout
magick montage *.jpg -tile 4x3 -geometry 200x150+5+5 contact.jpg
# 4 columns, 3 rows, each thumb 200x150, 5px gap

# With labels
magick montage *.jpg -tile 4x -geometry 200x150+5+5 -label '%f' contact.jpg

# Custom background, font
magick montage *.jpg -tile 3x -geometry 300x200+10+10 \
  -background black -fill white -font Arial -pointsize 12 \
  -label '%t' contact.jpg

# Single strip
magick montage img1.jpg img2.jpg img3.jpg -tile x1 -geometry 200x150+2+0 strip.jpg

Output: (none — exits 0 on success)

Compare — visual diff#

magick compare produces a highlighted difference image showing where two images diverge, and can compute numeric quality metrics such as PSNR (signal-to-noise ratio), SSIM (structural similarity), AE (absolute error pixel count), and MSE. Use it to verify that a compression or resizing step has not introduced unacceptable quality loss.

magick compare image1.jpg image2.jpg diff.jpg     # highlight differences
magick compare -metric PSNR image1.jpg image2.jpg null:  # PSNR score
magick compare -metric SSIM image1.jpg image2.jpg null:  # SSIM score
magick compare -metric AE image1.jpg image2.jpg null:    # absolute error count
magick compare -metric MSE image1.jpg image2.jpg diff.png  # mean square error

Output:

# magick compare -metric PSNR image1.jpg image2.jpg null:
32.4156

# magick compare -metric SSIM image1.jpg image2.jpg null:
0.971842

# magick compare -metric AE image1.jpg image2.jpg null:
14823

Canvas & gradients#

xc:color creates a blank canvas filled with a single color, while gradient: and radial-gradient: generate smooth linear and radial color transitions between two colors. These pseudo-image sources are used as starting points for compositing, testing, or building backgrounds without needing a pre-existing image file.

# Solid color canvas
magick -size 800x600 xc:white output.png
magick -size 800x600 xc:#1a1a2e output.png
magick -size 800x600 xc:"rgba(0,0,0,0)" transparent.png  # transparent

# Gradients
magick -size 800x400 gradient:blue-red output.png         # horizontal blue→red
magick -size 800x400 gradient:"#ff0000-#0000ff" out.png
magick -size 400x400 radial-gradient:white-black out.png  # radial

# Plasma (random colorful)
magick -size 800x400 plasma: output.png
magick -size 800x400 plasma:red-blue output.png

# Pattern
magick -size 400x400 pattern:checkerboard output.png
magick -size 400x400 pattern:crosshatch output.png
magick -list pattern                                       # list patterns

Output:

# magick -list pattern
bricks
checkerboard
circles
crosshatch
crosshatch45
fishscales
gray0
gray100

Borders & frames#

-border WxH adds a solid-color margin of width W and height H around the image using the -bordercolor value. -frame creates a raised or sunken 3D-style frame using highlight and shadow edges, while -extent with -gravity center is the most flexible approach when you want to pad the canvas to a specific total size.

# Add solid border
magick input.jpg -border 10x10 -bordercolor black output.jpg
magick input.jpg -border 5x20 -bordercolor white output.jpg  # asymmetric

# Add padding (extend canvas)
magick input.jpg -gravity center -background white -extent 1000x800 output.jpg

# Frame
magick input.jpg -frame 5x5+2+2 output.jpg      # raised frame effect

# Shadow
magick input.png \( +clone -background black -shadow 80x3+5+5 \) \
  +swap -background white -layers merge +repage output.png

Output: (none — exits 0 on success)

Transparency & alpha#

PNG and WebP support an alpha channel; JPEG does not. -alpha set enables the alpha channel on an image that lacks one, while -transparent color makes pixels of a specific color fully transparent — useful for removing solid-color backgrounds. Use -flatten with a -background color to collapse transparency when converting to a format that doesn’t support it.

# Remove white background → transparent PNG
magick input.jpg -fuzz 5% -transparent white output.png

# Remove background with flood-fill
magick input.png -fuzz 10% -fill none -draw "color 0,0 floodfill" output.png

# Set overall opacity
magick input.png -alpha set -channel A -evaluate set 50% output.png

# Add alpha channel
magick input.jpg -alpha set output.png

# Remove alpha channel (flatten to white background)
magick input.png -background white -flatten output.jpg

# Mask transparency
magick input.png mask.png -compose CopyOpacity -composite output.png

Output: (none — exits 0 on success)

PDF operations#

ImageMagick rasterizes PDFs via Ghostscript, so it must be installed separately and the system’s ImageMagick policy file must allow PDF access. -density sets the DPI at which the PDF is rendered before any other operations — 150 DPI is adequate for screen use and 300 DPI for print-quality output.

# PDF → PNG (one file per page)
magick -density 150 document.pdf page.png      # 150 DPI → page-0.png, page-1.png
magick -density 300 document.pdf -quality 90 page.jpg  # 300 DPI JPEG

# Specific pages
magick -density 150 'document.pdf[0]' page1.png
magick -density 150 'document.pdf[0-4]' pages.png

# PNG → PDF
magick image.png output.pdf
magick *.png -compress jpeg -quality 85 output.pdf  # multiple images → PDF

# Multi-image PDF
magick page1.jpg page2.jpg page3.jpg -compress Zip output.pdf

# Reduce PDF size (rasterize at lower DPI)
magick -density 150 -compress jpeg -quality 70 input.pdf compressed.pdf

# PDF info
magick identify -verbose 'document.pdf[0]' | grep -E "Geometry|Resolution|Type"

Output:

# magick identify -verbose 'document.pdf[0]' | grep -E "Geometry|Resolution|Type"
  Geometry: 1654x2339+0+0
  Resolution: 150x150
  Type: TrueColor

mogrify — in-place batch processing#

mogrify modifies files in place. Always work on a copy or use --path to redirect output.

# Resize all JPEGs in-place
magick mogrify -resize 1280x720 *.jpg

# Convert all PNGs to JPEG (creates new .jpg files alongside originals)
magick mogrify -format jpg *.png

# Output to a different directory (preserve originals)
mkdir -p resized
magick mogrify -resize 800x -path ./resized/ *.jpg

# Batch: convert, resize, quality
magick mogrify -resize 1920x1080\> -quality 85 -format jpg -path ./web/ *.png

# Strip EXIF from all JPEGs
magick mogrify -strip *.jpg

# Auto-orient all images (fix EXIF rotation)
magick mogrify -auto-orient *.jpg

# Sharpen all images
magick mogrify -unsharp 0x1+0.5+0.05 *.jpg

# Add watermark text to all images
magick mogrify -gravity SouthEast -fill "rgba(255,255,255,0.6)" \
  -font Arial -pointsize 20 -annotate +10+10 "© 2026" *.jpg

# Convert all HEIC to JPEG
magick mogrify -format jpg -path ./converted/ *.HEIC

Output: (none — exits 0 on success)

Append — combine images#

-append stacks images vertically (top to bottom) and +append concatenates them horizontally (left to right), scaling or aligning as needed. This is simpler than using montage or composite when you just want to tile a fixed set of images into a single strip without specifying geometry.

# Stack vertically
magick -append top.jpg bottom.jpg stacked.jpg

# Concatenate horizontally
magick +append left.jpg right.jpg side-by-side.jpg

# Multiple images
magick +append img1.jpg img2.jpg img3.jpg strip.jpg
magick -append img1.jpg img2.jpg img3.jpg column.jpg

Output: (none — exits 0 on success)

Common recipes#

# Create thumbnail with exact 200x200 square crop
magick input.jpg -thumbnail 200x200^ -gravity center -extent 200x200 thumb.jpg

# Convert HEIC photos to JPEG (macOS)
for f in *.heic *.HEIC; do
  magick "$f" -quality 85 "${f%.*}.jpg"
done

# Resize images, only shrink (never upscale), preserve folder
find photos/ -name "*.jpg" | while read f; do
  magick "$f" -resize '2048x2048>' -quality 85 "$f"
done

# Add white border + drop shadow
magick input.jpg \
  -bordercolor white -border 15 \
  \( +clone -background gray50 -shadow 60x4+4+4 \) \
  +swap -background white -layers merge output.png

# Create favicon set from source image
magick icon.png -resize 16x16  favicon-16.png
magick icon.png -resize 32x32  favicon-32.png
magick icon.png -resize 48x48  favicon-48.png
magick favicon-16.png favicon-32.png favicon-48.png favicon.ico

# Optimise JPEG for web (resize + strip + 85% quality)
magick input.jpg -resize '1920x1080>' -strip -quality 85 -interlace Plane output.jpg

# Progressive JPEG
magick input.jpg -interlace Plane output.jpg

# Convert image sequence to GIF with loop
magick -delay 8 -loop 0 frames/*.png animation.gif

# Optimize GIF
magick animation.gif -layers optimize optimized.gif
magick animation.gif -coalesce -layers Optimize out.gif

# Posterize + grayscale (stylized look)
magick input.jpg -colorspace Gray -posterize 6 output.jpg

# Blur background (fake tilt-shift)
magick input.jpg \
  \( +clone -blur 0x8 \) \
  -compose src-over \
  \( -size "%[fx:w]x%[fx:h]" gradient:white-black \) \
  -composite output.jpg

# Remove image background to PNG (white background removal)
magick input.jpg -fuzz 15% -transparent white output.png

# Stack images side by side with a separator line
magick +append left.jpg \( -size 4x%[left.jpg height] xc:gray \) right.jpg result.jpg

# Spritesheet: combine icons into one image
magick +append icon*.png spritesheet.png

# Compare two images, output highlighted diff
magick compare -highlight-color red -lowlight-color white img1.jpg img2.jpg diff.jpg

# Batch rename + convert with sequential numbering
i=1
for f in *.jpg; do
  magick "$f" -resize 800x "output_$(printf '%03d' $i).jpg"
  i=$((i+1))
done

Output: (none — exits 0 on success)

Useful options reference#

OptionDescription
-resize WxHResize preserving aspect ratio
-crop WxH+X+YCrop region
-rotate degRotate (expands canvas)
-flip / -flopVertical / horizontal mirror
-quality NJPEG/WebP quality 0–100
-stripRemove EXIF/profiles
-auto-orientFix orientation from EXIF
-gravity dirAnchor point (NW, N, NE, W, Center, E, SW, S, SE)
-extent WxHResize canvas (pad or crop)
-background colorFill color for new canvas area
-fill colorFill color for drawing
-stroke colorStroke color
-strokewidth NStroke width
-font nameFont for text
-pointsize NFont size
-annotate deg textDraw rotated text
-blur RxSGaussian blur (radius × sigma)
-sharpen RxSSharpen
-unsharp RxS+A+TUnsharp mask
-colorspace GrayConvert to grayscale
-normalizeStretch contrast to full range
-level B,W,GSet black/white point + gamma
-modulate B,S,HAdjust brightness/saturation/hue
-negateInvert image
-alpha setEnable alpha channel
-flattenFlatten layers onto background
-layers optimizeOptimize GIF layers
-density NDPI for PDF/PS input
-compress typeOutput compression
-interlace PlaneProgressive JPEG
-define jpeg:size=Hint for faster JPEG decode
-thumbnail WxHFast resize for thumbnails
-fuzz N%Color matching tolerance
-trimRemove border/whitespace
+repageReset canvas offset after trim/crop

Alternatives#

ImageMagick is the most format-complete and feature-rich image toolkit available, but it is not the fastest and not always the safest default for high-throughput web pipelines. The main 2026-relevant alternatives are libvips (and its bindings) for raw throughput, Sharp for Node.js, Pillow / Pillow-SIMD for Python scripting, and ffmpeg for video frames and some image batch work. Reach for ImageMagick when you need its breadth (200+ formats, MVG drawing, montage, compare, IM scripts); reach for libvips/Sharp when you are resizing or recompressing millions of photos.

ToolStrengthsTrade-offsBest for
ImageMagick200+ formats, scriptable MVG, drawing, montage, compare, broad effects libraryHighest memory/CPU per op; default policy.xml may need hardeningFormat conversion variety, complex compositing, scripting, one-offs
libvips (vips CLI)Demand-driven streaming pipeline — ~4–8× faster than IM on resize, low memorySmaller format set, terser CLI, less drawing capabilityBulk resize, thumbnail farms, ETL of image collections
Sharp (Node.js → libvips)Easiest libvips API, async, ~40–50× faster than Jimp, ~6M weekly npm downloadsNode-only; format set limited to libvips delegatesServer-side image APIs, build pipelines, Next.js / Astro asset transforms
Pillow / Pillow-SIMDPure Python API, ubiquitous in data-science stacksSlower than libvips; threading limited by GILNotebook work, ML preprocessing, ad-hoc Python scripts
GraphicsMagickIM 5 fork — faster on some ops, lower memory, narrower feature setLags IM on modern formats (HEIC, AVIF) and security fixesLegacy IM 5–era scripts, embedded/resource-tight servers
ffmpegExcellent video → frame extraction, can do basic resize/cropAwkward for non-video stills, no MVG/drawingVideo screenshots, animated GIF/WebP encoding, cross-format batch
VIPS Python (pyvips)libvips speed from PythonDifferent mental model (lazy pipeline) than PillowPython services that outgrow Pillow performance
# Quick libvips equivalent for the most common ImageMagick op (resize-and-strip)
vips thumbnail input.jpg output.jpg 800 --strip
# vs
magick input.jpg -resize 800x -strip output.jpg

# Sharp (Node.js) — async, libvips under the hood
node -e "
const sharp = require('sharp');
sharp('input.jpg').resize(800).toFile('output.jpg');
"

Output: (none — exits 0 on success)

Picking a default in 2026: for a new web service that resizes user uploads, start with Sharp (Node) or pyvips (Python) and keep magick available for the long-tail formats they don’t handle. For a workstation or a server doing diverse one-off jobs, ImageMagick is still the right default — just install with a hardened policy.xml and prefer the magick binary.

Sources#