简体   繁体   中英

Displaying all Bitmap Types from a Memory Buffer with MFC or Win32

The goal is to display bitmaps stored in memory buffers. The contents of the memory buffers are identical to disk-stored .bmp files. For performance reasons, writing these buffers to disk and then displaying them is not an option. GDI+ is also not an option. Currently, I can display 24 bit per pixel bitmaps from the memory buffers as desired. However, when I attempt to display 8 bit per pixel bitmaps, the images display with the wrong colors (ie figures in the image are recognizable; scaling, orientation, etc are correct, but everything is the wrong color).

Here is how I initialize the bitmap header structs:

bfh = *(tagBITMAPFILEHEADER*)buf1;
bih = *(tagBITMAPINFOHEADER*)(buf1+sizeof(tagBITMAPFILEHEADER));
rgb = *(RGBQUAD*)(buf1+sizeof(tagBITMAPFILEHEADER)+sizeof(tagBITMAPINFOHEADER));
bi.bmiColors[0] = rgb;
bi.bmiHeader = bih;
pPixels = (buf1+bfh.bfOffBits);

Then, I have tried several different ways of creating the HBITMAP, here are a few:

    g_hBmp = CreateDIBitmap(dcPaint, &bih, CBM_INIT, (VOID *) pPixels, &bi, DIB_RGB_COLORS);

Or:

g_hBmp = CreateDIBSection(dcPaint, &bi, DIB_RGB_COLORS, (void**) &ppvBits, NULL, 0);
SetDIBits(dcPaint, g_hBmp, 0, bih.biHeight, pPixels, &bi, DIB_RGB_COLORS);

I have also tried different parameters:

  • NULL instead of a CPaintDC object
  • DIB_PAL_COLORS instead of DIB_RGB_COLORS

I have dumped the contents of the memory buffers storing the .bmp file structures and verified that they are identical to disk-stored .bmp files that display correctly when loaded with LoadBitmap().

To emphasize, the above approach DOES WORK with 24bit per pixel images. But, it does NOT work with 8bit per pixel images.

Thanks in advance.

The problem is that CreateDIBSection() with DIB_RGB_COLORS expects RGB values for each pixel (ie 24-bits) and your 8-bit bitmap contains pixels that are 8-bit indexes into an RGB palette, which is stored at bi-bmiColors .

So, you have the option of converting your 8-bit bitmaps to 24-bit in a pre-processing step - for example by allocating memory for the RGB values and performing the look-up into the original palette to populate those values. That way you can use the same code for displaying the result. Alternatively, you can create an HBITMAP using the original data and select it into a memory DC then BitBlt() it to the display window.

Other options, apart from GDI or GDI+ might be to consider WIC (Windows Imaging Component) and/or Direct2D.

Hans is correct to say that bi.bmiColors was not being treated correctly. Instead of handling the bi.bmiColors table directly, just point pBitmapInfo to the appropriate offset in BITMAPFILEHEADER and cast. This takes care of the color table automatically. And yes, pBitmapInfo and pBitmapInfoHeader do point to the same place; what they point to is casted differently in each case. Both of those pointers a required by the CreateDIBitmap() function.

pBitmapFileHeader = (LPBITMAPFILEHEADER)buf1;
pBitmapInfoHeader = (LPBITMAPINFOHEADER)(buf1+sizeof(BITMAPFILEHEADER));
pBitmapInfo = (LPBITMAPINFO)(buf1+sizeof(BITMAPFILEHEADER));
pPixels = (buf1+pBitmapFileHeader->bfOffBits);

Then in OnPaint() do:

g_hBmp = CreateDIBitmap(dcPaint, pBitmapInfoHeader, CBM_INIT, (VOID *) pPixels, pBitmapInfo, DIB_RGB_COLORS);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM