Page 1 of 1

How to make sense of the .bmp format Teaches you how to write and read .bmp files Rate Topic: ***** 1 Votes

#1 WolfCoder  Icon User is offline

  • Isn't a volcano just an angry hill?
  • member icon


Reputation: 789
  • View blog
  • Posts: 7,623
  • Joined: 05-May 05

Post icon  Posted 20 April 2007 - 09:13 PM

I haven't written a tutorial in quite some time, but since I keep seeing people having problems when they try to write and read bitmaps, I have decided to clear up the confusion about it all.

I would read up on using structs in C++ if you do not know how to use them. This is important for this tutorial.

.bmp files (Windows BMP) commonly come in 8-bit or 24-bit formats. Working with 8-bit images can actually be difficult so I will cover 24-bit bitmaps in this tutorial since they are easier to understand (and look nicer too :) ). The first thing you should always do when handling a program that uses Windows is to include the windows.h header.

#include <windows.h> // This is a must



Now that is out of the way. The structure for the bitmap file is already handled for you! You simply create two variables (one for each structure using the structure itself as the variable type) to hold the format for the .bmp file. For writing an image, you fill them out and write them to the disk along with the image data. For reading an image, you read them into the variables from disk in order. There are two structures that you need to look at when handling Windows bitmap files. Here's the one that comes first when reading the file:

typedef struct tagBITMAPFILEHEADER { 
  WORD	bfType; 
  DWORD   bfSize; 
  WORD	bfReserved1; 
  WORD	bfReserved2; 
  DWORD   bfOffBits; 
} BITMAPFILEHEADER, *PBITMAPFILEHEADER; 



Here's a breakdown of the structure:
bfType contains the ID for a .bmp file. This is always equal to the string 'BM'. If not, then it isn't a bitmap file. This can help you check to see if the user accidentally opened some other kind of file.
bfSize this should always be equal to the size of the structure itself. Simply set this to sizeof(BITMAPINFOHEADER).
bfReserved1 bfReserved2 These should always be 0.
bfOffBits This should contain the offset in the file where the image data actually begins. For a 24-bit bitmap, simply set this to sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER). In simpler terms, this contains the size of the header for the bitmap file (whatever is not image data).

And the other structure is this:

typedef struct tagBITMAPINFOHEADER {
	DWORD  biSize;		  // size of structure, in bytes
	DWORD  biWidth;		 // bitmap width, in pixels
	DWORD  biHeight;		// bitmap height, in pixels
	WORD   biPlanes;		// see below
	WORD   biBitCount;	  // see below
	DWORD  biCompression;   // see below
	DWORD  biSizeImage;	 // see below
	DWORD  biXPelsPerMeter; // see below
	DWORD  biYPelsPerMeter; // see below
	DWORD  biClrUsed;	   // see below
	DWORD  biClrImportant;  // see below
} BITMAPINFOHEADER;



biSize this should always be sizeof(BITMAPINFOHEADER) just like the other one.
biWidth biHeight this should be the physical size of the bitmap image in pixels. Set them to your heart's content.
biPlanes don't even worry about this one, just set it to 1.
biBitCount for a 24-bit image, set this to 24. For an 8-bit image, set this to 8. (24-bit means a true-color image and an 8-bit is a palletized image).
biCompression since you aren't going to fiddle with compression, set this to BI_RGB (it's a macro in the windows header).
biSizeImage this should be set to the size of the image. Use sizeof(RGBTRIPLE)*width*height for this one if you don't want to use a calculator.
biXPelsPerMeter biYPelsPerMeter this is the resolution setting for printers. It's the number of pixels per meter. Unless you want to calculate stuff, I would just put 2400 for both of them.
biClrUsed biClrImportant these don't matter for a 24-bit image.

Now the image itself is an array of RGBTRIPLES. Sometimes padding is required, but you shouldn't encounter that problem with bitmaps that have a width that is a multiple of 4. For a 128*128 pixel image, you would declare:
RGBTRIPLE image[128*128];



I'm sure you want a simple example to help you, so look over the following example:

#include <windows.h>
#include <iostream.h>

HANDLE hfile;
DWORD written;
BITMAPFILEHEADER bfh;
BITMAPINFOHEADER bih;
RGBTRIPLE *image;

void()
{
 // Open the file
 hfile = CreateFile("source.bmp",GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,NULL,NULL);
 // Read the header
 ReadFile(hfile,&bfh,sizeof(bfh),&written,NULL);
 ReadFile(hfile,&bih,sizeof(bih),&written,NULL);
 // Read image
 imagesize = bih.biWidth*bih.biHeight; // Helps you allocate memory for the image
 image = new RGBTRIPLE[imagesize]; // Create a new image (I'm creating an array during runtime)
 ReadFile(hfile,image,imagesize*sizeof(RGBTRIPLE),&written,NULL); // Reads it off the disk
 // Close source file
 CloseHandle(hfile);
 // Now for some information
 cout<<"The image width is "<<bih.biWidth<<"\n"; // Will output the width of the bitmap
 cout<<"The image height is "<<bih.biHeight<<"\n"; // Will output the height of the bitmap
}



Running through the following code, you see me open the file, read all the bytes from the beginning of the file into two variables (defined by the structs), and then I make an array during runtime and fill it with the rest of the file.

Now, if you wanted to modify the bitmap and save it back, it gets a little confusing. For some reason (actually it's a long story) the bitmap image is upside down. Don't ask me why, I am not a mathematician. To get and set pixels, you would have to do the following:

RGBTRIPLE get_pixel(int x,int y)
{
 // Image define from earlier
 return image[(bih.biHeight-1-y)*bih.biWidth+x];
}
RGBTRIPLE set_pixel(int x,int y,RGBTRIPLE color)
{
 // Image define from earlier
 image[(bih.biHeight-1-y)*bih.biWidth+x] = color;
}



Now if you take a close look, I take the maximum height and subtract it by 1. For example, you enter 5 as the y value, you would get 5 from the bottom of the image. However, since the image is upside down, it is actually 5 from the top of the image. You can breathe a sigh of relief since it's only like that in the y direction of the bitmap.

So much for just a .bmp file! Fiddle around with the example program and see what you can do. For an exercise to help you understand this format, try modifying the program to alter the bitmap file and save it back to the disk. For some reference material on the .bmp format, visit this link.

This post has been edited by WolfCoder: 21 April 2007 - 09:38 PM


Is This A Good Question/Topic? 0
  • +

Replies To: How to make sense of the .bmp format

#2 sourabh009  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 3
  • Joined: 30-October 07

Posted 30 October 2007 - 04:38 AM

hi, i want to know 1 more thing that how to convert a .bmp file (256 color) into grayscale image.

This post has been edited by sourabh009: 30 October 2007 - 04:39 AM

Was This Post Helpful? 0
  • +
  • -

#3 nirvanarupali  Icon User is offline

  • D.I.C Stomach
  • member icon

Reputation: 13
  • View blog
  • Posts: 1,119
  • Joined: 01-August 07

Posted 30 October 2007 - 04:39 PM

Can you also make in .jpg or .gif format? I am more interested in jpg and gif.
Was This Post Helpful? 0
  • +
  • -

#4 jpr0  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 1
  • Joined: 09-February 08

Posted 09 February 2008 - 07:45 AM

"For some reason (actually it's a long story) the bitmap image is upside down. Don't ask me why, I am not a mathematician."

This is because matrices are indexed as "top to bottom, left to right", i.e. M(n,m) means nth row, mth column. Mapping this to what you see as a rectangular bitmap image, the index n corresponds to (Y - y), and m to x, where Y is the largest Y value, and (x,y) are cartesian coordinates (the origin chosen at the bottom left hand corner of the bmp, the x-axis points east, and y-axis points north).
Was This Post Helpful? 0
  • +
  • -

#5 calvinthedestroyer  Icon User is offline

  • D.I.C Lover

Reputation: 167
  • View blog
  • Posts: 1,915
  • Joined: 13-October 07

Posted 13 February 2008 - 11:26 PM

Wow thats allot different from the 3 pages of code it takes to do that in QBasic.
How do you adjust for the different .bmp files? such as 2bit, 4bit, and .bmp's with compression?
Were did you load the pallet? If I remember right 24bit has no pallet just raw data right?
thanks
Andy
Was This Post Helpful? 0
  • +
  • -

#6 arutr  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 1
  • Joined: 12-April 09

Posted 28 April 2009 - 02:37 PM

How to Convert 24bit and 1bit bitmap image to grayscale(8bit)
Was This Post Helpful? 0
  • +
  • -

#7 rwmaster  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 1
  • Joined: 24-May 11

Posted 24 May 2011 - 11:21 PM

I know this is an old post, but how would i be able to use the getpixel and setpiel functions... i dont know how please help!!
Was This Post Helpful? 0
  • +
  • -

Page 1 of 1