BMP file format

Since uncompressed bitmaps are a one-to-one representation of pixels in an image, they are one of the simplest formats to generate, if you are writing your own code. Here is a description (plus FreeBASIC code, which works well enough as pseudocode) of how to output a .bmp file, given an array of pixels.

In order to make the process as straightforward as possible, I will make several (hopefully reasonable) assumptions:

  • The image exists in memory, in a format (an array, for instance) which can be easily read in random-access order;
  • A color depth of 24 bits is used (eight bits each for Red, Green, and Blue);
  • BITMAPCOREHEADER (the simplest header) is used; and
  • The height and width of the image are reasonable and known.
    (I will call these variables XSIZE and YSIZE.)

Values given here are in hexadecimal. All multi-byte values in BMP files are little-endian.

Bitmap files consist of three parts:

  • The bitmap header;
  • The DIB header; and
  • The pixel data array.

The bitmap header is straightforward enough:

  • Two bytes to denote a bitmap file: ASCII “BM”, or hex 0x42 0x4D
  • Four bytes, representing the size of the BMP file in bytes.
  • Two bytes reserved: these can safely be 0x00 0x00.
  • Two more bytes reserved: these can also be 0x00 0x00.
  • Four bytes for the offset address of the pixel data.
    (If using BITMAPCOREHEADER, this is 0x1A 0x00.)

The BITMAPCOREHEADER is next, and also relatively simple:

  • Four bytes for the size of the header (14 bytes, so 0x0E 0x00 0x00 0x00).
  • Two bytes for the image width in pixels;
  • Two bytes for the image height in pixels;
  • Two bytes for the number of pixel planes (must be 0x01 0x00); and
  • Two bytes for the bits per pixel (0x18 0x00 in our 24-bit example.)

The last structure is the bitmap data itself. This is three bytes per pixel, with each row padded to the next multiple of four bytes, as needed. Each pixel is in BBGGRR order.

We now have all of the pieces of information we need to create the bitmap file…

  • Output ASCII “BM” (0x42 0x4D)to the file
  • Calculate the size of the file:
  • – 14 bytes for the bitmap header, plus
  • – 12 bytes for the DIB header, plus
  • – The number of rows (image height) times the row size in bytes.
    (The row size is the image width, times three, rounded up to
    the next multiple of four, if needed.)
  • Write this figure to the file, in little-endian hex, using four bytes.
  • Write 0x00 0x00 0x00 0x00 to the file, for the two reserved fields.
  • Write 0x1A 0x00 (representing the 26-byte offset for the start of data.)
  • Write 0x0C 0x00 0x00 0x00 (representing the DIB header size.)
  • Write XSIZE in two-byte little-endian hex.
  • Write YSIZE in two-byte little-endian hex.
  • Write 0x01 0x00 for the number of pixel planes;
  • Write 0x18 0x00 to represent 24 bits per pixel.
  • Loop over the number of rows (YSIZE) in the image:
  • – For each pixel in that row, write its image value in little-endian hex (BBGGRR)
  • – At the end of the row, pad it with zero to three extra bytes to make the number of bytes in the row a multiple of four.
  • Close the file. You’re done!

Here is an example in FreeBASIC, which produces a simple 3×3 bitmap.



This entry was posted in BASIC, Coding, HOW-TO. Bookmark the permalink.

Leave a Reply