问题
I have an array of pixels which I need to convert to HBITMAP in order to display it in a window. I tried to use CreateDIBitmap() but I don't have the BMP headers. I tried to construct them manually according to MSDN documentation but this didn't work.
Here how my code looks
HBITMAP hBitmap
char pixels[160*120]; // White grayscale image of size 160x120
memset(pixels,255,sizeof(pixels));
BITMAPINFOHEADER bmih;
bmih.biSize = sizeof(BITMAPINFOHEADER);
bmih.biWidth = 160;
bmih.biHeight = -120;
bmih.biPlanes = 1;
bmih.biBitCount = 8;
bmih.biCompression = BI_RGB ;
bmih.biSizeImage = 0;
bmih.biXPelsPerMeter = 10;
bmih.biYPelsPerMeter = 10;
bmih.biClrUsed =0;
bmih.biClrImportant =0;
BITMAPINFO dbmi;
dbmi.bmiHeader = bmih;
dbmi.bmiColors->rgbBlue = 0;
dbmi.bmiColors->rgbGreen = 0;
dbmi.bmiColors->rgbRed = 0;
dbmi.bmiColors->rgbReserved = 0;
void* bits = (void*)&(pixels[0]);
hBitmap = CreateDIBitmap(localDC, &bmih, CBM_INIT, qB.bmBits, &dbmi, DIB_RGB_COLORS);
Now I get a non NULL hBitmap which is good but it shows always black image as if it doesn't point to the array of pixels. I checked it using the code
BITMAP qB;
GetObject(reinterpret_cast<HGDIOBJ>(hBitmap),sizeof(BITMAP),reinterpret_cast<LPVOID>(&qB));
And indeed qB.bmBits is NULL. What is the problem and how to fix it?
回答1:
I found how to do it.
We need to use CreateDIBSection()
instead of CreateDIBitmap()
So here is the working code
HBITMAP hBitmap = NULL;
unsigned char pixels[160*120*3];
for (int i=0; i<160*120*3; i++){
pixels[i] = (i%4==1)*255; // An BGR (not RGB) 160x120 image.
}
BITMAPINFOHEADER bmih;
bmih.biSize = sizeof(BITMAPINFOHEADER);
bmih.biWidth = 160;
bmih.biHeight = -120;
bmih.biPlanes = 1;
bmih.biBitCount = 24;
bmih.biCompression = BI_RGB ;
bmih.biSizeImage = 0;
bmih.biXPelsPerMeter = 10;
bmih.biYPelsPerMeter = 10;
bmih.biClrUsed =0;
bmih.biClrImportant =0;
BITMAPINFO dbmi;
ZeroMemory(&dbmi, sizeof(dbmi));
dbmi.bmiHeader = bmih;
dbmi.bmiColors->rgbBlue = 0;
dbmi.bmiColors->rgbGreen = 0;
dbmi.bmiColors->rgbRed = 0;
dbmi.bmiColors->rgbReserved = 0;
void* bits = (void*)&(pixels[0]);
// Create DIB
hBitmap = CreateDIBSection(localDC, &dbmi, DIB_RGB_COLORS, &bits, NULL, 0);
if (hBitmap == NULL) {
::MessageBox(NULL, __T("Could not load the desired image image"), __T("Error"), MB_OK);
return;
}
// copy pixels into DIB.
memcpy(bits,pixels,sizeof(pixels));
For grey level images, copy the pixels to DIB in a loop instead of with memcpy()
#define INTENSITY unsigned char
INTENSITY* dest = (INTENSITY*)bits;
const INTENSITY* src = .. Put your char array of pixels;
for (int j=0; j<imageWidth; j++){
for (int i=0; i<imageHeight; i++, src++){
*dest++ = *src;
*dest++ = *src;
*dest++ = *src;
}
// Padd the line to round WORD.
if (imageWidth%2)
*dest++ = 0;
}
回答2:
Your post was very helpful (the answer) however it didn't work for me, here is the code with small corrections:
// creating input
unsigned char pixels[160*120*3];
for (int i=0; i<160*120*3; i++)
pixels[i] = (i%4==1)*255; // An BGR (not RGB) 160x120 image.
// at this point we have some input
BITMAPINFOHEADER bmih;
bmih.biSize = sizeof(BITMAPINFOHEADER);
bmih.biWidth = 160;
bmih.biHeight = -120;
bmih.biPlanes = 1;
bmih.biBitCount = 24;
bmih.biCompression = BI_RGB ;
bmih.biSizeImage = 0;
bmih.biXPelsPerMeter = 10;
bmih.biYPelsPerMeter = 10;
bmih.biClrUsed =0;
bmih.biClrImportant =0;
BITMAPINFO dbmi;
ZeroMemory(&dbmi, sizeof(dbmi));
dbmi.bmiHeader = bmih;
dbmi.bmiColors->rgbBlue = 0;
dbmi.bmiColors->rgbGreen = 0;
dbmi.bmiColors->rgbRed = 0;
dbmi.bmiColors->rgbReserved = 0;
HDC hdc = ::GetDC(NULL);
HBITMAP hbmp = CreateDIBitmap(hdc, &bmih, CBM_INIT, pixels, &dbmi, DIB_RGB_COLORS);
if (hbmp == NULL) {
::MessageBox(NULL, L"Could not load the desired image image", L"Error", MB_OK);
return;
}
::ReleaseDC(NULL, hdc);
// a little test if everything is OK
OpenClipboard(NULL);
EmptyClipboard();
SetClipboardData(CF_BITMAP, hbmp);
CloseClipboard();
// cleanup
DeleteObject(hbmp);
回答3:
The other answers here are very helpful, but i ended up being able to achieve it with just 1 line.
HBITMAP hBm = CreateBitmap(width,height,1,32,pixels); // 1 plane, 32 bits
Hope it may be useful to any future readers.
Also, there's CreateCompatibleBitmap and SetDIBits incase you need to use a device context.
At MSDN for CreateDIBitmap it states:
Calling CreateDIBitmap with fdwInit as CBM_INIT is equivalent to calling the CreateCompatibleBitmap function to create a DDB in the format of the device and then calling the SetDIBits function to translate the DIB bits to the DDB.
来源:https://stackoverflow.com/questions/15930528/how-to-convert-an-array-of-pixels-to-hbitmap