Draw Lines, Shapes and Text on PPM Images with ppmdraw
ppmdraw turns a short script of drawing verbs into marks on a PPM image: rectangles, lines, circles, splines and text, all placed by coordinate. This guide builds a small script, runs it against an image, and checks the result without ever touching the original file. Allow about fifteen minutes if you already know where the annotation needs to go.
The route
Jump straight to the step you need, or tick off Done means at the end.
You need the netpbm package and a shell. This describes the installed Netpbm 11.5.2 command, whose manual page is dated 22 June 2005, so check your local manual if the release differs. Drawing itself needs no elevated privileges; reach for sudo only if the input or output directory is genuinely protected, never as a default.
1. Check the command and pick an output file
Confirm the executable is the one you expect before writing a script:
$ command -v ppmdraw
/usr/bin/ppmdraw
$ ppmdraw --version
ppmdraw: Using libnetpbm from Netpbm Version: Netpbm 11.5.2
ppmdraw reads one or more PPM images and writes the drawn images to standard output. Keep the source file intact and pick a new destination for the result.
Warning
Shell redirection with > truncates an existing destination before ppmdraw has succeeded. Never point it at the only copy of an image you care about.
2. Write a drawing script
Create a file named annotate.draw with commands separated by semicolons:
setcolor red;
filledrectangle 10 10 160 35;
setpos 20 60;
text_here 12 0 "Sample image";
line 0 0 319 239;
One idea makes the whole language click: coordinates are column first, then row. Column 0 is the left edge, row 0 is the top edge.
filledrectangletakes the upper-left column and row, then a width and a height.linetakes a starting column and row, then an ending column and row.setcoloraffects every drawing command that comes after it, and takes a Netpbm colour name. The default colour is white, so set it explicitly whenever the result needs to be repeatable.setposchanges the current position, without drawing anything itself.text_herestarts its baseline at the current position and moves that position afterwards. Its arguments are character height, baseline angle in degrees, and the text itself. Quoted text with spaces counts as one token.
Checkpoint
Read the script back before running it. A missing semicolon can join two commands into one, and a row or column outside the image is simply off-canvas: pixels drawn beyond the edge are discarded, not a cropping warning you will see.
3. Apply the script to a PPM
Run the script against an input image and redirect the result to a new file:
$ ppmdraw -scriptfile annotate.draw /path/to/input.ppm > annotated.ppm
A successful run is quiet and exits 0. Check the status immediately, then inspect what you got:
$ printf '%s\n' "$?"
0
$ file annotated.ppm
annotated.ppm: Netpbm image data, size 320 x 240, rawbits, pixmap
The exact wording from file can differ between systems. What matters is that the file exists, is non-empty and has the dimensions you expected. The output is a PPM image on standard output, so never mix progress text into that same redirection.
4. Use an inline script for a one-off change
For a quick, throwaway operation, pass the script directly with -script instead of writing a file:
$ ppmdraw -script='setcolor blue; line 0 0 319 239;' input.ppm > diagonal.ppm
The shell quoting keeps every semicolon inside the one argument. A script file is still easier to review and reuse, especially once it grows text, several colours or coordinates you will want to tweak later. Option names and values can be joined with an equals sign or given separately, and the manual allows the shortest unique abbreviation of an option; full names read better in anything you keep.
5. Understand which commands move the current position
Use absolute commands when the geometry is already known:
circle 160 120 40;
line 20 20 300 20;
circle takes a centre column, centre row and radius. spline3 takes six coordinates: a start point, a control point and an end point. Neither line nor spline3 changes the current position.
Use relative commands when several marks should chain off one another:
setpos 20 80;
line_here 40 0;
line_here 0 20;
line_here -40 0;
- Each
line_heredisplacement is rightward and downward from the current point, and it moves the current point to its own endpoint. - Negative values are allowed, though the resulting point may land outside the canvas.
- The initial current position is
(0,0). Text sits on the baseline, so set a useful position beforetext_hereor much of the lettering can end up above the visible image.
6. Diagnose failures without losing the original
If the command cannot open the image or script, check paths and permissions without changing anything:
$ ls -l /path/to/input.ppm annotate.draw
$ test -r /path/to/input.ppm && echo input-readable
input-readable
A parse error is usually a misspelled verb, a missing argument, an unmatched quote or a missing semicolon. Check the command against the documented verbs: setpos, setlinetype, setlineclip, setcolor, setfont, line, line_here, spline3, circle, filledrectangle, text and text_here. The two line-clip commands are not explained by the installed manual, so do not build a repeatable example around undocumented behaviour.
The input filename is optional. Leave it out and ppmdraw reads a PPM image from standard input instead:
$ ppmdraw -scriptfile annotate.draw < input.ppm > annotated.ppm
Do not also try -scriptfile=- in that form: a dash means standard input for the script, and the command cannot read both the script and the image from standard input at once. The installed release does support multi-image PPM streams, applying the same script to every image in the stream.
To undo the example, delete only the newly created output and keep the input and script:
$ rm annotated.ppm
Warning
That removal is irreversible. Confirm the path with pwd and ls -l first if you are working in a directory that holds images you actually care about.
Done means
- Confirmed the version.
ppmdrawreports the expected Netpbm installation. - Wrote an explicit script. Colours and coordinates are set deliberately, not left to defaults.
- Kept the source untouched. The original PPM was never the redirection target.
- Verified the output. The new file has a valid PPM header and the expected dimensions.
- Know your verbs. You can say which commands move the current position and which do not.