Home / Alt manpages / ppmtopgm(1)

  • ppmtopgm(1)
  • User command
  • linux

Convert PPM Images to Greyscale with ppmtopgm

Turning a colour PPM to greyscale with ppmtopgm is not a simple channel average, and knowing that saves you from second-guessing the result. This guide uses Netpbm 11.5.2, installed here as package version 2:11.05.02-1.1build1. Allow about ten minutes. You need a shell, the netpbm package, and a PPM input file; the conversion itself does not require sudo.

ppmtopgm reads one PPM file and writes one PGM image to standard output. Omit the input filename and it reads standard input instead. The output is a black-and-white rendering based on luminance, not a straight average of the three channels.

1. Check the installed command

Confirm which executable the shell will run and record the Netpbm version:

$ command -v ppmtopgm
/usr/bin/ppmtopgm
$ ppmtopgm --version
ppmtopgm: Using libnetpbm from Netpbm Version: Netpbm 11.5.2

The extra version lines vary by build. If the command is missing, install the Netpbm package through your distribution's normal package manager, then repeat the check. Do not reach for an unrelated image converter and assume its greyscale formula matches.

Checkpoint

The command must resolve to the Netpbm executable before you convert anything. No elevated privileges are needed for this check.

2. Convert a PPM file to PGM

Pass the source filename as the optional argument and redirect standard output to a new destination:

$ ppmtopgm input.ppm > output.pgm

This does not touch input.ppm. Shell redirection creates or replaces output.pgm, so check that destination name before you press Enter. If output.pgm already holds something valuable, pick another name or move it aside first: a failed conversion can still leave a truncated destination, because the shell opens the file before the program even starts.

There is no status message on success. Check the exit status immediately and inspect the PGM header:

$ printf 'conversion status: %s\n' "$?"
conversion status: 0
$ od -An -tc -N 32 output.pgm
   P   5  \n   3       1  \n   2   5   5

Netpbm commonly writes the binary PGM format, whose magic number is P5. Do not expect the pixel data itself to be readable in a terminal; the header records width, height and maximum sample value, and the bytes after it are image data.

3. Verify the pixels in a readable form

Use Netpbm's plain-PNM utility when you need to inspect sample values rather than binary bytes:

$ pnmtoplainpnm output.pgm
P2
3 1
255
77 149 29

The exact numbers depend on the source image. For a reproducible smoke test, feed three primary-colour pixels through standard input and convert the result to plain PGM:

$ printf 'P3\n3 1\n255\n255 0 0   0 255 0   0 0 255\n' \
    | ppmtopgm | pnmtoplainpnm
P2
3 1
255
77 149 29

Those three values show the luminance weighting in practice: red, green and blue do not come out equally bright. The documented formula is y = .299 r + .587 g + .114 b, and the installed program rounds the resulting samples for the PGM representation.

Checkpoint

The output should start with P2 after pnmtoplainpnm, keep the dimensions 3 1, and hold three greyscale samples. This diagnostic pipeline changes no files.

4. Convert from a pipeline

Because the input filename is optional, another Netpbm command can feed ppmtopgm directly. Keep the final redirection explicit:

$ ppmtoppm source.pgm > source.ppm
$ ppmtopgm < source.ppm > source-greyscale.pgm

The first command is only there to show a producer that writes PPM. A PGM file can already be read by Netpbm programs, so do not bolt a pointless PGM-to-PPM round trip onto an existing greyscale workflow. If your source is already PPM, use the shorter direct conversion from step 2.

For a stream you do not want to save, send the result straight to another consumer instead:

$ ppmtopgm input.ppm | pnmtoplainpnm | sed -n '1,4p'
P2
...

Only do this when the next command actually understands PGM or plain PGM. Piping binary image data into a terminal or a text tool that is not PNM-aware produces confusing output and stray control characters.

5. Avoid losing brightness levels

The output keeps the input dimensions and maximum sample value, or maxval. That does not mean it keeps the same useful number of brightness levels: a PPM pixel has three channels, a PGM pixel has one, and with a very low maximum value several distinct input colours can collapse to the same grey.

If the source uses a low maxval, raise it before conversion with pamdepth:

$ pamdepth 255 low-range.ppm > expanded-range.ppm
$ ppmtopgm expanded-range.ppm > expanded-range.pgm

This does not restore detail already discarded; it just gives the luminance calculation more sample values to work with. Compare the headers and inspect representative pixels if the tonal range matters:

$ pnmtoplainpnm low-range.ppm | sed -n '1,4p'
$ pnmtoplainpnm expanded-range.pgm | sed -n '1,4p'

Do not reach for this step merely because the output looks dark or light. Check the source maxval and the actual pixel values first: brightness comes from the source data and the weighted conversion, not from any display adjustment inside ppmtopgm.

6. Handle failures without hiding them

Capture the status when the conversion is part of a script:

if ppmtopgm input.ppm > output.pgm; then
    printf '%s\n' 'PGM conversion succeeded'
else
    status=$?
    printf 'ppmtopgm failed with status %s\n' "$status" >&2
    exit "$status"
fi

A non-zero status usually means the input could not be read or was not a valid PPM stream. Check standard error, the input path and the destination permissions. A file merely being present is not proof of a complete conversion: the redirection may have created a partial file before failure.

Recovery

If a failed run replaced an existing destination, restore it from your normal backup or regenerate it from the original input. There is no undo built into ppmtopgm. The command has no conversion-specific options of its own; it accepts only the common libnetpbm options plus the optional input filename.

Done means

  • ppmtopgm --version identified the Netpbm implementation you used.
  • Converted a PPM to a separate PGM destination without needing sudo.
  • Checked the exit status and inspected the PGM header.
  • Used pnmtoplainpnm whenever readable sample values mattered.
  • Accounted for the weighted luminance formula and the input maxval.
  • Your script reports conversion failure instead of silently keeping a partial file.