Home / Alt manpages / ppmtoxpm(1)

  • ppmtoxpm(1)
  • User command
  • linux

Convert PPM Images to Portable XPM with ppmtoxpm

ppmtoxpm turns a PPM image into an XPM version 3 source file that any XPM library can load. You get predictable colour spelling and an optional transparency mask along the way. This guide uses Netpbm 11.5.2, installed from Debian's netpbm 2:11.05.02-1.1build1. Allow about 10 minutes if the input already exists; longer if you need to prepare or inspect a mask.

Before you start

You need a readable PPM file and the ppmtoxpm command. The output is text, not a rendered preview, written to standard output, so you choose the destination explicitly with shell redirection. No step below needs elevated privileges. Keep the input unchanged until you have checked the generated file.

Checkpoint

You are ready when the input path is known and the output path does not name a file you need to preserve.

1. Check the installed converter

Confirm which executable will run and record its Netpbm version. This catches the common trap of reading documentation for one installation while running another.

$ command -v ppmtoxpm
/usr/bin/ppmtoxpm
$ ppmtoxpm --version
ppmtoxpm: Using libnetpbm from Netpbm Version: Netpbm 11.5.2

The version output also includes build details on this installation. The man page accepts a minimum unique option abbreviation, double hyphens, and whitespace instead of the equals sign; full option names are clearer in scripts, so the examples here use them.

2. Convert the PPM to XPM

Replace the two placeholder paths. A single positional argument supplies the PPM; omit it and ppmtoxpm reads standard input instead. The command creates or replaces the output file, so do not point it at a valuable existing path until you have checked the result.

$ test -r /path/to/input.ppm
$ test ! -e /path/to/output.xpm
$ ppmtoxpm -name=input /path/to/input.ppm > /path/to/output.xpm
$ head -5 /path/to/output.xpm
/* XPM */
static char *input[] = {
/* width height ncolors chars_per_pixel */
"..."

The exact header name and palette depend on the image and its filename. The man page documents the input filename without its extension as the default identifier prefix, and noname for standard input. This Netpbm 11.5.2 build can preserve a supplied path in that identifier, so give the output a stable prefix when generated files feed into source code:

$ ppmtoxpm -name=logo /path/to/input.ppm > /path/to/logo.xpm
$ grep -m1 'static char' /path/to/logo.xpm
static char *logo[] = {

3. Choose portable colour names

Without extra options, the converter tries the system colour dictionary: a named colour when it finds one, hexadecimal RGB text otherwise. That makes for compact output, but a consumer may not have the same dictionary. Use -hexonly when the XPM must describe every colour directly:

$ ppmtoxpm -hexonly -name=logo /path/to/input.ppm > /path/to/logo-hex.xpm
$ grep -E ' c "#' /path/to/logo-hex.xpm | head
"a c #FF0000",
"b c #FFFFFF",

Hexadecimal component width follows the PPM maxval, using the shortest representation that can capture it. A low maxval can therefore produce one hexadecimal digit per RGB component, which some older readers mishandle. If compatibility with such a reader matters, raise the input depth first with pamdepth 255, then convert the resulting PPM:

$ pamdepth 255 /path/to/input.ppm > /tmp/input-255.ppm
$ ppmtoxpm -hexonly /tmp/input-255.ppm > /path/to/output.xpm

That creates a new temporary input and leaves the original alone. Remove the temporary file after checking the output with rm -- /tmp/input-255.ppm; do not remove a path you did not create.

4. Add transparency with a PGM mask

Transparency is opt-in. Supply a PGM file with exactly the same width and height as the PPM. Pixels whose mask value is at most half white become transparent; without a mask, every output pixel is opaque. ppmcolormask is one way to make a mask from a colour, but inspect its result before using it.

$ ppmtoxpm -hexonly -name=transparent -alphamask=/path/to/mask.pgm \
    /path/to/input.ppm > /path/to/transparent.xpm
$ head -5 /path/to/transparent.xpm
/* XPM */
static char *input[] = {

A mismatched mask is an input error, not a reason to force the conversion; fix the dimensions or generate a new mask. The transparency option also changes the colour-code count calculation, because one code is reserved for transparent pixels.

5. Verify before handing the file on

First check the file is non-empty and contains XPM markers. These checks do not prove an application will render it, but they catch a failed command or an accidental empty redirection.

$ test -s /path/to/output.xpm
$ grep -q '^/\* XPM \*/$' /path/to/output.xpm
$ grep -q 'static char' /path/to/output.xpm
$ wc -l -c /path/to/output.xpm
      42     987 /path/to/output.xpm

If a downstream X application rejects the file, compare the image dimensions and palette first. Try the -hexonly output to rule out colour-dictionary differences. If the problem appears only with transparency, repeat without -alphamask; that isolates the mask from the PPM conversion. If you need to discard an output you created, remove that exact output path only. The original PPM and mask are never changed by ppmtoxpm.

Done means

  • Version confirmed: ppmtoxpm --version identified the intended Netpbm installation.
  • Output valid: the XPM begins with an XPM marker and contains a generated C-style array.
  • Colours deliberate: you chose the default dictionary behaviour or used -hexonly on purpose.
  • Mask checked: any mask has the same dimensions as the PPM and was verified before use.
  • Sources untouched: the original image remains intact and the destination is the file you intended to create.