Convert GIF Images to PNM Safely with giftopnm
You will finish with a PNM version of a GIF, plus an optional PBM transparency mask when the GIF has transparency. Allow about ten minutes for a single image, longer if you need to inspect several frames or recover a damaged file.
The route
Jump straight to the step you need, or tick off Done means at the end.
This guide uses the giftopnm supplied by Netpbm 11.5.2 on this machine. You need the netpbm package, a readable GIF, and a directory where you can write the output. Conversion normally needs no elevated privileges. Do not use sudo just to read an image or write into your own working directory.
1. Check the installed command
Confirm the binary and package version before relying on an option in a script. These are read-only checks:
$ command -v giftopnm
/usr/bin/giftopnm
$ dpkg-query -W -f='${Package} ${Version}\n' netpbm
netpbm 2:11.05.02-1.1build1
$ giftopnm -version 2>&1
giftopnm: Using libnetpbm from Netpbm Version: Netpbm 11.5.2
The manual accepts either a filename argument or standard input. It also accepts long options with one or two hyphens, and whitespace can replace the equals sign. Use the full option names in scripts because they are easier to review.
2. Convert one GIF to a new PNM file
The simplest conversion writes the image to standard output. Redirect it to a new destination rather than overwriting a file you have not checked:
$ giftopnm /path/to/input.gif > /path/to/output.pnm
$ test -s /path/to/output.pnm && echo 'output is non-empty'
output is non-empty
$ file /path/to/output.pnm
/path/to/output.pnm: Netpbm image data, size 800 x 600, rawbits, pixmap
The exact file wording depends on the image. The format is chosen from the pixels: a black-and-white image becomes PBM, a grey-only image becomes PGM, and an image with other colours becomes PPM. The .pnm suffix is therefore a useful neutral name. Do not assume every GIF produces PPM.
Checkpoint: the command should exit successfully, the destination should be non-empty, and file should identify a Netpbm image with the expected dimensions. A successful exit does not prove that an image looks right, so open or otherwise inspect the PNM before deleting the original GIF.
3. Avoid accidental truncation
Shell redirection with > truncates an existing destination before giftopnm starts. If the destination matters, create a separate file and replace the old one only after checking it:
$ giftopnm /path/to/input.gif > /path/to/output.pnm.new
$ test -s /path/to/output.pnm.new
$ file /path/to/output.pnm.new
/path/to/output.pnm.new: Netpbm image data, size 800 x 600, rawbits, pixmap
$ mv /path/to/output.pnm.new /path/to/output.pnm
The final mv changes the destination name, so pause before it if the old output is still needed. If conversion fails, leave the original output alone and inspect the error. A partial .new file is not a valid replacement; remove it only after you have confirmed that you no longer need it.
4. Select frames from an animated GIF
A GIF stream normally contains one image, but an animated GIF can contain several. The default is image 1 only:
$ giftopnm --image=1 /path/to/animated.gif > /path/to/frame-1.pnm
$ giftopnm --image=all /path/to/animated.gif > /path/to/frames.pnm
--image=all writes a PNM stream containing multiple images. A program that reads only one PNM image may display just the first frame, so check the consumer's support before using the stream in a pipeline. For a particular later frame, use its sequence number, such as --image=3. The number is the image's position in the GIF stream, not a delay or timestamp.
With a single selected image, giftopnm still has to read and partly validate earlier images. That is why selecting frame 3 can fail even when frame 3 itself appears intact.
5. Preserve transparency as a separate mask
Without an alpha option, transparency in the GIF is discarded. Use --alphaout to write a PBM mask alongside the converted image:
$ giftopnm --alphaout=/path/to/transparency.pbm \
/path/to/input.gif > /path/to/image.pnm
$ file /path/to/image.pnm /path/to/transparency.pbm
/path/to/image.pnm: Netpbm image data, size 800 x 600, rawbits, pixmap
/path/to/transparency.pbm: Netpbm image data, size 800 x 600, rawbits, bitmap
In the mask, black means transparent and white means opaque. The mask has the same dimensions as the input. The option can also use - as its filename, but then the transparency mask uses standard output and the image itself is discarded. Avoid that form unless a downstream command explicitly expects the mask stream.
Keep the image and mask paired. If one conversion succeeds and the other destination is unusable, rerun into new names rather than guessing which file is complete. Netpbm's pamcomp can use transparency output in a later compositing workflow.
6. Handle damaged GIF input deliberately
By default, invalid GIF input makes giftopnm fail. Any output already written may be arbitrary and may not be valid PNM, so do not publish it merely because a destination file exists.
For a truncated or otherwise damaged file, --repair asks the program to salvage what it can:
$ giftopnm --repair /path/to/possibly-damaged.gif \
> /path/to/recovered.pnm
$ file /path/to/recovered.pnm
/path/to/recovered.pnm: Netpbm image data, size 800 x 600, rawbits, pixmap
Repair emits warnings. Pixels that cannot be determined are filled with one arbitrary colour for the remaining part of the image, so this is recovery, not verification. Compare the result with the source or obtain a fresh copy before treating it as trustworthy. Keep the damaged original for diagnosis.
7. Decide whether to read the whole stream
Normally, giftopnm reads to the end of the GIF stream, even after converting the requested image. That lets it validate trailing data, but it can waste time or fail because of an error after the frame you wanted.
--quitearly stops reading once the requested image has been converted. Use it only when you accept that trailing data will not be checked. It is unsuitable when the producer of a pipe expects the reader to consume the entire stream, and it has no effect with --image=all:
$ giftopnm --image=1 --quitearly /path/to/animated.gif \
> /path/to/first-frame.pnm
For ordinary files, leave this option out unless a known trailing-stream problem gives you a reason to use it. For a pipe, decide first whether the upstream process requires full consumption.
Done means
- The installed Netpbm version and input path were checked.
- The GIF was converted into a non-empty PBM, PGM or PPM result without overwriting a useful file.
- Animated input was handled with an explicit image selection when needed.
- Transparency was preserved as a PBM mask when the later workflow requires it.
- Damaged input was either rejected or explicitly marked as repaired and inspected.
- The output dimensions and visual result were checked before the original was removed.