Tuesday, April 7, 2015

Exploring BMP format

Let's decode bitmap image file. Just because it's simple and I want to dig into something. And because BMP is relatively easy.

BMP file structure will vary a little depending on how much bits per pixel are used and whether or not there are color tables in file. So I prefer to simplify the decoding process. Let's say we have a small 5x4 pixel, 24 bits per color image (Windows bitmap image). And it looks like this (this one is .png and rescaled, the original image is available for download at the end of this topic):

Because the file is very small we can easily open it with hex editor and take a good look at the structure:

Offset 000102030405060708090A0B0C0D0E0F
00000000 424D7600000000000000360000002800
00000010 00000500000004000000010018000000
00000020 00004000000000000000000000000000
00000030 000000000000000000FFFFFF000000FF
00000040 FFFF00000000FFFFFF000000FFFFFF00
00000050 0000FFFFFF00000000FFFFFF000000FF
00000060 FFFF00000000FFFFFF000000FFFFFF00
00000070 0000FFFFFF00

In general bitmap file structure will look like this:

Green blocks are optional. In case of our image we have only mandatory blocks. So lets take a closer look on those.

Bitmap File Header is 14 bytes long. In our case file header looks like this:

42 4D - BM (two characters, always BM)
76 00 00 00 - Size of file in bytes (118 bytes, least-significant byte first)
00 00 00 00 - Reserved
36 00 00 00 - Offset of Pixel Array

Next is DIB Header. Its length and structure can vary and it contains specific information about the image. There are few types of DIB Headers, but in our case it is BITMAPINFOHEADER- 40 bytes length. And here it is:

28 00 00 00 - Header size (40 bytes)
05 00 00 00 - Image width (5 px)
04 00 00 00 - Image height(4 px)
01 00 - Number of color planes (BMP file always contain only one color plane)
18 00 - Bits per pixel (24)
00 00 00 00 - Compression method (no compression here)
40 00 00 00 - Size of bitmap data (64 bytes in Pixel Array)
00 00 00 00 - Horizontal resolution
00 00 00 00 - Vertical resolution
00 00 00 00 - Number of colors in the image
00 00 00 00 - Minimum number of important colors

Next we have Pixel Array and we have already decoded the header and know exactly where array starts. Its offset was 00 00 00 36, So here it is:

00 00 00 FF FF FF 00 00 00 FF FF FF 00 00 00 00
FF FF FF 00 00 00 FF FF FF 00 00 00 FF FF FF 00
00 00 00 FF FF FF 00 00 00 FF FF FF 00 00 00 00
FF FF FF 00 00 00 FF FF FF 00 00 00 FF FF FF 00

What's important to know about pixels is that they are packed in rows and each row is a multiple of four bytes. Row size can be calculated based on information in DIB Header:

RowSize = ((BitsPerPixel * ImageWidth + 31)/32)*4

In our case:

(24 * 5 + 31)/32 = 4.71875 = 4 (round up to the lower value)

4 * 4 = 16 - we have 16 byte row size

Now lets take a look at one particular pixel row:

00 00 00 FF FF FF 00 00 00 FF FF FF 00 00 00 00

We have 24 bits per pixel which means 3 bytes. So amount of pixels per row will be RowSize/3 = 16 / 3 = 5 (round up to lower value)

Basically, to read a pixel from this row means to read 3 consecutive bytes. And to read the whole row you need to read (in this case) 5 pixels from it. And the rest of the bits in the row will be padding bits which supposed to be skipped. One more thing to notice - rows are stored upside-down, so the first row you read is the last row of the image.

Now lets move on topixel format. Our image has two colors - black and white. Which is obvious if you look at the image :) or at pixel data: 00 00 00 - is black, FF FF FF is white.

3 bytes of pixel data represent Blue, Green and Red color components. If it was 4 bytes per pixel it would be Blue, Green, Red, Alpha. Color components stored in this particular order - BGR, red for example would be stored as 00 00 FF.

There is much more to know about bmp format. Most of it can be found here. There is a list of bmp related books there as well.

And here is the bmp image which was used in this article.

No comments :

Post a Comment