GetDiBits:BITMAPINFOHEADER 中传递的不同维度

GetDiBits: different dimensions passed in BITMAPINFOHEADER

根据我使用此功能的经验,我对 GetDiBits 有一些疑问。 我错误地创建了一个双倍大小的位图:

HBITMAP hBmpSection = CreateCompatibleBitmap(ScreenDC, 2 * radius, 2 * radius);

我没有注意到,因为代码的下一部分起作用了。 我在这个位图的一半上 BitBlt 屏幕的一部分:

bmpSmallInfo.bmiHeader.biHeight = (2*radius / 2);
bmpSmallInfo.bmiHeader.biWidth = (2*radius / 2);
BitBlt(hSectionDC, 0, 0, bmpSmallInfo.bmiHeader.biWidth, bmpSmallInfo.bmiHeader.biHeight, ScreenDC, 0, 0, SRCCOPY);

然后我得到对应的数组:

GetDIBits(hSectionDC, hBmpSection, 0, bmpSmallInfo.bmiHeader.biHeight, dataBuffer3, &bmpSmallInfo, DIB_RGB_COLORS);

当我将所有这些数据发送到另一台计算机时,图像完全正确(周围没有黑色边缘,因为它在发送超大位图的情况下会出现)。这意味着 GetDiBits 忽略位图的正确大小并使用 BITMAPINFOHEADER 中提供的位图,而不会崩溃。 (我使用的是 Win10。)

这正常吗?因为我不想通过网络发送不需要的字节,所以我不得不问:GetDiBits 是否输出一个大小正确的数组:(4*radius^2)*3 或者它是否照看结构中的值: radius^2 *3 -忽略填充-?

基本上你有这样的代码:

hbitmap = CreateCompatibleBitmap(hdc, max_width, max_height);
oldbmp = (HBITMAP)SelectObject(memdc, hbitmap);
BitBlt(memdc, 0, 0, width, height, hdc, x, y, SRCCOPY);
SelectObject(memdc, oldbmp);
int size = width_in_bytes_with_padding * height;
allocate size count memory ...
BITMAPINFOHEADER bi = { 40, width, height, 1, 24, BI_RGB };
GetDIBits(...);

您似乎在问的问题:如果 width/height 小于 max_width/max_height 可以吗?

答案是肯定的。 GetDIBits 期望 dataBuffer3 足够大以接收 size 字节。 width/height 应小于或等于 max_width/max_height

请注意,BitBlt 是这段代码中最慢的函数,这就是您需要优化的地方。 CreateCompatibleBitmap 需要几微秒,创建更大的位图不会节省太多。

GetDIBits 是 GDI 标准的一个相当奇怪的函数。它不是只采用 HDCHBITMAP 的通常模式,而是两者都需要,并且对 HBITMAP 参数施加了额外的限制。 iirc 当您要求 GDI(可能)相对于颜色 table 转换位图时使用此模式 - 即在 8 位或更低版本的图像中,您应该在 HDC 中选择 HPALETTE .

然而 MSDN 上的 GetDIBits function 页面非常清楚 - LPBITMAPINFO 参数是:

A pointer to a BITMAPINFO structure that specifies the desired format for the DIB data.

后续评论阐明,如果 lpvBits 为 NULL,您可以使用 GetDIBits 通过将位图属性写入 BITMAPINFO 结构来检索它们。

回答您的具体问题; GetDIBits 使用您在 BITMAPINFOHEADER 中提供的维度和格式输出到 dataBuffer,如果 DDB 具有不同的维度或像素格式,将根据需要进行剪辑和转换。