【问题标题】:Drawing on 8bpp grayscale bitmap (unmanaged C++)绘制 8bpp 灰度位图(非托管 C++)
【发布时间】:2023-03-03 20:18:01
【问题描述】:

我一直在尝试绘制 8bpp 灰度位图,但没有成功。以下是我的一些尝试。也许有人可以指出我做错了什么。

================================================ ====

尝试 1:创建、选择和绘制:

在构造函数中:

CBitmap bm;
bm.CreateBitmap (200, 200, 1, 8, NULL);

在 OnDraw 中:

CDC *mdc=new CDC ();
HGDIOBJ tmp = mdc->SelectObject(bm);

结果:tmp为NULL,表示失败。

================================================ ====

尝试 2:创建 DIBSection

在构造函数中:

HBITMAP hbm;
BITMAPINFOHEADER bih;
BITMAPINFO bi;
HANDLE hb;
CDC* myDc = new CDC ();
HDC hdc = myDc->GetSafeHdc ();
void* bits;
RGBQUAD rq [256];

 initBi ();
 hbm = CreateDIBSection (hdc, &bi, DIB_RGB_COLORS, &bits, NULL, 0);

...

void CEightBitDrawingView::initBi()
{
 bih.biSize = sizeof (BITMAPINFOHEADER);
 bih.biWidth = 200;
 bih.biHeight = -200;
 bih.biPlanes = 1;
 bih.biBitCount = 8;
 bih.biCompression = BI_RGB;
 bih.biSizeImage = 0;
 bih.biXPelsPerMeter = 14173;
 bih.biYPelsPerMeter = 14173;
 bih.biClrUsed = 0;
 bih.biClrImportant = 0;

 memset ((void *) rq, 0, 256 * sizeof (RGBQUAD));

 bi.bmiHeader = bih;
 bi.bmiColors = rq;
}

结果:这甚至无法编译,因为 BITMAPINFO bmiColors 成员定义为: RGBQUAD bmiColors[1];

因此不会接受一种以上的 RGB 颜色。事实上,我分配给该成员的任何内容都无法编译! (他们能不能让它变得更复杂!?)

任何建议将不胜感激!谢谢!

================================================ ====

【问题讨论】:

  • 你试过GDI+吗?或者有什么业务不需要?
  • 为了提高速度,我正在将 GDI+ 中的工作示例转换为非托管 C++/GDI。事实证明,要在 GDI 中绘制 8bpp 位图非常困难。
  • GDI+ 不受管理。这是一个基于win32构建的C++库。托管将是 WinForms 或 WPF。

标签: c++ mfc winapi bitmap gdi


【解决方案1】:

这里。演示如何 - 在非托管环境中 - 在堆栈上分配动态大小的结构、填充它并将其传递给 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);
}

【讨论】:

  • BITMAPINFO 结构大小的计算错误。由于任何特定平台/架构的对齐规则,它不考虑填充。编译器可以使用offsetof 宏:alloca(offsetof(BITMAPINFO, bmiColors[256])); 计算正确的大小。此博客条目中解释了基本原则:Why do some structures end with an array of size 1?
【解决方案2】:

在您的两个示例中,您使用以下行创建了一个新的CDC

CDC* pDC = new CDC();

但是缺少一些东西:这只会创建一个新的 CDC 对象,但没有附加有效的 HDC 句柄。您需要先调用 CDC::CreateCompatibleDC,否则尝试将任何对象选择到此 DC 中都会失败。

关于 bmiColors:这个成员被定义为 1 个大小的数组,因为它后面的数据取决于位图的颜色深度和类型。这记录在 MSDN 中。例如,如果您有一个 128x128 像素的 8Bit 位图,则必须分配以下数量的内存:

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

【讨论】:

    【解决方案3】:

    我最终求助于使用 .NET 图形工具 (Aurigma) 创建 8bpp 位图,并将其句柄传递给非托管 C++。

    然后在 C++ 中:

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

    我能够将位图选择到 CDC 中并在其上绘图。不是 100% 非托管,但这让我可以在非托管代码中进行绘图,这提供了可接受的速度。

    【讨论】:

      【解决方案4】:

      您的位图需要与您要在其上渲染的显示上下文兼容(相同的颜色深度)。此外,8 位/像素位图不一定是灰度 - 这是您使用的调色板的函数。

      【讨论】:

      • 8bpp 位图将包含另一个应用程序的 CYMK 位图组件,因此我不希望它们与显示器兼容。我不关心调色板,但 Windows 强迫我处理它以获得 8bpp 位图。
      猜你喜欢
      • 1970-01-01
      • 2019-02-10
      • 2012-06-03
      • 2011-10-10
      • 2013-02-09
      • 1970-01-01
      • 1970-01-01
      • 2019-12-03
      • 1970-01-01
      相关资源
      最近更新 更多