Map Numeric Image Values to Colours with pamlookup
pamlookup turns a greyscale index image into a colour one by treating each pixel value as a row into a palette you supply. This guide builds a small, reproducible lookup workflow on Netpbm 11.5.2, package netpbm version 2:11.05.02-1.1build1.
The route
Jump straight to the step you need, or tick off Done means at the end.
Allow about fifteen minutes. You need the Netpbm tools, a PAM or PNM index image, and a PAM or PNM lookup image. The examples use plain-text PGM and PPM files so their values are easy to inspect. Nothing here needs elevated privileges when you work in a directory you own.
1. Check the installed command
Confirm which executable will run and record the installed Netpbm version. These are read-only checks:
$ command -v pamlookup
/usr/bin/pamlookup
$ pamlookup --version
pamlookup: Using libnetpbm from Netpbm Version: Netpbm 11.5.2
$ dpkg-query -W -f='${Package} ${Version}\n' netpbm
netpbm 2:11.05.02-1.1build1
The command takes one index image as its positional argument and needs -lookupfile to name the table image. The result goes to standard output, so redirect it to a new destination. You do not need sudo just because the input is an image.
2. Make a small index and colour table
For a first test, build an index image with values from 0 to 2 and a three-entry colour table. The table is one row, wide enough for those values: column 0 is red, column 1 is yellow, column 2 is pale beige.
$ mkdir -p "$HOME/pamlookup-demo"
$ cd "$HOME/pamlookup-demo"
$ printf 'P2\n3 2\n2\n0 1 0\n2 2 2\n' > index.pgm
$ printf 'P3\n3 1\n255\n255 0 0 255 255 0 245 245 220\n' > colours.ppm
These are ordinary PGM and PPM files. In the index, the first row is 0 1 0 and the second is 2 2 2. The maximum index value is 2, so the lookup table needs at least three columns. Check both headers before mapping:
$ pamfile index.pgm colours.ppm
index.pgm: PGM plain, 3 by 2 maxval 2
colours.ppm: PPM plain, 3 by 1 maxval 255
Your pamfile wording can differ slightly between Netpbm builds. What matters is the dimensions, format and maximum value.
3. Map whole-number indices to colour tuples
Run the default mode, whole tuple indexing. Each sample in the one-plane index image is treated as a column number in the one-row lookup image:
$ pamlookup index.pgm -lookupfile=colours.ppm > mapped.ppm
$ pamfile mapped.ppm
mapped.ppm: PPM raw, 3 by 2 maxval 255
The output keeps the index image's width and height, but takes its tuple depth, image type and maximum value from the lookup image. Here that is a two-row, three-column PPM. The first output row comes out red, yellow, red; the second, beige, beige, beige.
Checkpoint
Inspect the result with an image viewer or another Netpbm converter. A PPM may be written in raw binary form even when the inputs were plain text, so use pamfile rather than sed to inspect the full output.
4. Handle an index that is not in the table
In whole tuple mode, a lookup table that is too narrow does not automatically stretch. Without -fit, an index beyond the table dimensions uses the top-left lookup tuple unless you provide -missingcolor. That default can hide bad or unexpected data without complaint.
For a deliberate fallback, make a table with only two entries and map an index that contains a 2:
$ printf 'P3\n2 1\n255\n255 0 0 0 0 255\n' > short-colours.ppm
$ pamlookup index.pgm -lookupfile=short-colours.ppm -missingcolor=black > missing-black.ppm
$ pamfile missing-black.ppm
missing-black.ppm: PPM raw, 3 by 2 maxval 255
The pixels with index 2 come out black. -missingcolor matters only for PNM lookup images, and it has no effect when -fit or -byplane is used. Colour names are parsed by Netpbm's colour parser, so stick to a simple name such as black or a documented value your installation accepts.
Alternatively, use -fit when the table is a palette that should be stretched or shrunk to the index image's maximum value:
$ pamlookup index.pgm -lookupfile=short-colours.ppm -fit > fitted.ppm
$ pamfile fitted.ppm
fitted.ppm: PPM raw, 3 by 2 maxval 255
-fit resizes the lookup image to the required width using Netpbm scaling. It is a data transformation, not a way to mark invalid indices, so reach for it only when interpolation or resampling is actually what you want.
5. Use each image plane as its own index
Add -byplane when each sample in a multi-plane image should be looked up independently. The output has the index image's dimensions and the lookup image's maximum value. A one-plane PGM makes the rule visible without needing a multi-plane PAM:
$ printf 'P2\n3 2\n2\n0 1 0\n2 0 2\n' > plane-index.pgm
$ printf 'P2\n3 1\n7\n3 4 7\n' > sample-table.pgm
$ pamlookup -byplane plane-index.pgm -lookupfile=sample-table.pgm > plane-result.pgm
$ pamfile plane-result.pgm
plane-result.pgm: PGM raw, 3 by 2 maxval 7
The output samples are 3, 4, 3 on the first row and 7, 3, 7 on the second. In this mode pamlookup always scales the lookup image to the index range, and both -fit and -missingcolor have no effect. For a true multi-plane input, every sample at a given row, column and plane is mapped separately.
Whole tuple mode has a second form: a two-plane index image supplies ordered pairs. The first sample selects a lookup-table row, the second a column. Use pamstack to combine two one-plane index images before passing them to pamlookup; the lookup image then needs the matching two-dimensional layout.
6. Avoid destructive redirection and diagnose failures
Shell redirection truncates its destination before pamlookup even starts. Protect an existing result by writing to a new name first, then replacing it only after checking the new file:
$ pamlookup index.pgm -lookupfile=colours.ppm > mapped.ppm.new
$ pamfile mapped.ppm.new
$ mv mapped.ppm.new mapped.ppm
If the command fails, the old mapped.ppm stays put. The temporary output may be incomplete, so remove it only once you know which file is safe to discard. Do not delete the original index or lookup images until the mapped image has been checked.
A missing or unreadable lookup file points to a path or permission problem. An invalid lookup dimension usually means the table is too short for whole tuple mode: decide between a deliberate -missingcolor fallback and -fit. The index and lookup images may each be read from standard input with -, but not both at once, since pamlookup needs two independent inputs.
Done means
- Versions checked. You confirmed the installed Netpbm and pamlookup versions.
- Table sized correctly. The index image's values match the lookup table's columns, or you chose an explicit out-of-range policy.
- Mode chosen deliberately. Whole tuple indexing for palette output, or -byplane for independent sample mapping.
- Output verified. pamfile confirms the dimensions, format and maximum value.
- Safe write path. You wrote to a new output name before replacing an existing image.
- Inputs preserved. The original index and lookup images remain available for recovery or a different mapping.