64-bit BMP image files

BMP is essentially the native bitmap image file format of Microsoft Windows. BMP color depths up to 32 bits per pixel are pretty well standardized, but there is some mystery about higher bit depths. BMP has always been documented in a haphazard way, without a formal specification.

As the developer of Bmpsuite, a program that generates a set of sample BMP files, I’ve been derelict in my duty to figure out 64-bit BMP files. Only recently did I finally add a 64-bit BMP file to Bmpsuite.

In this post, I’ll go over what I think I know about the simplest form of 64-bit BMP. There may well be more to these bit-depth-higher-than-32 BMPs than this, and if someone else wants to investigate, that would be great.

The main documentation I used is “Windows Imaging Component: Native Pixel Formats Overview”. It may be found here.

Many nonstandard extensions of BMP have been used by various applications, but 64-bit images might have to be considered to be reasonably standard. They’re supported by Windows Explorer’s previews in at least Windows 10–11 (which alone should be sufficient), by some Microsoft applications, and some third-party applications that use Windows components.


A BMP file starts with a 14-byte structure named “BITMAPFILEHEADER”. You can do a search for Microsoft’s documentation about it.

Next comes a structure named “BITMAPINFOHEADER”, which is usually 40 bytes. You can do a search for Microsoft’s documentation about it.

For the format I’m covering here, the image pixels come next, at offset 54, and continue to the end of the file.

Here is a hex dump of the bytes making up a simple 2×2 64-bit BMP file (downloadable here: bmp-64bit.zip):

BITMAPFILEHEADER:
42 4D 56 00 00 00 00 00 00 00 36 00 00 00

BITMAPINFOHEADER:
28 00 00 00 02 00 00 00 02 00 00 00 01 00 40 00
00 00 00 00 00 FE 00 00 13 0B 00 00 13 0B 00 00
00 00 00 00 00 00 00 00

Pixels:
00 00 00 00 00 20 00 20 00 20 00 00 00 00 00 20
D9 06 D9 06 D9 06 00 20 00 00 00 00 00 00 00 00

Referring to the standard field names, a simple 64-bit image has the following characteristics:

  • biSize is 40.
  • biHeight is a positive number.
  • biBitCount is 64.
  • biCompression is 0 (BI_RGB).
  • biClrUsed and biClrImportant are 0.

Each pixel is stored as 8 contiguous bytes.

Each row is stored contiguously as biWidth pixels, ordered from left to right.

(Each row of a BMP image is normally padded to a multiple of 4 bytes, but in this case there is never a need for row padding.)

Rows are stored from bottom up.

Each pixel is made of four samples. Each sample is a 16-bit value (see below), least-significant byte first.

The sample order is blue, green, red, alpha.

As in most formats, alpha is unassociated. Low values are more transparent; high values are more opaque.

Important: The color (non-alpha) samples use a linear color space. It most cases, to use this format, you must translate these sample values to or from the standard sRGB color space. I won’t give the sRGB formula here, but you can easily look it up. Note that you should not translate the alpha sample to/from sRGB.

The samples use a fixed point format, described as “s2.13: sign bit, two integer bits, and thirteen fractional bits.” What this boils down to is that, for samples in the normal brightness range, you can interpret each sample as an integer, and the normal range will be from 0 to 8192, inclusive. For example, a sample having the normal maximum brightness would have value 8192, or 0x2000, which is encoded as the bytes 0x00 0x20.

Another example: In my sample image above, medium-gray samples are encoded as 0xD9 0x06, or 0x06D9, which is decimal 1753. Dividing by 8192 yields 0.213989. Converting that from linear to sRGB gives about 0.5000. Scaling that to the range [0–255] gives 127.5, so we expect it to be rendered as gray shade 127 or 128 on a typical computer monitor.

I have not investigated sample values outside the normal range. Such values would be used for high dynamic range images.


Here’s a zoomed-in screenshot of how this image is displayed by Windows Explorer on my computer:

The gray pixel (above the red pixel) has value 127, as expected.

Leave a comment