Home / Alt manpages / ppmtoterm(1)

  • ppmtoterm(1)
  • User command
  • linux

Show a PPM Image in the Terminal with ppmtoterm

ppmtoterm turns a tiny PPM image into coloured blocks of text, right there in your terminal, no image viewer needed. It uses ANSI colour escape codes, one character per pixel, so the trick only works on a terminal that understands ISO 6429 colour control sequences. Allow about 10 minutes to render a test image and then a real one.

You need a shell, the ppmtoterm command and that ANSI-capable terminal. No root access is needed. Because the output is escape sequences and image characters, test it live in a terminal rather than redirecting it to a text file. The examples here use the Netpbm package installed on this machine, version 2:11.05.02-1.1build1.

1. Check the installed command

Confirm the command is present and note the package version. There are no ppmtoterm-specific switches: it takes one optional PPM filename, or reads a PPM from standard input.

$ command -v ppmtoterm
/usr/bin/ppmtoterm
$ dpkg-query -W -f='${Package} ${Version}\n' netpbm
netpbm 2:11.05.02-1.1build1
$ ppmtoterm --help
ppmtoterm: Use 'man ppmtoterm' for help.

That is not a broken help message. There are genuinely no program-specific options to list. Netpbm's common options may still be recognised, but this guide sticks to the documented filename and standard-input interface.

Checkpoint

You should have a real executable at /usr/bin/ppmtoterm, and your terminal should be able to display ANSI colour changes. If the command is missing, install the distribution's Netpbm package through your normal software-management process; that is an administrative step and deliberately not a copy-and-paste command here.

2. Create a tiny test image

A plain-text PPM gives you a predictable first test: two pixels wide, one pixel high, red then green. It is disposable and lives in the current directory only as a temp file.

$ cat > /tmp/ppmtoterm-test.ppm <<'PPM'
P3
2 1
255
255 0 0 0 255 0
PPM
  • P3 identifies an ASCII PPM.
  • 2 1 gives the width and height.
  • 255 is the maximum channel value.
  • The six numbers are the red, green and blue channels for the two pixels.

No sudo needed for this test. The only state change is a temporary file in /tmp. Remove it later with rm -- /tmp/ppmtoterm-test.ppm if you want to tidy up; that removes only this named test file.

3. Render the image at the cursor

Pass the filename as the optional argument:

$ ppmtoterm /tmp/ppmtoterm-test.ppm

What comes back is not ordinary text. The program emits ANSI escape sequences to pick approximate colours and uses one terminal character per input pixel. For a two-pixel test image, that is just two character cells, easy to miss if you blink. A reset sequence follows the image.

Tip

The image starts wherever the cursor already is when the command runs. Every later row starts at column 0. That means a prompt or earlier output can sit beside the first row while later rows overwrite from the left edge. Run it from a clean prompt, or add a line break first, if placement matters.

4. Feed the image through standard input

Skip the named file by piping PPM data straight into the command. Handy when another Netpbm program produces the image for you.

$ printf 'P3\n2 1\n255\n255 0 0 0 255 0\n' | ppmtoterm

The output should again be a pair of coloured character cells followed by a terminal reset. To confirm the pipeline actually worked, check the exit status:

$ printf 'P3\n2 1\n255\n255 0 0 0 255 0\n' | ppmtoterm > /dev/null
$ printf 'exit status: %s\n' "$?"
exit status: 0

Redirecting to /dev/null is fine for checking the exit status, but it throws away the ANSI image. Redirecting to a text file just captures escape sequences, not a portable screenshot or plain-text drawing.

5. Fit a real image to the terminal

ppmtoterm does not resize anything. One output character per input pixel means a large image fills the terminal and scrolls past before you can look at it. Scale first with Netpbm's pamscale. For example, to a width of 80 pixels:

$ pamscale -width 80 input.ppm | ppmtoterm

Height is worked out from the source image's proportions. If the result is still too tall, pick a smaller width or set a height explicitly, keeping the original proportions in mind. The manpage specifically points to pamscale and pamcut for making an image fit; reach for pamcut when cropping beats shrinking.

A terminal character is normally taller than it is wide, often by about a factor of two. Without compensating for that, a square source image looks stretched tall. To make a 20 by 20 image look closer to square, squash it vertically or stretch it horizontally by roughly two, per the documented approach. A practical starting point:

$ pamscale -width 40 -height 20 input.ppm | ppmtoterm

Adjust those numbers for your own font and terminal. Scaling only changes the data in the pipeline; input.ppm itself is untouched.

6. Set expectations for colour and image choice

The output palette is limited. Netpbm maps each input RGB value to the nearest colour in that palette by Cartesian distance between the RGB vectors, so what you see is an approximation, not a faithful copy.

Cartoons, logos and other flat-colour images tend to work best. Photos and gradients can look markedly different, especially with bright or numerous colours. For a better first result, pick an image whose channel intensities sit near zero, half maximum or maximum. That is a limitation of the terminal palette, not a sign the PPM file is corrupt.

If you actually need a monochrome line drawing, this is the wrong tool. ppmtoascii combines pixels into characters that represent rough brightness, and pbmto4425 targets black-and-white output on terminals that support its line-drawing characters.

Common traps

  • File cannot be opened. Check the path with ls -- /path/to/image.ppm. The input must be a readable PPM, not a PNG or JPEG renamed to end in .ppm.
  • Only escape-looking text appears. You are outside an ANSI-capable terminal, or the output got redirected. Go back to an interactive terminal for the visual test.
  • First row is offset, later rows aren't. That is documented cursor behaviour, not a bug. Move the cursor to where you want the image before running the command.
  • Image scrolls away. Scale it with pamscale or crop it with pamcut before rendering.
  • Colours look wrong. Try a small, flat-colour image. No terminal colour setting can restore detail the generated palette cannot represent.

Done means

  • Command confirmed: ppmtoterm is installed and its Netpbm version is known.
  • File rendered: a valid PPM file rendered at the current cursor position.
  • Pipeline checked: a standard-input pipeline returned exit status 0.
  • Sizing understood: you can scale or crop large images before rendering.
  • Output understood: ANSI control sequences, one character per input pixel, approximate colour palette.
  • No side effects: no elevated privileges or persistent configuration changes were needed.