ImageMagick add text to image
Burn text into an image with ImageMagick. Positioning with -gravity and -annotate, readable drop shadows, choosing fonts, and fixing CJK text that renders as empty boxes.
Two operators draw text: -annotate and -draw. Use -annotate — it respects -gravity, which means you can position text relative to an edge without knowing the image dimensions.
A basic caption
magick input.jpg -gravity south -pointsize 48 -fill white \
-annotate +0+28 'Your caption here' output.jpg
With -gravity south, the offset +0+28 means 28 pixels inward from the bottom edge, horizontally centred. Change the gravity and the same offset is measured from a different edge.
Text that stays readable on any photo
White text disappears over a bright sky; black text disappears in shadow. Draw it twice — dark offset by a pixel, then the real colour on top:
magick input.jpg -gravity southeast -pointsize 42 \
-fill black -annotate +26+22 '© 2026 Your Name' \
-fill white -annotate +24+24 '© 2026 Your Name' output.jpg
Cheap, and far more robust than guessing a colour. The alternative is a translucent box behind the text:
magick input.jpg -gravity south -pointsize 36 \
-undercolor '#00000080' -fill white -annotate +0+24 'Caption' output.jpg
-undercolor takes 8-digit hex, so the last two characters are the alpha.
Choosing a font
magick -list font
That prints every font ImageMagick knows about. Pass one by family name, or give a full path to a font file:
magick input.jpg -font DejaVu-Sans-Bold -pointsize 48 \
-fill white -gravity center -annotate 0 'Hello' output.jpg
If the list is empty
You are missing the fontconfig delegate, or the machine has no fonts at all. This is extremely common in slim Docker images. Install some:
apt install fonts-dejavu-core
If text renders as empty boxes
The font has no glyphs for those characters. The default fonts cover Latin only, so Chinese, Japanese, Korean, Arabic and emoji all come out as boxes. Pass a font that covers them, by full path:
magick input.jpg \
-font /usr/share/fonts/truetype/noto/NotoSansCJK-Regular.ttc \
-pointsize 48 -fill white -gravity south -annotate +0+30 '你好世界' output.jpg
Sizing text relative to the image
A fixed -pointsize looks tiny on a 4000px photo and enormous on a thumbnail. Either compute it in your script, or let ImageMagick fit the text to a box:
magick input.jpg -gravity south -size 1000x120 \
-background none -fill white label:'Fitted caption' \
-composite output.jpg
label: chooses the largest point size that fits the given -size.
Create a text-only image
magick -background none -fill '#0d9488' -pointsize 96 \
label:'MagickCmd' output.png