Need to create a bitmap filled with black

May 18, 2013 at 7:24pm
I need to create a HBITMAP that stores a bitmap where all its pixels are black. The dimensions of the desired bitmap are unknown until the user enters them.

I am new to windows programming and am trying to understand the idea of device contexts. If I create a memory DC and HBITMAP as follows:

1
2
3
4
5
HDC bmpHdc;
bmpHdc = CreateCompatibleDeviceContext(hdc) //hdc is created when the paint message is received 
//by the wndproc call back function
HBITMAP hBmp;
hBmp = CreateCompatibleBitmap(hdc, width, height); //width height assigned by user earlier 


How do i then fill it with black pixels? I have tried doing so using this approach:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
COLORREF fillColour;
fillColour = RGB(0,0,0)

HBRUSH fillBrush;
fillBrush = CreateSolidBrush(fillColour);

//select the bitmap into the device context
SelectObject(bmpHdc, hBmp);
//select the brush into the device context
SelectObject(bmpHdc, fillBrush);

//draw a rectangle on the HDC
Rectangle(bmpHdc, 0,0,width,height);

//at this point I should have drawn a black rectangle to the bitmap but how can I get 
//that bitmap and assign it to the classes HBITMAP data member? 


I am new and despite a lot of looking around and at documentation I can't either see an example of someone doing this or work out what to do myself. Some help would be appreciated.

Thanks
May 18, 2013 at 8:53pm
I'm unclear what you want to do?

It it this kind of thing?

Create a solid bitmap...

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
// Need to call DeleteObject on returned bitmap handle when
// done with it
HBITMAP
CreateSolidBitmap(HDC hdc, int width, int height, COLORREF cref)
{
	// Create compatible memory DC and bitmap, and a solid brush
	HDC hdcMem = CreateCompatibleDC(hdc);
	HBITMAP hbmp = CreateCompatibleBitmap(hdcMem, width, height);
	HBRUSH hbrushFill = CreateSolidBrush(cref);

	// Select the bitmap and brush into DC
	HBITMAP hbmpOld   = (HBITMAP)SelectObject(hdcMem, hbmp);
	HBRUSH  hbrushOld = (HBRUSH)SelectObject(hdcMem, hbrushFill);

	// Fill the whole area with solid color
	Rectangle(hdcMem, 0, 0, width, height);

	// Restore old bitmap and brush
	SelectObject(hdcMem, hbmpOld);
	SelectObject(hdcMem, hbrushOld);

	// Delete brush
	DeleteObject(hbrushFill);

	// Delete memory DC
	DeleteDC(hdcMem);

	// Set preferred dimensions
	SetBitmapDimensionEx(hbmp, width, height, NULL);

	return hbmp;
}


... and then draw it?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
void DisplayBitmap(HDC hdc, int x, int y, HBITMAP hbmp)
{
	// Get preferred dimensions
	SIZE sizeBitmap = {0, 0};
	GetBitmapDimensionEx(hbmp, &sizeBitmap);

	// Create compatible memory DC
	HDC hdcMem = CreateCompatibleDC(hdc);

	// Select the bitmap into DC
	HBITMAP hbmpOld = (HBITMAP)SelectObject(hdcMem, hbmp);

	// Blit the bitmap on target DC from memory DC
	BitBlt(hdc, x, y, sizeBitmap.cx, sizeBitmap.cy, hdcMem, 0, 0, SRCCOPY);

	// Restore old bitmap
	SelectObject(hdcMem, hbmpOld);

	// Delete memory DC
	DeleteDC(hdcMem);
}


Andy

PS If you want to work on the bitmap's pixels directly, rather than drawing it, you start of with CreateDIBSection. See this codeproject.com article for further info: Create bitmap from pixels
http://www.codeproject.com/Tips/150253/Create-bitmap-from-pixels
Last edited on May 18, 2013 at 9:46pm
May 18, 2013 at 11:38pm
That's exactly right. I did fix the problem in the same whay that you have posted. However the idea was for the bmp handle to be saved to be drawn later.

I am creating a 2d map editor that creates map files for another graphics library. This graphics library supports transparency but in the editor transparency needs to be represented by a default color (i choose black) so that the editor can see which tiles are transparent.

This is the code I used for drawing:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
void TilePalette::DrawTiles(HDC hdc)
{
	HDC bmpHdc;
	bmpHdc = CreateCompatibleDC(hdc);

	int length = tilePalette_.size();
	int xBound = 0, yBound = 0, margin = 4;

	if (length > 6)
	{
		yBound = sqrt(length);

		xBound = length - yBound;
	}
	else
	{
		yBound = 1;
		xBound = length;
	}

	int i = 0;
	for (int y = 0; y < yBound; y++)
	{
		for (int x = 0; x < xBound; x++)
		{
			BlitBitmap(tilePalette_[i].BGImage, 
                                   hdc, 
                                   (x*Map::TileWidth_) + (x * margin) + margin, 
                                   (y * Map::TileHeight_) + (y * margin) + margin);
			++i;
		}
	}
}


I now have a new similar problem but I'll create a new post about it.
Last edited on May 18, 2013 at 11:41pm
May 19, 2013 at 12:05am
the idea was for the bmp handle to be saved to be drawn later.

My code allows you to do that. If you call CreateSolidBitmap once and keep the HBITMAP, you can repeatly use it, and only delete it during program clean-up. That's actually how I checked the code before posting it.

As it was just a quick check, I added the code to an exisiting Win32 GUI app using an evil global:

HBITMAP g_hbmp = NULL;

And the following code added to the WndProc

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
		case WM_PAINT:
			hdc = BeginPaint(hWnd, &ps);

			// other stuff

			if(g_hbmp == NULL)
				g_hbmp = CreateSolidBitmap(hdc, 40, 40, RGB(0, 0, 0));
			if(g_hbmp != NULL)
				DisplayBitmap(hdc, 200, 200, g_hbmp);

			// other stuff

			EndPaint(hWnd, &ps);
		break;

		case WM_DESTROY:
			// other stuff

			if(NULL != g_hbmp)
			{
				DeleteObject(g_hbmp);
				g_hbmp = NULL;
			}

			PostQuitMessage(0);
		break;

Andy

PS While checking on a couple of the calls, I saw this article in passing, in case it's of use later... (including to me!)

Storing an Image
http://msdn.microsoft.com/en-us/library/windows/desktop/dd145119%28v=vs.85%29.aspx

Last edited on May 19, 2013 at 12:09am
Topic archived. No new replies allowed.