Convert an Atari Spectrum SPC File to PPM with spctoppm

Someone hands you a .spc file from an old Atari archive and spctoppm turns it into a PPM that every other Netpbm tool can actually read. It writes the image to standard output, so the real job is redirecting that cleanly and checking what lands. Ten minutes if the file is already readable.

This guide covers the installed Netpbm 11.5.2 command. The manual page is old and the interface is deliberately tiny: one optional input filename, no command-specific switches.

1. Check the command and the input

Two read-only checks, no elevated privileges needed:

$ command -v spctoppm
/usr/bin/spctoppm
$ spctoppm --version
spctoppm: Using libnetpbm from Netpbm Version: Netpbm 11.5.2
$ test -r /path/to/picture.spc && echo readable
readable

Swap in your actual path for /path/to/picture.spc. The extension is a hint, not proof: a .spc name does not make a random file a Spectrum picture. Leave the original alone until the converted image checks out.

Checkpoint: If command -v comes back empty or the read test prints nothing, stop. Install Netpbm the normal way, or fix the path and permissions. Do not reach for root just because a filename is wrong.

2. Convert the file

Pass the input filename and redirect standard output to a new destination:

$ spctoppm /path/to/picture.spc > picture.ppm
$ printf 'exit status: %s\n' "$?"
exit status: 0

A clean run stays quiet because the image itself is the standard output. That output is binary, so do not paste it into a terminal or crack it open in a text editor. The command only reads the SPC file and writes the PPM; it never touches the input.

Warning: shell redirection truncates picture.ppm the instant spctoppm starts, before it has produced anything. If that file already holds an image you care about, use a fresh name or back it up first. A failed conversion can leave you with a zero-length or half-written destination.

$ spctoppm /path/to/picture.spc > picture.ppm.new
$ status=$?
$ if [ "$status" -eq 0 ]; then mv -- picture.ppm.new picture.ppm; else rm -- picture.ppm.new; exit "$status"; fi

The temporary file only gets removed on a failed conversion; the real destination only gets replaced once the converter has exited successfully. That rm is scoped to the newly created temp file alone, but check its name before you reuse this pattern elsewhere.

3. Verify the output is a real PPM

Do not trust the exit status alone. Look at the file itself:

$ test -s picture.ppm && echo non-empty
non-empty
$ file picture.ppm
picture.ppm: Netpbm image data, size 256 x 192, rawbits, pixmap
$ head -c 2 picture.ppm
P6

The dimensions are part of the PPM header, so jot them down if a later step expects a particular size. For an extra check, a Netpbm reader gives you the header in plain terms:

$ pamfile picture.ppm
picture.ppm: PPM raw, 256 by 192 by 255 maxval

pamfile is a separate utility, so if it is missing that says nothing about whether spctoppm worked. A trusted image viewer, or another Netpbm converter, gives you the visual confirmation. Keep the SPC source until that check is done.

4. Feed it from a pipeline instead

The filename is optional. Omit it and spctoppm reads the Atari data from standard input, still writing PPM to standard output:

$ cat /path/to/picture.spc | spctoppm > picture-from-stdin.ppm
$ file picture-from-stdin.ppm
picture-from-stdin.ppm: Netpbm image data, size 256 x 192, rawbits, pixmap

Handy when another program supplies the bytes, but a pipeline hides which stage failed. For a one-off conversion, passing the filename directly is easier to inspect. If you do script a pipeline, enable proper pipeline error handling and check the output file afterwards; do not mistake an omitted argument for a format-selection option.

5. Diagnose a rejected input

An unsupported file gets an error like not a Spectrum picture and a non-zero exit status:

$ spctoppm /path/to/unknown-file.spc > rejected.ppm
spctoppm: not a Spectrum picture
$ printf 'exit status: %s\n' "$?"
exit status: 1
$ ls -l rejected.ppm

Keep the source and inspect it rather than guessing. Only delete rejected.ppm once you have confirmed it is disposable test output. Check that the file is genuinely the Atari compressed Spectrum format this tool expects, not a renamed image or something meant for sputoppm. That is a related but separate converter, and the manual lists it as such; it is not a drop-in substitute without matching input data.

There are no spctoppm-specific options worth hunting for. It picks up common libnetpbm options, but this conversion never needs them. Do not invent resize, format or quality flags here; those belong to whatever tool you run after the PPM is verified.

Done means