Jonathan. Frech’s WebBlog

BMP Implementation in C (#182)

Jonathan Frech

C is one cool and important lan­guage. CPython and Unix are based on it, the Mars Curiosity rover is run by it and even the GCC C compiler itself is written in C. However, as C is some years old by now, it lacks a lot of higher-level features most modern languages possess, being more down to the silicon, as the cool kids say. Concepts like pointer manipulation, bit fiddling and its string im­ple­men­ta­tion — just to name a few — are at times cumbersome, insecure and error-prone; nevertheless is there a certain appeal to writ­ing in C.

Being on­ly one ab­strac­tion level away from Assembly — which itself is on­ly one ab­strac­tion level above raw byte code — and having access to file manipulation down to the individual bit, I set out to write a Microsoft Bitmap (.bmp) im­ple­men­ta­tion in pure C. As Microsoft’s stan­dard for this image file format is quite feature-rich, I decided to focus on the bare minimum — a bitmap with 24-bit color depth (three colors, one byte per), one color plane, no compression, no palette and 300 DPI.
My Bitmap im­ple­men­ta­tion supports both reading and writ­ing .bmp files, as well as generating some test images — including a Mandelbrot set fractal renderer, of course. Implementation source code can be downloaded (bmp.c) or seen below.

A Mandelbrot set fractal rendering.

Implementing a file format requires knowing its specification. Although it is not the best article I have ever seen, this Wikipedia article gave me some insights. The missing pieces were reverse engineered using Adobe Photoshop CC and the HxD hex editor.
The following is a snippet of the im­ple­men­ta­tion’s savebmp function (full source code listed below). It illustrates the Bitmap file’s byte layout on­ly showing the file header, omitting a lengthy data part concatenated to the header. S, K, W, H and B are all byte arrays of length four (little-endian format) which contain the file’s total size, the bitmap data offset (which is con­stant, since the header is always exactly 54 bytes large), the image’s dimensions (horizontal and vertical) and the bitmap data’s section’s size, respectively.

/*  bitmap file header  */
0x42, 0x4D,             // BM
S[0], S[1], S[2], S[3], // file size
0x00, 0x00, 0x00, 0x00, // unused
K[0], K[1], K[2], K[3], // bitmap data offset
/*      DIB header      */
0x28, 0x00, 0x00, 0x00, // DIB size
W[0], W[1], W[2], W[3], // pixel width
H[0], H[1], H[2], H[3], // pixel height
0x01, 0x00,             // one color plane
0x18, 0x00,             // 24 bit color depth
0x00, 0x00, 0x00, 0x00, // no compression
B[0], B[1], B[2], B[3], // bitmap data size
0x23, 0x2E, 0x00, 0x00, // 300 DPI (horizontal)
0x23, 0x2E, 0x00, 0x00, // 300 DPI (vertical)
0x00, 0x00, 0x00, 0x00, // no palette
0x00, 0x00, 0x00, 0x00  // color importance
/*  data bytes follow   */

Key bytes to note are the first two identifying the file type (the ASCII-encoded letters BM) and the DPI bytes, 0x23, 0x2E, which indicate 0x00002E23 = 11811 pixels per meter in both the horizontal and vertical direction. Converting from pixels per meter to dots per inch results in 11811 / (1 meter / 1 inch) = 11811 * 127 / 5000 = 300 DPI (roughly).
Most values are represented using four bytes in little-endian format. Translating an 32-bit integer into four little-endian formatted bytes can be achieved as follows.

/* unsigned 32-bit integer */
unsigned int n = 0b10100100010000100000100000010000;
/*                 < m sig><sm sig><sl sig>< l sig> */

/* byte (unsigned char) array of size four */
unsigned char N[4] = {
    (n & 0xff000000) >>  0, // most significant byte
    (n & 0x00ff0000) >>  8, // second most significant byte
    (n & 0x0000ff00) >> 16, // second least significant byte
    (n & 0x000000ff) >> 24  // least significant byte
};

Other than rendering a fractal, I also im­ple­ment­ed three nested loops which output an image containing every possible color exactly once ((2**8)**3 = 16777216 pixels in total).

All sixteen million colors in one image.

An image’s data type is im­ple­ment­ed as a struct image which contains three variables — width and height, two integers specifying the image’s dimensions, and *px, a pointer to an one-di­men­sion­al integer array of size width*height which holds the en­tire image data.
Defined functions are listed ahead.

Images shown in this post were converted to .png files as WordPress does not allow .bmp file uploads; the raw pixel data should, however, be identical.⁠¹

Source code: bmp-im­ple­men­ta­tion-in-c_bmp.c


[1][2020-08-06] On the new blog, however, I can upload them without a hassle: bmp-im­ple­men­ta­tion-in-c_frc.bmp, bmp-im­ple­men­ta­tion-in-c_all-sixteen-million-colors.bmp.