Home / Alt manpages / pgm(5)

  • pgm(5)
  • File format
  • linux

Build and Verify a Portable Grayscale Image with PGM

You will create a tiny grayscale image as a PGM file, inspect what its header means, convert it to the binary form, and produce a PNG for a normal image viewer. The examples use the Netpbm tools installed here as package version 2:11.05.02-1.1build1.

Allow about fifteen minutes. You need a shell, the pnmtopng, pgmtopgm and pamfile commands, and a writable working directory. None of the examples need sudo. PGM is an image format, not a command, so the format header and the program's standard input and output are the parts to keep in view.

1. Check the installed tools

Confirm that the commands used in this guide resolve to installed programs:

$ command -v pamfile pnmtopng pgmtopgm
/usr/bin/pamfile
/usr/bin/pnmtopng
/usr/bin/pgmtopgm
$ dpkg-query -W -f='${Package} ${Version}\n' netpbm
netpbm 2:11.05.02-1.1build1

If a command is missing, stop at this checkpoint and install Netpbm through your normal package-management process. Do not replace a missing converter with a guessed option from another image tool.

2. Create a plain PGM without overwriting a file

PGM's plain form uses the magic number P2 and stores each pixel as an ASCII decimal value. This four by three sample has a maximum grey value of 15:

$ cat > gradient.pgm <<'EOF'
P2
# small test image
4 3
15
0 5 10 15
15 10 5 0
3 6 9 12
EOF

The quoted heredoc marker keeps the shell from expanding anything in the image data. The first line identifies P2. The next non-comment values are width, height and Maxval. Each later number is one pixel, read left to right and then top to bottom. Zero is black and Maxval is white.

A redirection with > truncates an existing destination before the command runs. For a file you care about, choose a new name or use a temporary output and rename it only after checking it. The sample above is safe to repeat only if replacing gradient.pgm is intentional.

Checkpoint: ask Netpbm to parse the file rather than trusting its name:

$ pamfile gradient.pgm
gradient.pgm:    PGM plain, 4 by 3  maxval 15

The spacing may differ. The useful facts are that the type is PGM plain, the dimensions are four by three, and Maxval is 15.

3. Understand the header before changing the encoding

Every PGM image begins with a magic number. The normal raw form uses P5; the plain form uses P2. Both can contain comments beginning with # and both describe width, height and Maxval. Whitespace may separate those fields.

Maxval must be greater than zero and below 65536. A value below 256 uses one byte per pixel in raw PGM. A value from 256 through 65535 uses two bytes per pixel, with the most significant byte first. The raw raster still contains rows from top to bottom and pixels from left to right.

Do not assume that a file ending in .pgm is valid, or that every PGM reader supports every valid file. PGM files may contain more than one image, with the images placed directly one after another. Older readers may stop after the first image, and older software may reject raw files whose Maxval is above 255.

4. Convert the sample to raw PGM

pgmtopgm reads its input from standard input and writes the converted image to standard output. Use shell redirection to give it a separate destination:

$ pgmtopgm < gradient.pgm > gradient-raw.pgm
$ pamfile gradient-raw.pgm
gradient-raw.pgm:    PGM raw, 4 by 3  maxval 15
$ file gradient-raw.pgm
gradient-raw.pgm: Netpbm image data, size = 4 x 3, rawbits, greymap

The converted file is binary after its header, so do not inspect it with a text editor. For this sample, each pixel still occupies one byte because Maxval is 15. A raw PGM is normally more compact and faster for software to read, while P2 is convenient when a person needs to inspect or generate the pixel values.

Checkpoint: if pamfile reports a different size or Maxval, do not continue to a lossy or display conversion. Reopen the source and check that the number of pixel values is exactly width multiplied by height.

5. Convert the verified image to PNG

Once the PGM parses correctly, use pnmtopng to create a viewable PNG. This reads either P2 or P5; here it reads the raw file:

$ pnmtopng gradient-raw.pgm > gradient.png
$ file gradient.png
gradient.png: PNG image data, 4 x 3, 4-bit grayscale, non-interlaced

The exact file wording can vary between versions. Check for a PNG image and the expected four by three dimensions. The output is a separate file, so the original PGM remains available for comparison or another conversion.

If the image looks inverted or has unexpected contrast, check what the values mean before editing pixels. In ordinary PGM, zero is black and Maxval is white. A transparency mask is a documented PGM variant in which the values represent opaqueness instead. That interpretation is part of the consuming application's contract, not a different file extension.

6. Diagnose failures without guessing

A bad magic number usually means the input is not a PGM or has been damaged. A dimension error often means the header was mistyped or the raster does not contain enough values. Check the first lines of a plain file with head, then run pamfile again. Do not use head on a raw raster as if all of its bytes were text.

If a conversion fails after you used >, the destination may already be an incomplete file. Remove or quarantine that new output after confirming its path, then rerun to a fresh name. Never delete the only copy of the source while diagnosing a format problem. If you need to replace an existing output, keep a backup until the new PNG has been opened and its dimensions checked.

PGM sample values are also subject to an encoding convention. The format describes values using the ITU-R BT.709 transfer function, while linear and sRGB variants are common in the wild. If a workflow depends on photometric accuracy, use pnmgamma deliberately and document which variant enters and leaves the workflow; do not treat a visually plausible PNG as proof that the transfer function was correct.

Done means

  • pamfile recognises the source as a PGM with the intended dimensions and Maxval.
  • You can distinguish plain P2 text from raw P5 binary data.
  • The raw conversion was written to a separate destination and checked before further use.
  • The PNG has the expected dimensions and the original PGM files remain available.
  • You know that comments, multi-image files, high Maxval values and gamma variants can affect compatibility.