Combine Netpbm Images Safely with pamarith
Multiply two Netpbm images naively and the result comes out far darker than expected: pamarith treats samples as fractions of maxval. You will use it to combine two Netpbm images and check the result without guessing what the sample values mean. The examples use PAM files because their width, depth, maxval and tuple type are visible. Allow about 15 minutes if the input images already exist.
The route
Jump straight to the step you need, or tick off Done means at the end.
You need the netpbm package and two readable PBM, PGM, PPM or PAM images. This guide matches Netpbm 11.5.2, installed here on Debian as package version 2:11.05.02-1.1build1. No command below needs elevated privileges. Keep the original inputs: pamarith reads them and writes a new image to standard output.
1. Check the inputs
Inspect both files first. Replace the example names with your own paths.
pamfile left.pam right.pam
Each image must have the same width and height. Their depths must match, unless one image has depth 1. A depth-1 image is applied to every sample in the other image, which is useful for a greyscale mask applied to an RGB image. If these conditions are not met, stop here and fix the inputs rather than forcing the command.
Checkpoint
The dimensions agree, and either the depths agree or one depth is 1.
2. Add two images
Choose one operation and put it before the input paths. The first path is the left operand and the second is the right operand. This matters for subtraction, division and shifts.
pamarith -add left.pam right.pam > added.pam
pamfile added.pam
For ordinary arithmetic, samples are treated as fractions of their maxval. The output maxval is normally the larger input maxval, and values outside the usable range are clipped. With equal maxvals, adding sample values 80 and 40 gives 120 unless that exceeds the maxval.
Do not assume multiplication means the literal product of stored samples. With maxval 255, multiplying samples 5 and 10 means multiplying 5/255 by 10/255, then rescaling. The rounded result is 0, not 50. Division works the same fractional way; a zero divisor produces the output maxval.
3. Choose the operation deliberately
These are the useful everyday choices:
-add,-subtract,-difference,-minimum,-maximum. Combine or compare sample intensities. Subtraction is left minus right; difference is the absolute difference.-equal. Emits a two-valued image with maxval 1. Add-closeness=Nwhen samples within N percent of maxval should count as equal. Closeness is valid only with-equal.-compare. Emits 0 when left is smaller, 1 when equal and 2 when left is greater. Its output maxval is 2.-and,-or,-nand,-nor,-xor. Treat samples as bit strings. Their maxval must be a full binary count such as 1, 3, 7 or 255.-shiftleft,-shiftright. Shift the left bit string. The right sample is the actual shift count, so its maxval does not define the shift width.
Use one function option only. Option names can be abbreviated to a unique prefix, and the installed program accepts either one or two leading hyphens, but full names make scripts easier to audit.
4. Verify a comparison result
This small in-memory check uses two one-pixel PAM streams. It verifies that comparing 3 with 7 produces a PAM image whose maxval is 2.
printf 'P7\nWIDTH 1\nHEIGHT 1\nDEPTH 1\nMAXVAL 15\nTUPLTYPE GRAYSCALE\nENDHDR\n\n\003' \
| pamarith -compare - <(printf 'P7\nWIDTH 1\nHEIGHT 1\nDEPTH 1\nMAXVAL 15\nTUPLTYPE GRAYSCALE\nENDHDR\n\n\007') \
| pamfile
Expected output includes PAM, 1 by 1 by 1 maxval 2. The command uses Bash process substitution; for ordinary files, use their paths instead. A comparison result is data, not a shell exit status, so inspect or consume the output image explicitly.
5. Handle multiple inputs and failures
In this Netpbm release, associative and commutative operations such as -add, -minimum and -maximum can take more than two images. The operation is applied repeatedly across the supplied inputs.
pamarith -maximum first.pam second.pam third.pam > brightest.pam
Subtraction, division, equality and comparison require exactly two inputs. Before Netpbm 10.93, every operation rejected more than two inputs, so do not copy a multi-input command to an older host without checking its installed manual.
If a command fails, the shell may still leave a partial redirected file. Write to a temporary name in the same directory, inspect it, then replace a destination only after success:
tmp='added.pam.tmp'
if pamarith -add left.pam right.pam > "$tmp"; then
pamfile "$tmp" && mv -- "$tmp" added.pam
else
rm -f -- "$tmp"
printf '%s\n' 'pamarith failed; the old output was kept' >&2
exit 1
fi
Warning
This changes only the named output. If mv has already replaced it, recover the previous version from your backup or version-control system; pamarith has no undo operation.
Done means
- Inputs checked: the input dimensions and permitted depths were checked.
- Operation matches intent: the operation matches the meaning of the maxval, especially for multiply, divide and bit operations.
- Output verified: the output passed
pamfileand was written to a deliberate destination. - Failures handled safely: any failed temporary output was removed without overwriting the previous result.