Convert PBM Images to MRF and Back with Netpbm

MRF squeezes a black-and-white image down small, and Netpbm's pbmtomrf and mrftopbm are the only two commands that speak it. This walks through converting a bilevel PBM into MRF, converting it back, and checking the dimensions without touching the source. Allow about ten minutes if Netpbm is already installed.

This follows Netpbm 11.05.02, packaged here as 2:11.05.02-1.1build1. That package provides pbmtomrf and mrftopbm; mrf(1) is the format specification, not a command you run. No elevated privileges are needed when the input and output live in a directory you can write.

1. Check the two conversion commands

$ command -v pbmtomrf mrftopbm
/usr/bin/pbmtomrf
/usr/bin/mrftopbm
$ dpkg-query -W -f='${Package} ${Version}\n' netpbm
netpbm 2:11.05.02-1.1build1

If either command is missing, stop and install or repair Netpbm through your normal package-management process. Do not reach for sudo just because the format documentation mentions system paths.

Checkpoint: both command paths are printed, and the version is the one you intend to document or deploy.

2. Prepare a small PBM input

MRF can only represent one-bit black-and-white data. A PBM plain-text image makes a convenient, controlled test; create it in a working directory rather than touching an existing image:

$ mkdir -p ~/mrf-work
$ cat > ~/mrf-work/input.pbm <<'EOF'
P1
8 4
0 0 0 0 0 0 0 0
0 1 1 0 0 1 1 0
0 1 1 0 0 1 1 0
0 0 0 0 0 0 0 0
EOF

The header declares an 8 by 4 bitmap. In PBM, 1 is black and 0 is white. This file is only a test fixture: if you already have a PBM, use its path instead and keep the original unchanged.

3. Compress the PBM as MRF

pbmtomrf reads the named PBM and writes MRF to standard output, so redirect it to a new filename:

$ pbmtomrf ~/mrf-work/input.pbm > ~/mrf-work/image.mrf
$ test -s ~/mrf-work/image.mrf && echo 'MRF output is non-empty'
MRF output is non-empty
$ file ~/mrf-work/image.mrf
/home/you/mrf-work/image.mrf: data

That generic file description is normal for MRF. The header starts with the ASCII magic number MRF1, followed by big-endian 32-bit width and height fields and a reserved zero byte. You can look at those bytes without editing the file:

$ od -An -tx1 -N13 ~/mrf-work/image.mrf
 4d 52 46 31 00 00 00 08 00 00 00 04 00

The first four bytes identify MRF, the next eight encode 8 and 4, and byte 12 is reserved. Treat the rest as compressed data, not text.

4. Convert MRF back to PBM

mrftopbm also writes to standard output. Send it to a different destination so the original PBM stays around for comparison:

$ mrftopbm ~/mrf-work/image.mrf > ~/mrf-work/round-trip.pbm
$ file ~/mrf-work/round-trip.pbm
/home/you/mrf-work/round-trip.pbm: Netpbm image data, size = 8 x 4, rawbits, bitmap
$ od -An -c -N8 ~/mrf-work/round-trip.pbm
   P   4  \n   8       4  \n

The result uses the binary P4 encoding, so do not run a text diff against it. What matters is the P4 magic number and the expected dimensions; use a PBM-aware viewer or a Netpbm comparison tool if you need to check the image itself.

Checkpoint: round-trip.pbm reports 8 by 4 and the source files still exist.

5. Understand edge padding before reaching for -a

MRF processes images in 64 by 64 squares. An image smaller than that grid gets encoded in a larger square, and the extra area is undefined. Normally mrftopbm drops those unseen edges and returns just the stored dimensions.

The -a option includes the encoded edges in the output PBM, which is useful for debugging a compressor, not for ordinary conversion:

$ mrftopbm -a ~/mrf-work/image.mrf > ~/mrf-work/with-edges.pbm
$ file ~/mrf-work/with-edges.pbm
/home/you/mrf-work/with-edges.pbm: Netpbm image data, size = 64 x 64, rawbits, bitmap

For this 8 by 4 test image, the expanded output shows the 64 by 64 processing square in full. Its extra pixels have no defined visual meaning. Do not use -a as a resize operation, or as a way to recover content outside the original bounds.

6. Avoid the redirection trap

Warning: shell redirection with > truncates its destination before the converter even starts. Never point it at the only copy of an input, or at an output you might need to recover:

$ pbmtomrf ~/mrf-work/input.pbm > ~/mrf-work/image.mrf.new
$ test -s ~/mrf-work/image.mrf.new
$ mv ~/mrf-work/image.mrf.new ~/mrf-work/image.mrf

That final mv replaces the old MRF only once a non-empty candidate exists. If conversion fails, inspect the error and remove the specifically named image.mrf.new once you are sure it is disposable. Keep the PBM source until the round-trip has passed your visual or automated check: neither conversion modifies its input, and neither needs a service restart.

Done means