Build and apply a smaller Netpbm colour map with pnmcolormap
You will finish with a smaller palette for a PNM or PAM image, a quantised copy made from that palette, and checks that show what the command actually produced. The examples use Netpbm 11.5.2 from Debian package netpbm 2:11.05.02-1.1build1.
The route
Jump straight to the step you need, or tick off Done means at the end.
- 1. Check the installed command
- 2. Inspect the input before choosing a palette size
- 3. Generate a map without changing the source
- 4. Apply the map to the image
- 5. Make the output easier to compare
- 6. Choose quantisation behaviour deliberately
- 7. Use all colours only when you mean it
- 8. Handle multi-image input consistently
- 9. Diagnose the common failures
Allow about fifteen minutes. You need pnmcolormap, pnmremap, and an input image in PNM or PAM format. The examples write new files beside the input and do not alter the original. No elevated privileges are needed. Keep enough disk space for a temporary copy: the program may need several passes through the image.
1. Check the installed command
Start by recording the binary and library version. This is read-only and should work as an ordinary user:
$ command -v pnmcolormap
/usr/bin/pnmcolormap
$ pnmcolormap --version
pnmcolormap: Using libnetpbm from Netpbm Version: Netpbm 11.5.2
...
The remaining version lines identify the build date and distributor. They vary between machines, so the useful checkpoint is the reported Netpbm version. This guide follows the command installed on the machine where the local manual page is available. Older Netpbm releases can differ in the details of their tie handling during quantisation.
2. Inspect the input before choosing a palette size
Use an existing file for the first run. Replace INPUT.ppm with a real path, and do not overwrite it with shell redirection:
$ file INPUT.ppm
INPUT.ppm: Netpbm image data, size 1920 x 1080, rawbits, pixmap
$ head -n 3 INPUT.ppm
P6
1920 1080
255
A PNM image may be PBM, PGM, or PPM. PAM is accepted too. The output keeps the input format, so a PPM input produces a PPM map. A map is itself a tiny image containing one pixel for each selected colour, unless a layout option adds padding.
Choose a target that matches the job rather than assuming that a larger number is always better. For a preview, 16 or 32 colours is a useful first comparison. If the source has fewer distinct colours than requested, the result can contain slightly fewer colours. That is normal. The required argument is a positive number, or the special value all.
3. Generate a map without changing the source
Write the map to a new file. This ordinary command reads INPUT.ppm and sends the generated image to standard output:
$ pnmcolormap 32 INPUT.ppm > palette-32.ppm
pnmcolormap: making histogram...
pnmcolormap: Scanning image 0
pnmcolormap: ...
$ head -n 3 palette-32.ppm
P6
32 1
255
The diagnostic lines are written to standard error, while the PNM data goes to the redirected standard output. The default method is Heckbert's median cut. It separates colours into boxes, repeatedly splits boxes, and picks one representative colour from each box. By default it splits the box containing the most pixels and chooses the centre colour of each box.
Do not treat the width in the header as an image width that you selected independently. Without -square, this program normally emits one row with one column per colour. It is a colour map for another Netpbm program, not usually a display-ready swatch.
Checkpoint: confirm that the file exists and has a plausible header:
$ test -s palette-32.ppm && sed -n '1,3p' palette-32.ppm
P6
32 1
255
4. Apply the map to the image
pnmcolormap only creates the palette. Use pnmremap to produce an image whose pixels are selected from that palette:
$ pnmremap -map palette-32.ppm INPUT.ppm > INPUT-32.ppm
$ file INPUT-32.ppm
INPUT-32.ppm: Netpbm image data, size 1920 x 1080, rawbits, pixmap
The input image is still untouched. The remapped image has the same dimensions and format in this example, but its colours come from the map. Inspect it with an image viewer or the tool used by your normal image pipeline. If you need the combined operation and do not need to keep the palette, pnmquant performs the map-and-remap workflow for you.
There is no undo command because these examples create new files. To remove a result, first check the exact path and then delete only that generated file:
$ ls -l -- palette-32.ppm INPUT-32.ppm
$ rm -- palette-32.ppm INPUT-32.ppm
This deletion is irreversible unless you have another copy. Never replace INPUT.ppm in the output redirection unless you have deliberately made a backup and checked that the source and destination are different.
5. Make the output easier to compare
Use -sort when you want two generated maps to be easier to compare. It sorts colours by red, then green, then blue intensity:
$ pnmcolormap -sort 32 INPUT.ppm > palette-32-sorted.ppm
Sorting changes the order of pixels in the map, not the target number of colours. It uses insertion sort, so it is not a good performance choice for very large maps. For routine quantisation, leave it out unless stable visual comparison matters.
Use -square when a viewer or contact sheet works better with a roughly square map:
$ pnmcolormap -square 32 INPUT.ppm > palette-32-square.ppm
$ head -n 3 palette-32-square.ppm
P6
6 6
255
The square layout can duplicate the final pixel so that the number of pixels is close to a perfect square. Those duplicates are padding, not extra palette choices. If the target is not a perfect square, count the meaningful colours from the requested value and remember that the final pixel may be repeated.
6. Choose quantisation behaviour deliberately
The defaults are reasonable for a first pass, but they are not neutral. Add -meancolor to represent each box with the component-wise mean of its colours. Add -meanpixel to weight that mean by how often each colour appears. Leave the representative-colour option unset if you want the default centre colour.
The split decision also has three choices:
-splitpixelctis the default and splits the box containing the most pixels.-splitcolorctsplits the box containing the most distinct colours. The manual describes this as mainly useful for academic purposes.-splitspreadsplits the box with the largest colour spread, which can preserve small details whose colours occur less often.
For the component used to measure spread, -spreadbrightness is the default. -spreadluminosity weights components by their contribution to luminosity, so red, green, and blue do not count equally. Change one decision at a time and compare the remapped image, because a palette that looks plausible as a strip may still lose an important detail in the result.
For example, this keeps the default representative colour but favours a wide colour spread and a stable order:
$ pnmcolormap -splitspread -spreadbrightness -sort 32 INPUT.ppm > palette-detail.ppm
$ pnmremap -map palette-detail.ppm INPUT.ppm > INPUT-detail.ppm
These algorithm options were added in Netpbm 10.88. The installed 11.5.2 version supports them. Repeated runs with the same Netpbm version are repeatable, including equal-value tie handling, but do not assume byte-for-byte equality across older versions or different implementations.
7. Use all colours only when you mean it
The special argument all asks for every colour found in the input and skips quantisation:
$ pnmcolormap all INPUT.ppm > palette-all.ppm
$ head -n 3 palette-all.ppm
P6
N 1
255
Replace N with the width reported by the command on your own image. On a photograph, the number may be large, so the resulting map may offer little space or processing benefit. Use a numeric target when the point is to reduce the palette. If all is used for an exact colour inventory, compare the map with ppmhist -map as described by the manual, rather than interpreting it as a compressed image.
8. Handle multi-image input consistently
pnmcolormap can read a multi-image stream and build one map from all images. Every image must have the same format, depth, and maxval, although dimensions may differ. This is useful for animation frames or a batch that must share one palette: the same source colour will not be assigned differently merely because it appears in another frame.
Do not concatenate unrelated formats and hope the command will reconcile them. If the stream violates those requirements, stop at the diagnostic and normalise the inputs before trying again. A single-image test is easier to inspect, so make that your checkpoint before building a multi-image pipeline.
9. Diagnose the common failures
A message saying that the number of colours must be positive means the required argument was zero or negative. Use a positive integer or all. A map with fewer entries than requested usually means that the input contains fewer distinct colours, not that the redirection failed.
If the output file is empty or is not a PNM image, check the command's standard error and the input path. Shell redirection creates the destination before the program runs, so a failed command can leave an empty file behind. Remove that known generated file before retrying, and do not mistake its existence for successful output.
If the image is technically valid but looks poor, keep the source and compare a few target sizes. Try -meanpixel for photographs dominated by common colours, or -splitspread for small, infrequent details. Keep the map beside each result so you can reproduce the choice later. Quantisation is a trade-off, not a promise that every input colour will remain visible.
Done means
- You recorded the installed Netpbm version and confirmed the input format.
- You generated a palette into a new file without overwriting the source.
- You checked the map header and applied it with
pnmremap. - You know that the default split is by pixel count and the default representative is the centre colour.
- You used
-sortor-squareonly for a clear comparison or layout need. - You kept the original image and can remove the generated files by their exact paths.