Drawing on 8bpp grayscale bitmap (unmanaged C++)

徘徊边缘 提交于 2019-11-29 13:11:50

Here. Code that demonstrates how to - in a not managed world - allocate a dynamically sized structure on the stack, fill it in and pass it to CreateDIBSection.

#include <malloc.h>

HBITMAP CreateGreyscaleBitmap(int cx, int cy)
{
  BITMAPINFO* pbmi = (BITMAPINFO*)alloca( sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD)*256);
  pbmi->bmiHeader.biSize = sizeof (pbmi->bmiHeader);
  pbmi->bmiHeader.biWidth = cx;
  pbmi->bmiHeader.biHeight = cy;
  pbmi->bmiHeader.biPlanes = 1;
  pbmi->bmiHeader.biBitCount = 8;
  pbmi->bmiHeader.biCompression = BI_RGB;
  pbmi->bmiHeader.biSizeImage = 0;
  pbmi->bmiHeader.biXPelsPerMeter = 14173;
  pbmi->bmiHeader.biYPelsPerMeter = 14173;
  pbmi->bmiHeader.biClrUsed = 0;
  pbmi->bmiHeader.biClrImportant = 0;

  for(int i=0; i<256; i++)
  {
    pbmi->bmiColors[i].rgbRed = i;
    pbmi->bmiColors[i].rgbGreen = i;
    pbmi->bmiColors[i].rgbBlue = i;
    pbmi->bmiColors[i].rgbReserved = 0;
  }

  PVOID pv;
  return CreateDIBSection(NULL,pbmi,DIB_RGB_COLORS,&pv,NULL,0);
}

In both your examples, you created a new CDC with the following line:

CDC* pDC = new CDC();

But there's something missing: This will just create a new CDC object, but without a valid HDC handle attached to it. You need to call CDC::CreateCompatibleDC first, otherwise trying to select any object into this DC will fail.

Regarding the bmiColors: This member is defined as 1 sized array because the data behind it depends on the color depth and type of bitmap. This is documented in the MSDN. For example, if you had a 128x128 pixels 8Bit Bitmap, you would have to allocate the following amount of mem:

128 * 128 * sizeof(WORD) + sizeof(BITMAPINFOHEADER)

Your bitmap needs to be compatible (same color-depth) as the display context you're going to render it on. Also, 8-bits/pixel bitmaps aren't necessarily grayscale - that's a function of what palette you're using.

I finally resorted to using a .NET graphics tool (Aurigma) to create an 8bpp bitmap, and passed its handle to the unmanaged C++.

Then in C++:

HDC memDc = CreateCompatibleDC (NULL);      
HGDIOBJ Obmp  = ::SelectObject(memDc, varLayer);  // Handle to 8-bit bitmap.

I was able to select the bitmap into a CDC and draw on it. Not 100% unmanaged, but this allowed me to do the drawing in unmanaged code, which gives acceptable speed.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!