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 0×42 0x4D
- Four bytes, representing the size of the BMP file in bytes.
- Two bytes reserved: these can safely be 0×00 0×00.
- Two more bytes reserved: these can also be 0×00 0×00.
- Four bytes for the offset address of the pixel data.
(If using BITMAPCOREHEADER, this is 0x1A 0×00.)
The BITMAPCOREHEADER is next, and also relatively simple:
- Four bytes for the size of the header (14 bytes, so 0x0E 0×00 0×00 0×00).
- 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 0×01 0×00); and
- Two bytes for the bits per pixel (0×18 0×00 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” (0×42 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 0×00 0×00 0×00 0×00 to the file, for the two reserved fields.
- Write 0x1A 0×00 (representing the 26-byte offset for the start of data.)
- Write 0x0C 0×00 0×00 0×00 (representing the DIB header size.)
- Write XSIZE in two-byte little-endian hex.
- Write YSIZE in two-byte little-endian hex.
- Write 0×01 0×00 for the number of pixel planes;
- Write 0×18 0×00 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.