Reputation: 193
I am try to create an HBITMAP from pixel buffer and display it. Here is my code to create the HBITMAP
char buffer[640 * 480 * 3];
memset(buffer, 255, 640 * 480 * 3);
BITMAPINFO bm = { sizeof(BITMAPINFOHEADER),
640,
480, 1, 24,
BI_RGB, 640 * 480 * 3, 0, 0, 0, 0 };
HBITMAP imageBmp = CreateDIBSection(hdc, &bm, DIB_RGB_COLORS, (void**)buffer, 0, 0);
if (imageBmp == NULL) {
DWORD lastError = GetLastError();
return;
}
Here is the code to display it:
HDC imageDC = CreateCompatibleDC(NULL); // create an offscreen DC
SelectObject(imageDC, imageBmp); // put the loaded image into our DC
RECT rect;
GetClientRect(hDlg, &rect);
BitBlt(
hdc, // tell it we want to draw to the screen
0, 0, // as position 0,0 (upper-left corner)
rect.right - rect.left, // width of the rect to draw
rect.bottom - rect.top, // height of the rect
imageDC, // the DC to get the rect from (our image DC)
0, 0, // take it from position 0,0 in the image DC
SRCCOPY // tell it to do a pixel-by-pixel copy
);
I am expecting to see a white image, but what I got was a black window screen. I am pretty sure my display code is correct, but do not know why the code to create HBITMAP was wrong.
Upvotes: 1
Views: 762
Reputation: 27756
CreateDIBSection
already returns an allocated buffer through the ppvBits
argument to you, so it overwrites your buffer
variable. From the docs (emphasis mine):
ppvBits A pointer to a variable that receives a pointer to the location of the DIB bit values.
Fixes required to your code:
ppvBits
parameter.CreateDIBSection
.char* buffer = NULL;
BITMAPINFO bm = { sizeof(BITMAPINFOHEADER),
640,
480, 1, 24,
BI_RGB, 640 * 480 * 3, 0, 0, 0, 0 };
HBITMAP imageBmp = CreateDIBSection(hdc, &bm, DIB_RGB_COLORS, (void**) &buffer, 0, 0);
if (imageBmp == NULL) {
DWORD lastError = GetLastError();
return;
}
memset(buffer, 255, 640 * 480 * 3);
Note:
Make sure that in production code, you properly calculate the size by aligning the bitmap width to the next DWORD
boundary, as described by the article "DIBs and Their Use":
Calculating the size of a bitmap is not difficult:
biSizeImage = ((((biWidth * biBitCount) + 31) & ~31) >> 3) * biHeight
The crazy roundoffs and shifts account for the bitmap being DWORD-aligned at the end of every scanline.
In your sample, 640 * 480 * 3
gives the correct result only because the width of 640
is already divisable by 4. For a width of 641
your formula would fail, while the formula cited from the article would give the correct result.
Upvotes: 4