The basics
What is a PFM file?
A Portable FloatMap is the simplest way to store an image whose pixels are floating-point numbers. It follows the spirit of the Netpbm PPM format: a few lines of text say what the image is, and the pixels follow with nothing in between. The difference is that each sample is a 32-bit float rather than a whole number from 0 to a maximum, so a pixel can hold 0.0001 or 5,000. That makes PFM a high-dynamic-range format, like Radiance HDR and OpenEXR, but with none of their packing or compression.
No standards body owns PFM. Its best-known description is a short page on Paul Debevec's website, and USC's HDRShop program used it. Netpbm added converters in April 2004 and documents a version of the format, but calls it unofficial: its manual says there are several similar formats known as PFM, none of them authoritatively documented. In practice the variants agree on almost everything except the row order (see below).
Where you'll meet PFM files:
- Computer vision. The Middlebury stereo benchmark distributes its ground-truth disparity maps as PFM, and expects results in the same format, so PFM is common in stereo-matching and depth-estimation code.
- HDR research and teaching. A program can write one with a
printfand a singlefwrite, with no library. - Pipelines and tests. As a lossless go-between for floating-point data, and as test input for image libraries.
Two different .pfm formats
A .pfm file in a fonts folder is almost certainly a Printer Font Metrics file, part of a PostScript Type 1 font on Windows. It has nothing to do with images. The section on fonts below explains how to tell them apart.
Anatomy
What's inside a PFM file
A PFM file is three lines of ASCII text, then the pixels as raw 4-byte floating-point numbers. Below is every byte of a 60-byte file we wrote for this page: 2 × 2 pixels, one of them brighter than white. ImageMagick, Netpbm and OpenImageIO all read it as the picture shown at the bottom. It isn't offered for download.
tiny.pfm: 2 × 2 pixels, colour, little-endian, 60 bytes
offset bytes part
0 50 46 0A "PF" + newline: colour
3 32 20 32 0A "2 2": width, height
7 2D 31 2E 30 0A "-1.0": little-endian, scale 1
12 00 00 00 00 00 00 00 00 00 00 00 00 bottom row, pixel 1
24 EC 51 38 3E EC 51 38 3E EC 51 38 3E bottom row, pixel 2
36 00 00 80 3F 00 00 00 3F 00 00 80 3E top row, pixel 1
48 00 00 80 40 00 00 00 40 00 00 80 3F top row, pixel 2
60 end of file
the picture, as (red, green, blue):
top row (1.0, 0.5, 0.25) (4.0, 2.0, 1.0)
bottom row (0.0, 0.0, 0.0) (0.18, 0.18, 0.18)- 1
50 46 0AThe identifier
PFmeans a colour image with three samples per pixel;Pf, with a lower-case f, a greyscale image with one. The case of one letter is the only difference, so a reader must compare both bytes exactly. - 2
32 20 32 0AWidth and height
Two positive decimal integers separated by a space: 2 pixels wide, 2 rows high. Unlike PPM, there's no maximum value line: floats need none.
- 3
2D 31 2E 30 0AScale and byte order
A non-zero decimal number. Its sign gives the byte order of the floats: negative means little-endian (as on x86 and ARM computers), positive means big-endian. Its absolute value is a scale factor that, according to Netpbm, tells the units of the samples. Most files use
-1.0or1.0. - 4
00 00 00 00 …The bottom row comes first
The pixel data starts with the bottom row of the image and works upwards, left to right within each row. This is the opposite of PPM and most other formats, and the commonest cause of upside-down PFM images.
- 5
EC 51 38 3EA 32-bit float
Each sample is an IEEE 754 single-precision number. Read little-endian, these bytes are
0x3E3851EC: 0.18, the value of a mid-grey card in linear light. Three of them make one grey pixel. - 6
00 00 80 3F1.0, full brightness
0x3F800000is exactly 1.0. In an 8-bit image, this would be the brightest value possible. - 7
00 00 80 40Brighter than white
0x40800000is 4.0, four times brighter than 1.0. Nothing caps the values, which is what makes PFM a high-dynamic-range format. Negative numbers are possible too. - 8
60No trailer
The file ends after the last sample: 12 header bytes plus 2 × 2 pixels × 3 samples × 4 bytes = 60. There's no compression, metadata or checksum.
Under the hood
The header: three lines and a sign trick
PF
768 512
-1.0| Line | Contents | Notes |
|---|---|---|
| 1 | PF or Pf | Colour (3 floats per pixel) or greyscale (1 float per pixel) |
| 2 | Width and height | Two positive decimal integers separated by a space |
| 3 | Scale | A non-zero decimal number: the sign sets the byte order, the absolute value is the scale factor |
Each line ends with one whitespace character, normally a newline (0A), and the pixel data starts straight after the newline that ends line 3. Unlike PPM, the format doesn't allow comments.
Putting the byte order in the sign of a number is the format's one clever idea. A program that writes floats straight from memory writes -1.0 on a little-endian computer and 1.0 on a big-endian one, and the reader swaps bytes only if its own byte order differs. Tools differ in what they choose: in our tests on an x86 Linux machine, Netpbm's pamtopfm wrote little-endian files (its default is the computer's own byte order), while ImageMagick 6 wrote big-endian ones.
The scale factor is more loosely defined. Netpbm says it gives the units of the samples; Paul Bourke's description of the format treats the same number as the pixel aspect ratio. Most software writes 1 and ignores the value on reading, so don't rely on it to carry information.
Quirks
Rows from the bottom up
Both main descriptions of PFM say the rows are stored from the bottom of the image to the top, left to right within each row. That's the opposite of PPM, so code adapted from a PPM writer produces upside-down PFM files unless it reverses the rows.
- Netpbm notes that a PFM variant it attributes to Adobe orders the rows top to bottom instead, and suggests flipping the image if one comes out upside down.
- There's nothing in the file to say which convention a writer followed. If a PFM looks upside down, it probably is: flip it once and check against a reference image.
# flip a PFM vertically, keeping the float values
oiiotool upside-down.pfm --flip -o fixed.pfmComparison
PFM vs PPM, Radiance HDR and OpenEXR
| PFM | PPM | Radiance HDR | OpenEXR | |
|---|---|---|---|---|
| Bytes per RGB pixel, uncompressed | 12 | 3 or 6 | 4 | 6 (half) or 12 (float) |
| Values | Any 32-bit float, including negative | Whole numbers from 0 to maxval | Zero or positive, about 1% precision | Half or full floats, or integers |
| Alpha | No | No (PAM has it) | No | Yes |
| Compression | None | None | Run-length | Many, lossless and lossy |
| Metadata | None | Comments | Text header | Any attributes |
| Best for | Research, tests, disparity and depth maps | Simple 8- or 16-bit images | HDRI lighting maps | Film, VFX and rendering |
PFM keeps full 32-bit precision and is trivial to read, but the files are large: a 1920 × 1080 colour PFM is about 24.9 MB, twice the size of a half-float EXR before compression and four times an 8-bit PPM. Use it inside a pipeline or for data where exact values matter, and EXR for anything you store or exchange.
Identify
Printer Font Metrics: the other .pfm
On Windows, a PostScript Type 1 font usually comes as a pair: a .pfb file (PostScript Font Binary) with the glyph outlines, and a .pfm file with the font metrics: the character widths and other measurements that Windows and printer drivers use to lay out text. The two must stay together. Older fonts sometimes came as .pfb, .afm and .inf files instead, and installing them produced the .pfm.
| Portable FloatMap | Printer Font Metrics | |
|---|---|---|
| First bytes | 50 46 or 50 66 (PF or Pf), then a newline | 00 01: the version field, 0x0100, little-endian |
| Readable start | Three short lines of text, then binary data | Binary from the first byte |
| Found next to | Other images, or render and vision output | A .pfb file of the same name, in a fonts folder |
| Opens with | Image tools | Installed as a font, with its .pfb |
To check, open the file in a text editor or run head -c 16 file.pfm | xxd. If it starts with PF or Pf it's an image; if the first two bytes are 00 01, it's a font. Type 1 fonts are a legacy format: for new work, use an OpenType font.
How to
How to open and convert a PFM file
- ImageMagick reads and writes colour and greyscale PFM. Builds without HDRI support, such as the ImageMagick 6 packages of many Linux distributions, clip values above 1.0 to white when they read the file.
- Netpbm:
pfmtopamconverts PFM to an ordinary Netpbm image andpamtopfmgoes the other way, with-endian=littleorbigto choose the byte order. - OpenImageIO (
pip install OpenImageIO) reads and writes PFM with full float values, and converts it to EXR or HDR without losing range. - GIMP can export images as PFM.
- Pillow (Python) reads and writes greyscale PFM (
Pf) as 32-bit float images (modeF). It doesn't read colour PFM, and in our test with Pillow 12 an RGB image saved with a.pfmname came out as an 8-bit PPM file. - Browsers, Windows Photos and macOS Preview don't open PFM.
# PFM to half-float EXR, keeping the HDR values
oiiotool input.pfm -d half -o output.exr
# EXR or HDR back to PFM
oiiotool input.exr -o output.pfm
# PNG to PFM with Netpbm (values 0 to 1; grey PNGs become Pf)
pngtopam input.png | pamtopfm > output.pfm
# PFM to a Netpbm image with whole numbers
pfmtopam input.pfm > output.pamReading one yourself takes a few lines: split the header on whitespace, pick <f4 or >f4 from the sign of the scale, read width × height × channels floats, and reverse the order of the rows. In Python with NumPy that's np.frombuffer(data, dtype).reshape(h, w, c)[::-1].
Troubleshooting
Common PFM problems
- The image is upside down. The writer or the reader got the row order wrong. Flip it vertically.
- The image is random noise or a few huge values. The floats were read in the wrong byte order: the reader ignored the sign of the scale line. Swap every group of 4 bytes.
- It's black, or flat white. The values are linear light and may be far outside 0 to 1. Adjust the exposure in an HDR viewer, or scale the values before converting to an 8-bit format.
- Bright areas go strange after converting to PNG. Values above 1.0 can't fit in 8 bits: most tools clip them to white, but some converters wrap them around into wrong colours. Scale the image down first.
- Pillow says "cannot identify image file". It's a colour (
PF) file, which Pillow doesn't read. Use OpenImageIO, ImageMagick or a few lines of NumPy. - Nothing opens it at all. Look at the first two bytes.
00 01means it's a font metrics file, not an image.
Security
Is a PFM file safe?
A PFM file is a header and numbers, nothing that runs. As with PPM, the risk is in readers that trust the header: a few bytes can claim an image of 100,000 × 100,000 pixels, which at 12 bytes per pixel is 120 GB. Check the dimensions against a limit, and the file length against width × height × channels × 4, before allocating memory. Values can also be infinities or NaN (not a number), which can break code that sums or divides them.
Sample files
There are no sample PFM files on this page yet. To make one for testing, convert an image with Netpbm (pngtopam input.png | pamtopfm > output.pfm), OpenImageIO (oiiotool input.exr -o output.pfm) or ImageMagick (convert input.png output.pfm).
Put it online
Have a PFM file? Give it a link.
Drop a Portable FloatMap on 99helpers and it gets its own web address. Browsers can't display PFM, so anyone who opens the link downloads the file, ready for an HDR viewer, a vision pipeline or an image library.
Questions
PFM files, frequently asked
What is a .pfm file?
Usually a Portable FloatMap: an uncompressed high-dynamic-range image with a three-line text header and 32-bit floating-point pixels. In a fonts folder, a .pfm is instead the Printer Font Metrics file of a Windows Type 1 font.
How do I open a PFM image?
Use ImageMagick, OpenImageIO, Netpbm or GIMP, or convert it to EXR or PNG first. Pillow reads only greyscale PFM files. Browsers and the built-in photo viewers on Windows and macOS can't open it.
What's the difference between PF and Pf?
PF is a colour image with three floats (red, green, blue) per pixel; Pf is greyscale, with one float per pixel.
Why is my PFM image upside down?
PFM stores rows from the bottom of the image to the top, the opposite of most formats, and some programs get it wrong. Flip the image vertically, for example with oiiotool in.pfm --flip -o out.pfm.
What does -1.0 in a PFM header mean?
The pixels are little-endian. A negative number on the third line means little-endian floats, a positive one big-endian. The absolute value, usually 1, is a scale factor.
Is PFM the same as PPM?
No, but it's modelled on it. PPM stores whole numbers up to a maximum value, top row first; PFM stores 32-bit floats with no maximum, bottom row first. Netpbm converts between them with pfmtopam and pamtopfm.
Is a .pfm file a font?
It can be. If it sits next to a .pfb file and starts with the bytes 00 01, it's the metrics half of a PostScript Type 1 font. If it starts with PF or Pf, it's an image.
Related formats
Other file types explained
Keep going
Related
Sources
- Paul Debevec: PFM Portable FloatMap image format
- Netpbm: PFM format description (manual page)
- Netpbm: pamtopfm manual page
- Paul Bourke: PFM, an unofficial PBM format for HDR images
- Middlebury Stereo Evaluation: submission instructions (PFM disparities)
- The National Archives (PRONOM): Adobe PostScript Font Metrics file
Last reviewed 27 October 2026.