You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

GDI中如何从位图获取原始缓冲区?相关异常问题咨询

GDI GetDIBits相关问题解答

问题背景

我对GDI的理解是:GetDIBits函数可在Windows系统中从捕获的位图中提取原始像素数据。

引用:GetDIBits函数会检索指定兼容位图的位数据,并按指定格式将其复制到缓冲区中作为DIB。

我写了以下代码尝试获取像素数据:

HDC srcd , memdc;
HBITMAP hbmp;
BITMAP bmp;
DWORD dwBytesWritten = 0;
DWORD dwSizeofDIB = 0;
HANDLE hFile = NULL;
char* lpbitmap = NULL;
HANDLE hDIB = NULL;
DWORD dwBmpSize = 0;
BITMAPFILEHEADER   bmfHeader;
BITMAPINFOHEADER   bi;
int Height = GetSystemMetrics(SM_CYSCREEN);
int Width = GetSystemMetrics(SM_CXSCREEN);

srcd = GetDC(NULL); 
if (!srcd)
    printf("failed to obtain screen");

memdc = CreateCompatibleDC(srcd); // creates memory device context 
hbmp = CreateCompatibleBitmap(srcd, Width, Height);
SelectObject(memdc, hbmp);
BitBlt(memdc, 0, 0, Width, Height, srcd, 0, 0, SRCCOPY);
BITMAP bmpScreen;
GetObject(hbmp, sizeof(bmpScreen), (LPVOID)&bmpScreen);
bi.biSize = sizeof(BITMAPINFOHEADER);
bi.biWidth = bmpScreen.bmWidth;
bi.biHeight = bmpScreen.bmHeight;
bi.biPlanes = 1;
bi.biBitCount = 32;
bi.biCompression = BI_RGB;
bi.biSizeImage = 0;
bi.biXPelsPerMeter = 0;
bi.biYPelsPerMeter = 0;
bi.biClrUsed = 0;
bi.biClrImportant = 0;

dwBmpSize = ((bmpScreen.bmWidth * bi.biBitCount + 31) / 32) * 4 * bmpScreen.bmHeight;
hDIB = GlobalAlloc(GHND, dwBmpSize);
lpbitmap = (char*)GlobalLock(hDIB);

GetDIBits(memdc, hbmp, 0,
    (UINT)bmpScreen.bmHeight,
    lpbitmap,
    (BITMAPINFO*)&bi, DIB_RGB_COLORS);

printf("dwBmpSize: %ld\n", dwBmpSize);
printf("Strlen(lpbitmap): %lld\n", strlen(lpbitmap));

我的设备是1920×1080分辨率的单屏,每个像素32位,理论上应获取约66兆位的数据,但输出不符合预期:

dwBmpSize: 8294400
Strlen(lpbitmap): 103614

我的疑问:

  1. 为何strlen返回如此小的数值?
  2. 为何lpbitmap缓冲区包含大量类似“A”的垃圾值?

问题解答

1. 关于strlen返回值过小的问题

strlen是用来统计以'\0'(空字符)结尾的字符串长度的函数,但lpbitmap里存储的是二进制像素数据,不是字符串。像素数据中很容易出现值为0的字节(比如黑色像素的Alpha通道或蓝色通道),strlen遇到第一个'\0'就会停止计数,所以返回的长度远小于实际的像素数据大小。

要确认缓冲区的真实数据量,直接用你计算好的dwBmpSize即可,完全不应该用strlen来检测二进制数据。

2. 关于缓冲区出现类似“A”的“垃圾值”问题

首先,32位像素的格式通常是BGRA(蓝、绿、红、Alpha),每个通道占1字节。你看到的“A”对应的ASCII码是0x41,这其实是某个通道的正常数值,不是垃圾值——比如某个像素的Alpha通道是0x41,或者红/绿/蓝通道是0x41,就会被文本编辑器解析成字符“A”。

另外,GlobalAlloc分配的内存默认不会初始化,但你已经通过GetDIBits把像素数据写入了缓冲区,所以里面的内容都是真实的屏幕像素数据,只是用文本方式查看二进制数据时,会把部分字节解析成可打印字符,看起来像“垃圾值”而已。如果要验证数据正确性,可以尝试把这些像素数据保存为BMP文件,或者直接读取特定位置的像素值来检查。


内容的提问来源于stack exchange,提问作者loaded_dypper

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.13 20:15:39