Replace PPM Colours Safely with ppmchange
You will replace selected colours in a PPM image and write a verified result without changing the source file. The examples use ppmchange from Netpbm 11.5.2, installed here as package version 2:11.05.02-1.1build1. Allow about ten minutes if the input file is ready. You need the netpbm package and a writable working directory.
The route
Jump straight to the step you need, or tick off Done means at the end.
Checkpoint
This is an unprivileged image operation. Do not use sudo unless ordinary file permissions genuinely prevent access to the input or output directory. The command reads a PPM image and writes the converted image to standard output; shell redirection decides where that output is saved.
1. Check the installed command
Confirm which executable will run and record the package version. These checks do not change files:
$ command -v ppmchange
/usr/bin/ppmchange
$ dpkg-query -W -f='${Package} ${Version}\n' netpbm
netpbm 2:11.05.02-1.1build1
Netpbm's manual page for this installed command is dated December 2016. The local package version is the reference point for the examples below. If your distribution ships another release, run man ppmchange before putting an option into a script.
2. Replace one exact colour
Give one old-colour and new-colour pair, followed by the input file. The input is not edited:
$ ppmchange red blue /path/to/input.ppm > recoloured.ppm
Colour names are parsed by Netpbm's colour parser. Names such as red, blue and black are convenient, while a numeric form accepted by that parser is useful when you need an exact shade. Keep the old and new values as separate arguments, and quote a value if your shell command constructs it from user input.
By default, the match is exact. A pixel must have the specified red, green and blue values at the image's own scale. Pixels with other colours remain unchanged unless you request a remainder colour later.
Checkpoint
Check the exit status immediately and inspect the PPM header. PPM output is commonly binary, so do not expect the whole image to be readable with less:
$ printf 'exit status: %s\n' "$?"
exit status: 0
$ file recoloured.ppm
recoloured.ppm: Netpbm image data, size ...
The wording from file varies. A successful check should show a non-empty Netpbm image. For a direct header check, use:
$ head -c 2 recoloured.ppm
P6
The installed command writes a raw PPM stream with the P6 magic number in this example. Do not treat the output as text or paste its binary bytes into a terminal.
3. Preserve the old output while testing
Shell redirection with > truncates its destination before ppmchange starts. That can destroy a previously useful result if the command then fails. Use a temporary output beside the final file, verify it, and replace the final file only after the check:
$ ppmchange red blue input.ppm > input.ppm.new
$ test -s input.ppm.new
$ head -c 2 input.ppm.new
P6
$ mv input.ppm.new input.ppm
The mv command changes the directory entry, so it is the state-changing step in this sequence. If conversion or verification fails, leave input.ppm alone and investigate the error. Remove the incomplete input.ppm.new only when you have confirmed that it is the failed temporary file. If you must replace an existing file across a more complicated workflow, make a separate backup first.
4. Replace several colours in one pass
Supply more old/new pairs in sequence. The command accepts up to 256 pairs:
$ ppmchange red blue green yellow input.ppm > two-colour-replacements.ppm
Here, red becomes blue and green becomes yellow. If a pixel matches more than one old colour, the leftmost pair wins. That ordering is easy to miss when similar colours are involved, so put the most specific intended match first and keep the command readable.
Do not confuse a pair with the input filename. Every colour replacement needs two arguments. If the final colour argument is missing, the program cannot interpret the command as intended. Re-run with the exact pair list and check the generated file rather than trying to repair a partial binary stream.
5. Replace near matches with closeness
Use -closeness=10 when a small variation around the requested colour should also match:
$ ppmchange -closeness=10 red blue input.ppm > nearby-reds-to-blue.ppm
The default closeness is 0, which means exact matching. The percentage is based on Netpbm's normalised Cartesian sum of the red, green and blue differences. It is not a perceptual distance and it does not understand that two differently lit areas may belong to the same object. A larger value can therefore replace pixels that merely happen to be numerically close.
Use a small value first, inspect the result, and keep the original image. This option can change more pixels than expected, especially in photographs or images with gradients. There is no undo inside ppmchange; recovery means rerunning from the untouched original with a narrower match or restoring your saved output.
6. Set a remainder colour for a mask-like result
Without -remainder, colours you did not name pass through unchanged. With it, every pixel that did not receive an explicit replacement is set to one colour:
$ ppmchange -remainder=black red white input.ppm > red-mask.ppm
This turns exact red pixels white and all other pixels black. It is useful for a simple mask, but it is deliberately destructive to the other colours in the output. The input remains untouched because the output is redirected to a new file.
You can combine a remainder with several explicit pairs. Remember that the remainder applies only after the explicit matches have been considered. Verify both the header and the visual result before using the mask in a later pipeline.
7. Handle maxval warnings
PPM stores a maximum sample value called maxval. The output keeps the input image's maxval. If a requested new colour cannot be represented exactly at that scale, ppmchange uses the nearest representable colour and, unless -closeok is supplied, warns about the approximation.
This matters particularly when a source came from PBM, whose maxval is normally 1. A black-and-white source cannot represent ordinary RGB shades accurately just because you provide colour names. Inspect the input first, and use pamdepth to create a suitable maxval before colourising when that is appropriate:
$ pamdepth 255 input.ppm > input-255.ppm
$ ppmchange red blue input-255.ppm > recoloured.ppm
Only use -closeok when the approximation is understood and acceptable:
$ ppmchange -closeok red blue input.ppm > recoloured.ppm
This option suppresses the warning; it does not increase the image's precision. Do not use it as a way to hide unexpected output in an automated job. Capture diagnostics and verify the resulting image when the exact colour matters.
8. Diagnose failures without guessing
An input error usually means the path is wrong, the file is empty, or it is not a valid Netpbm image. Check those facts without changing the image:
$ ls -l /path/to/input.ppm
$ test -r /path/to/input.ppm && echo readable
$ head -c 2 /path/to/input.ppm
P3
A source can use P3 for plain-text PPM or P6 for raw binary PPM. The output may be binary even when the input is plain text. If the header is missing or the command reports an invalid magic number, stop and locate the correct source rather than appending more options.
If the result looks unchanged, check whether the pixels are exact matches, whether the requested pair is ordered correctly, and whether the source maxval can represent the requested colour. Add a small closeness value only when you have inspected the risk of replacing neighbouring shades. There is no need for elevated privileges for any of these checks.
Done means
- The installed
ppmchangeand Netpbm version were checked. - The source PPM remains available and the output was written to a separate path first.
- Exact replacements, pair ordering and any remainder behaviour are understood.
- Closeness was used deliberately, with the original retained for recovery.
- The output header and exit status were checked, and maxval warnings were not hidden accidentally.