Accessing bitmap pixels in GDI

With device independent bitmap (DIB) Windows allows to access bitmap pixels directly.
I was wondering how I can get an array of pixels of a given bitmap with Win32 API GDI functions to perform some image proceessing like simple decreasing of image brightness.

My goal was to access a bitmap of existing desktop window and fade all pixels a little.
First create a DIB:

	unsigned __int32 * pBuffer;

	//uiWidth and uiHeight are set appropriately
	DibInfo.bmiHeader.biWidth = uiWidth;
	DibInfo.bmiHeader.biHeight = uiHeight;

	DibInfo.bmiHeader.biPlanes  = 1;      

	// 32 bits per pixel
	// were mapped as 0x00RRGGBB
	DibInfo.bmiHeader.biBitCount = 32;   

	//no compression
	DibInfo.bmiHeader.biCompression = BI_RGB;

	//size is not set initially, that's ok for this call
	DibInfo.bmiHeader.biSizeImage = 0;      

	//for 72DPI resolution
	DibInfo.bmiHeader.biXPelsPerMeter = 2834;
	DibInfo.bmiHeader.biYPelsPerMeter = 2834;  

	DibInfo.bmiHeader.biClrUsed = 0;      
	DibInfo.bmiHeader.biClrImportant = 0;   

	//this is mandatory
	DibInfo.bmiHeader.biSize = sizeof(DibInfo.bmiHeader);

	//create DIB using display or window DC
	//note, that after this call pBuffer will contain a pointer to the allocated
	//memory reserved for DIB pixels
	hDIB = CreateDIBSection(hDC, &DibInfo, DIB_RGB_COLORS, &pBuffer, NULL, 0);

	//copy DDB bitmap pixels to DIB buffer at pBuffer
	//this function allows to specify compression mechanism
	//but I use plain uncompressed format now
	GetDIBits(hDC, hSourceBitmap, 0, uiHeight, pBuffer, &DibInfo, DIB_RGB_COLORS);

In the code above there were two parameters called biXPelsPerMeter and biYPelsPerMeter.
For a common 72DPI resolution I calculated the value 2834 in this was:

	there are (100 cm / 2.54 cm) = 39.3700... inches in one centimeter
	for 72dpi resolution we need to calculate
	39.3700 inches *  72 dpi = 2834 dots per meter

Now accessing pixels is straightforward:

	DWORD iNumberOfPixels = uiHeight * uiWidth;

	//lower brightness substantially
	for(i=0;i<inumberofpixels ;i++){
		pBuffer[i] = (pBuffer[i] >> 3) & ~0x00E0E0E0;

And finally it is needed to copy pixels back from DIB to DDB.

	SetDIBits(hDC, hSourceBitmap, 0, uiHeight, pBuffer, &DibInfo, DIB_RGB_COLORS);

There is a faster method in Windows, which was designed to provide a faster way to access displayed pixels. Look for DirectDraw documentation.

Leave a Reply