Split a PPM Image into Raw YUV Planes with ppmtoyuvsplit

ppmtoyuvsplit takes a PPM image and writes three raw files: a full-resolution .Y luminance file, and subsampled .U and .V chrominance files. Allow about ten minutes if Netpbm is already installed and you know the input path. The input is read, not modified, but the three output names get replaced if they already exist.

1. Check the installed command

This guide uses the ppmtoyuvsplit shipped by Debian's Netpbm package. The installed command here reports Netpbm 11.5.2, built from source dated 31 March 2024. The manual page itself is dated 6 March 2003, so the version check is worth doing if you are reproducing an older workflow. No elevated privileges are needed for files in your own working directory.

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

The command has one program-specific interface, not a collection of conversion flags:

ppmtoyuvsplit basename [ppmfile]

Checkpoint: you should have a readable PPM file and a destination directory where you can create three new files.

2. Convert a PPM file

Give the output basename first, followed by the PPM input. The program then creates basename.Y, basename.U and basename.V. For example, this writes into the current directory:

$ ppmtoyuvsplit yuv/frame-001 /path/to/frame-001.ppm
$ ls -l yuv/frame-001.Y yuv/frame-001.U yuv/frame-001.V
-rw-r--r-- 1 you you 307200 Sep 26 12:00 yuv/frame-001.Y
-rw-r--r-- 1 you you  76800 Sep 26 12:00 yuv/frame-001.U
-rw-r--r-- 1 you you  76800 Sep 26 12:00 yuv/frame-001.V

The exact file sizes and timestamps depend on the image. What matters is three files sharing a basename and the three suffixes. Omit ppmfile and the program reads a PPM image from standard input instead:

$ ppmtoyuvsplit yuv/frame-001 < /path/to/frame-001.ppm

Use one input form at a time. A common mistake is putting the basename after the input filename, which reverses the documented order and can produce a confusing argument error.

3. Understand the output layout

The .Y file contains one byte for each input pixel, rows stored top to bottom and each row left to right. The .U and .V files use one byte per square of four input pixels, so each is a quarter of the Y file's size for a valid even-width, even-height image. The values use the CCIR.601 scaling expected by MPEG, rather than being three independent RGB channels.

For a 640 by 480 image, expect 307,200 bytes for Y and 76,800 bytes for each chrominance plane. Check both the image dimensions and the result sizes before handing the files to an encoder:

$ file /path/to/frame-001.ppm
/path/to/frame-001.ppm: Netpbm image data, size = 640 x 480, pixmap
$ wc -c yuv/frame-001.Y yuv/frame-001.U yuv/frame-001.V
307200 yuv/frame-001.Y
 76800 yuv/frame-001.U
 76800 yuv/frame-001.V
384000 total

Checkpoint: for width W and height H, expect Y to hold W * H bytes and each of U and V to hold W * H / 4 bytes. Confirm the dimensions suit the consumer before relying on that calculation.

4. Test with a small image

A small, known-size test makes it easier to tell a path problem from a format problem. If the Netpbm package also provides ppmmake, this creates a 4 by 4 red PPM and converts it into a temporary output set:

$ test -x "$(command -v ppmmake)" && echo "ppmmake is installed"
ppmmake is installed
$ work=$(mktemp -d /tmp/ppmtoyuvsplit-test.XXXXXX)
$ ppmmake red 4 4 > "$work/input.ppm"
$ ppmtoyuvsplit "$work/out" "$work/input.ppm"
$ wc -c "$work/out.Y" "$work/out.U" "$work/out.V"
16 /tmp/ppmtoyuvsplit-test.example/out.Y
 4 /tmp/ppmtoyuvsplit-test.example/out.U
 4 /tmp/ppmtoyuvsplit-test.example/out.V
24 total

The directory name your shell prints will differ from the example. The byte counts are the useful check: a 4 by 4 input has 16 Y bytes and four bytes in each subsampled plane. Keep the temporary directory until you have finished checking it, then remove it with your normal temporary-file housekeeping.

5. Avoid overwriting an existing split

ppmtoyuvsplit uses the basename to choose its outputs. Do not point it at a basename whose Y, U or V files are valuable unless you have already copied them or intend to replace them. A safer batch pattern uses a new basename and inspects the results before changing any downstream configuration:

$ mkdir -p yuv/new
$ ppmtoyuvsplit yuv/new/frame-001 /path/to/frame-001.ppm
$ wc -c yuv/new/frame-001.Y yuv/new/frame-001.U yuv/new/frame-001.V

The mkdir command changes filesystem state but needs no sudo when the parent directory is yours. If a conversion stops part-way through, treat any newly created plane as incomplete and remove or quarantine the whole new output set before retrying. Do not delete an older set until the replacement has passed your size and consumer checks.

6. Diagnose failures

If the command reports that it cannot open the input, inspect the path and permissions without changing anything:

$ ls -l /path/to/frame-001.ppm
$ test -r /path/to/frame-001.ppm && echo readable

The program has no specific command-line options of its own. It does accept common libnetpbm options, but this guide does not depend on them. Do not invent a resize flag or assume the basename is a directory: the basename is a filename prefix, and the parent directory must already exist.

Done means