----- |n| -------------------------------------\ \||\ | | _ | \ \\ | |/ / Bitmap Image Format | _\_\\_|_| / by Riftor | |__________| | | | riftor@g615.co.uk | | | | | | www.g615.co.uk/riftor/ | | | www.illuminus.org.uk | |__________| | | |-----------------------------------------------| | Understanding the BMP File Structure | \-----------------------------------------------/ ================================================== (1-1) Contents ================================================== Overview 1). Understanding the BMP file structure 1-1). Contents 1-2). Intro 1-3). The 4 Fold Structure 1-3-1). BITMAPFILEHEADER in depth 1-3-2). BITMAPINFOHEADER in depth 1-3-3). RGBSQUAD in depth 1-3-4). BYTE in depth 1-4). Structure Recap/Overview ================================================== (1-2) Intro ================================================== The bitmap file format is an OS/2 and Windows image file, that uses a system of raterised data (pure image data) often in an uncompressed form (a bit.. map!) or sometimes in a loss-less form of encoding to decrease the file size. The sections on what is on offer can be seen in the contents (1-1). Throughout these articles I will use Microsoft's Paint for Bitmap examplse. BMP refers to bitmap and vice versa. Knowledge Requisites: For section 1, some knowledge of hexadecimal would really help, and some knowledge of how to use MS Paint or any hex editor/dumper. All numbers prefixed with 0x are hexadecimal numbers, unless I explicitly state they are without 0x in front. All hex dumps use hex values. Anyway lets get on with it. An application written by me that processes a bitmap header can be found at http://www.g615.co.uk/riftor/bmpheader.shtml Supplementary material (sample bmps and hex dumps) for this tutorial can be found at http://www.g615.co.uk/riftor/bmpstructure-supp.zip ================================================== 1-3 The 4 fold Structure ================================================== The file structure of BMPs (bitmaps), as far as I know, has remained relatively unchanged for a while now, which is useful for us, and also is quite an easy one to read as image files concern thanks to its small header structure, lack of compression and generally easy to grasp ideas. Let's start by looking at the main overview of the structure:- BITMAPFILEHEADER BITMAPINFOHEADER RGBQUAD BYTE BITMAPFILEHEADER is the only structure here that you can always be sure of the size of, and that is 14 bytes in length. This structure maps out some basic details of the file; what type of file it is, the size of the file ad the start position of the structure BYTE. BITMAPINFOHEADER is *usually* 40 bytes in length, but don't worry, the start of this structure defines its own length, so you can easily find out. This contains values to do with the dimensions of the BMP, the type of BMP, the colours used and a few other things. RGBQUAD is a colour table. The presence of this structure depends on the type of bitmap. When I say types of bitmaps, I mean the colour depth. If you load up MS Paint and click Save, you will see a "Save as Type" drop down box underneath the file name box. This will contain entries such as "Monochrome Bitmap","16 color bitmap","256 color bitmap",and maybe "16 bit Bitmap","24-bit Bitmap" and maybe "32-bit Bitmap". Monochrome, 16 and 256 colour bitmaps all have the RGBQUAD present, it is a basic colour palette and it reduces the size of these smaller colour bitmaps as less data is needed for small colours anyway. BYTE this is the structure that holds the image data. ================================================== (1-3-1) BITMAPFILEHEADER in depth ================================================== ------------------------------------------------------------------------ 0000: 42 4d 66 00 00 00 00 00 00 00 36 00 00 00 28 00 BMf 6 ( 0010: 00 00 04 00 00 00 04 00 00 00 01 00 18 00 00 00     0020: 00 00 30 00 00 00 c4 0e 00 00 c4 0e 00 00 00 00 0   0030: 00 00 00 00 00 00 c5 82 30 ee de 91 c7 a9 1f c5 ł0ޑǩ 0040: 82 30 c7 a9 1f 84 65 2b c5 82 30 c7 a9 1f ee de 0ǩe+ł0ǩ 0050: 91 c5 82 30 84 65 2b ee de 91 c5 82 30 c7 a9 1f ł0e+ޑł0ǩ 0060: ee de 91 c5 82 30 ޑł0 ------------------------------------------------------------------------ Above is the Hex dump of foo4.bmp (look at foo4.txt for a breakdown of this and the above hex dump). We are going to look at the BITMAPFILEHEADER in this section, and as I mentioned earlier, this structure is 14 bytes in length, and it starts at the start of the file at offset 0000 0000: 42 4d 66 00 00 00 00 00 00 00 36 offset size name 0x0 2 bfType 0x2 4 bfSize 0x6 2 bfReserved1 0x8 2 bfReserved2 0x10 4 bfOffBits [note: the size is in bytes] bfType will always be BM, if not, your not looking at a real bitmap! bfSize is the size of the bitmap in bytes and starts at offset 2 and will read backwards, this is stored in little endian format, which means its the little end first... E.g. a hex number EF D3 C0 2B wold be stored as 2B C0 D3 EF. The maximum size of a bitmap is therefore... FF FF FF FF as bfSize is 4 bytes... so that's about 4 Gb, heh. [note: ALL values will be stored in little endian format in the file SO YOU NEED TO REMEMBER THIS] bfReserved1 and bfReserver2 are just reserved... leave them set to 00 00 and 00 00 bfOffBits is another 4 bytes value that points to the position that the BYTE structure starts, very handy. ================================================== (1-3-2) BITMAPINFOHEADER in depth ================================================== Where BITMAPFILEHEADER leave off, BITMAPINFOHEADER starts at offset 0014:- ------------------------------------------------------------------------ 000E: 28 00 0010: 00 00 04 00 00 00 04 00 00 00 01 00 18 00 00 00 0020: 00 00 30 00 00 00 c4 0e 00 00 c4 0e 00 00 00 00 0030: 00 00 00 00 00 00 ------------------------------------------------------------------------ This tends to be 40 bytes, in length, but don't worry, the first value is 0x28 (this a hex number), which is 40 in decimal, and so tells us the length of the structure, which I will now describe:- offset size name 0x0E 4 biSize 0x12 4 biWidth 0x16 4 biHeight 0x1A 2 biPlanes 0x1C 2 biBitCount 0x1E 4 biCompression 0x22 4 biSizeImage 0x26 4 biXPelsPerMeter 0x2A 4 biYPelsPerMeter 0x2E 4 biClrUsed 0x32 4 biClrImportant biSize is the size of the BITMAPINFOHEADER, usually set to 0x28 (40 bytes), and here we can see, this lasts for 0x28 bytes. biWidth this specifies the width of the image (in pixels), again this is stored in little endian. With foo4.bmp the width is only 4 pixels, hence. biHeight this specifies the height of the image, foo4.bmp is 4 pixels high. biPlanes this is the number of "planes" of the target device don't worry about this, it is almost always set to 01 00. biBitCount is the colour depth of the image, and is the number of bits per pixel. Here the value is 0x18, which is 24 in decimal, therefore this image is a 24-bit bitmap. Remember earlier when you looked at the different types of bitmaps? Well these 2 bytes tell you the bit depth that was chosen. Monochrome is 01 00 (1 bit for a colour, as its only black and white), 16 colours is 04 00 (half a byte, max value... yah.. 16), 256 colours is 08 00, and 24bit is 18 00. biCompression specifies what type of compression is used, and is usually set to 00 00 00 00 (no compression). There are 2 types of compression that is generally accepted for bitmaps and those are 8bit RLE encoding (set biCompression to 1) and 4bit RLE encoding (set biCompression to 2). I won't cover these in these articles, but if you want to check them out, look on google.com. Anything we will deal with here will be 0 compression. biSizeImage refers to the (uncompressed) size of the image data. This is often used for the program to know what the uncompressed data size is IF there is compression, so sometimes this is set to 0 if the compression is 0, but not always. Here it is set to 30 00 00 00, which in decimal is 48. However the size of foo4.bmp is 4x4 pixels (therefore 16 pixels). However, colours are represent with 24bits in maximum form (that's 3 bytes). Therefore in uncompressed form there are 3 bytes for every pixel. In this case that's 3*16=48! Get it? biXPelsPerMeter is the number of horizontal pixels per meter. This is a measure of the resolution and is quite useful, it is usually set to c4 0e 00 00 (which is 0xEC4 = 3780 in decimal). biYPelsPerMeter is the number of vertical pixels per meter. This is a measure of the resolution and is quite useful, it is usually set to c4 0e 00 00 (which is 0xEC4 = 3780 in decimal). biClrUsed is the number of colours used in the bitmap, its often set to zero though, and if it is, the value of biBitCount (the number of bits per colour, or the colour depth of the image) is used to work out the max number of colours used. This can be used to limit the number of colours used and cut out some of the RGBQUAD data. biClrImportant specifies the number of colours that are "important" for the bitmap, its often set to zero again, and this means all colours are important. Don't worry too much about this, its very very often 0. So that's the BITMAPINFOHEADER structure, which will put you up to the offset 0x0036. Don't worry if its all to confusing, look over the table of the structure again and then either compare it with a hex dump of any bitmap or play around with my Bitmap header processing program which can be found at http://www.g615.co.uk/riftor/bmpheader.shtml From this point onwards there is the RGBQUAD structure/array or if this is not present there is blank space (00s) until the start of the image data occurs (defined by the value of bfOffBits in the BITMAPFILEHEADER structure). Often this will follow directly after the BITMAPINFOHEADER structure or RGBQUAD structure. ================================================== (1-3-3) RGBQUAD in depth ================================================== If the image is a Monochrome, 16 colour of 256 colour image then this structure is present. This can be ascertained if the biBitCount (in BITMAPINFOHEADER) value at the offset 0x1C is either 01, 04 or 08. If an image is 24bit colour (biBitCount is set to 0x18) then the RGBQUAD array is not present. So for images with more than 256 colours, this table is NOT present. Okay... so lets say it is? Well the RGBQUAD array lists all the colours that are available to that image, and their order relates to how they are later referenced. The structure for each colour looks like this:- relative offset size name 0x01 1 rgbBlue 0x02 1 rgbGreen 0x03 1 rgbRed 0x04 1 rgbReserved rgbBlue is the value of blue, ranging from 0 to FF rgbGreen is the value of green, ranging from 0 to FF rgbRed is the value of red, ranging from 0 to FF rgbReserved is a reserved byte and should be left as 0. Notice how its rgbBlue then rgbGreen then rgbRed instead of Red.Green.Blue, this is because again the colour is stored in little endian format, hence the blue value goes first. This structure is repeated over and over for everycolour. Therefore for a monochrome bitmap the size of the RGBQUAD structure will be 8 bytes (00 00 00 00 for black and FF FF FF 00 for white). For a 16 colour image the RGBQUAD structure would be 64 bytes in length, and for a 256 colour image the RGBQUAD structure would be 1024 bytes (256*4). If you look at the file sizes of foo1.bmp, foo2.bmp, foo3.bmp, you will see that foo3.bmp is over 1kb in size, whereas the rest are around the 100byte level. That's because foo3.bmp is a 256 colour BMP, therefore there is a 1kb colour table. Colours in the table are referenced by the order they are in, so for foo1.bmp, the hex dump looks like:- ------------------------------------------------------------------------ 0000: 42 4d 4e 00 00 00 00 00 00 00 3e 00 00 00 28 00 BMN > ( 0010: 00 00 04 00 00 00 04 00 00 00 01 00 01 00 00 00     0020: 00 00 10 00 00 00 c4 0e 00 00 c4 0e 00 00 00 00    0030: 00 00 00 00 00 00 00 00 00 00 ff ff ff 00 60 00 ` 0040: 00 00 90 00 00 00 90 00 00 00 60 00 00 00 ------------------------------------------------------------------------ The RGBQUAD structure starts at the offset 0x36, and contains the entries 00 00 00 00 and FF FF FF 00. You will then see that the BYTE data starts at the offset 0x003E (which is referenced by the bfOffBits value, try and spot it on the first line of the hex dump). Now to reference the colour black here the data would be set to 0 (it is first) and for white the data would need to set 1 (for white). For a 16 colour image it could range from 0 to 15, and for a 256 colour image 0 to 255. Now you may be confused by the data that follows, you will notice there are no values of 1! Yet doesn't this monochrome picture (foo1.bmp) need to have the black colour referenced, well it does, in a different way. ================================================== (1-3-4) BYTE in depth ================================================== There are several quirks to the way the BYTE structure works, and also the way that colours in the colour table are referenced depends on the bit depth. I'll start of by describing the way that colours are referenced for BMPs that are less than (and including) 256 colours (therefore they have an RGBQUAD structure). For Monochrome pictures the value of biBitCount is 01, and if you remember, the BitCount is the number of bits per pixel. Therefore in the BYTE data, 1 byte represents a whole 8 pixels, as a pixel is only 1 bit. The only two possibilities for the colour are white and black, 1 and 0. Hence 8 black pixels could be represented as 11111111 in binary, which is FF in hex (or 255 in decimal). Each bit references its colour in the RGBQUAD structure. Interestingly this offers a way to easily create an inverted monochrome image, just swap the colours in RGBQUAD around! Or even change them to different values to make a different 2 tone colour picture. So a foo1.bmp would only need 2 bytes to represent its data, as it only has 16 pixels, it only needs 8*2 bits = 2 bytes. However, you'll notice from the hex dump that there is significantly more than 2 bytes, in fact their is 16 (coincidently the same number of pixels, but just a coincidence!). The BYTE structure REQUIRES that each line in the image needs to finish on a 4-byte boundary in the file. I'm not sure why, but this is just the case! Now a line of foo1.bmp is going to be much less than 4kb, as a line is only 4 pixels, and its a pixel per byte! Therefore a line is represented by a nibble (half a byte), and the rest needs to be padded out with 0s. Therefore the minimum amount of data to represent a line in the image is 4 bytes. Therefore for 4 lines (such as in foo1.bmp) you need 16 bytes, but only the first 4 bits of this is actual data! Nevermind! If you convert the above BYTE structure for foo1.bmp into binary we get... (remember in the hex dump the values are all stored in hex, so 60 is 0x60, which is 96 in decimal and 01100000 in binary) 01100000 00000000 00000000 00000000 10010000 00000000 00000000 00000000 10010000 00000000 00000000 00000000 01100000 00000000 00000000 00000000 Any data after the first 4 bits we know is just padding, so we only need to look at:- 0110 1001 1001 0110 Recognise the shape, if you look at foo.bmp you will see the same shape, and if you look at the hexdump again and look at the RGBQUAD data, we see that 0 is black (colour #000000) and 1 is white (#FFFFFF), see how it fits the image? Now lets look at foo2.bmp. ------------------------------------------------------------------------ 0000: 42 4d 86 00 00 00 00 00 00 00 76 00 00 00 28 00 BM v ( 0010: 00 00 04 00 00 00 04 00 00 00 01 00 04 00 00 00     0020: 00 00 10 00 00 00 c4 0e 00 00 c4 0e 00 00 00 00    0030: 00 00 00 00 00 00 00 00 00 00 00 00 80 00 00 80 0040: 00 00 00 80 80 00 80 00 00 00 80 00 80 00 80 80 0050: 00 00 80 80 80 00 c0 c0 c0 00 00 00 ff 00 00 ff 0060: 00 00 00 ff ff 00 ff 00 00 00 ff 00 ff 00 ff ff 0070: 00 00 ff ff ff 00 98 8a 00 00 80 08 00 00 80 08   0080: 00 00 98 8c 00 00 ------------------------------------------------------------------------ foo2.bmp is a 16 colour bitmap, therefore there is a bigger (a 64byte) RGBQUAD structure, and the actual BYTE structure here starts at the offset 0x0076, with the byte 98. Again you may think, how can 98 be a colour in a 16 colour table?! Well its a similar thing. 16 colours bitmaps have 4-bits to the every pixel, therefore a byte can hold 2 pixels of data, similar to getting 8 pixels into 1 byte for a mono image. Here the BYTE structure starts at 0x0076 as I said, and it lasts for 16 bytes again. Seeing many 00s in there? Well again, the BYTE structure requires lines to end on 4-byte boundaries hence there is some padding as 4 pixels fits into 2 bytes this time (intead of half a byte!). If we look at the binary of the BYTE structure, with the padding taken out, we get:- 10011000 10001010 10000000 00001000 10000000 00001000 10011000 10001100 This time its not as simple as seeing the bit pattern, no. Each 4 bits here represents a pixel, so we need to split it up, then convert each nibble (each 4 bits) into a decimal, and compare it to the colour table. (of course the computer can do this seemlessly!) 1001 1000 1000 1010 = 9 8 8 10 = red grey grey green 1000 0000 0000 1000 = 8 0 0 8 1000 0000 0000 1000 = 8 0 0 8 1001 1000 1000 1100 = 9 8 8 12 Seeing a pattern here? if you compare it to the picture foo2.bmp you can see how that now with different colours u can see the corners and their positions etc. I counted my way through the table, and have put the corresponding enteries in RGBQUAD next to, and then put their actual colours here:- 9 8 8 10 = red grey grey green 8 0 0 8 = grey black black grey 8 0 0 8 = grey black black grey 9 8 8 12 = red grey grey blue Now look at that, then look at the foo2.bmp, compare the colours. Now before you leap to flame me about how I got the rows upside down, stop! Yes, the data shows green at the top, instead of blue, as in the picture. However this is the way that the BYTE structure works. The data is read from the bottom up, and left to right. That is, the first byte read is the bottom left hand corner, and the last one read is the top right hand corner, confusing aye? But its true, but the its part of the structure. Now for foo3.bmp I won't go through it, but here there are 8-bites to the byte, therefore each byte represents one pixel, which is much easier to deal with, and references from either 0 to 255 in the colour table, so that's nice and easy to do, as the value of a byte can range from 0 to 255 too! The lines ending on 4-byte boundaries still applies, but it doesn't matter here, seeing as a byte = a pixel, and our lines for this series of image are 4 pixels in length, therefore a line of pixels lies on the boundary, so its all good. For 24-bit images though things are much different. There is NO RGBQUAD structure for these images, so all the pixels are represented directly using 3 byte values of reg green and blue (but in reverse order, BLUE GREEN RED). ------------------------------------------------------------------------ 0000: 42 4d 66 00 00 00 00 00 00 00 36 00 00 00 28 00 BMf 6 ( 0010: 00 00 04 00 00 00 04 00 00 00 01 00 18 00 00 00     0020: 00 00 30 00 00 00 c4 0e 00 00 c4 0e 00 00 00 00 0   0030: 00 00 00 00 00 00 c5 82 30 ee de 91 c7 a9 1f c5 ł0ޑǩ 0040: 82 30 c7 a9 1f 84 65 2b c5 82 30 c7 a9 1f ee de 0ǩe+ł0ǩ 0050: 91 c5 82 30 84 65 2b ee de 91 c5 82 30 c7 a9 1f ł0e+ޑł0ǩ 0060: ee de 91 c5 82 30 ޑł0 ------------------------------------------------------------------------ Notice how on the first like the value of bfOffBits is 0x36? which is the END of the BITMAPINFOHEADER header; there is NO RGBQUAD structure, we just launch straight into groups of:- relative offset size name 0x01 1 rgbBlue 0x02 1 rgbGreen 0x03 1 rgbRed (with no reserved byte) This is quite handy, and again the data starts at the bottom left pixel and works its way right and up!!! I hope this wasn't all too confusing for you, I hope you can now play with the bitmaps a bit, have a look at the colours, have a look at the values in the header structures, and compare with other bitmaps and your own. ================================================== (1-4) Structure Recap/Overview ================================================== BITMAPFILEHEADER offset size name 0x0 2 bfType 0x2 4 bfSize 0x6 2 bfReserved1 0x8 2 bfReserved2 0x10 4 bfOffBits BITMAPINFOHEADER offset size name 0x0E 4 biSize 0x12 4 biWidth 0x16 4 biHeight 0x1A 2 biPlanes 0x1C 2 biBitCount 0x1E 4 biCompression 0x22 4 biSizeImage 0x26 4 biXPelsPerMeter 0x2A 4 biYPelsPerMeter 0x2E 4 biClrUsed 0x32 4 biClrImportant RGBQUAD[number of colours] relative offset size name 0x01 1 rgbBlue 0x02 1 rgbGreen 0x03 1 rgbRed 0x04 1 rgbReserved BYTE relative offset size name 0x01 1 rgbBlue 0x02 1 rgbGreen 0x03 1 rgbRed or relative offset size name 0x01 1 bPixelRef