GetDIBits异常输出 Win32屏幕捕获代码返回大量意外0值如何解决?
问题根因及修复方案
你代码里存在5处核心错误,是导致大量0值输出的直接原因:
- 兼容位图尺寸设置错误
你调用CreateCompatibleBitmap时传入了w+x, h+y作为宽高,实际只需要创建和捕获区域等大的位图,传入w, h即可。你当前创建了远大于目标区域的位图,额外区域没有内容填充,自然全为0值。 BitBlt目标坐标参数错误BitBlt的第二、三个参数是目标DC的绘制起始坐标,你需要将捕获的屏幕内容绘制到兼容DC的左上角,所以这两个参数应该填0, 0,而不是屏幕区域的左上角坐标x, y。你之前的写法把有效内容绘制到了兼容DC的偏移位置,偏移区域全是空的0值。BITMAPINFO参数未完整初始化
你没有显式设置位图的位深、宽高、位面数参数,导致GetDIBits可能返回非预期的像素格式。要获取32位BGRA格式,需要提前配置对应参数。- 像素遍历和输出逻辑错误
你当前的遍历判断j==w时才存入行,会导致每行第一个像素被归到上一行,而且输出时同时对行顺序和行内像素顺序做了倒序,输出结果和实际像素位置完全不匹配。 - 资源泄漏
你创建了hCaptureDC但没有调用DeleteDC释放,会导致GDI资源泄漏。
修正后的核心代码片段
#include <Windows.h> #include <iostream> #include <vector> #include <fstream> using namespace std; int main() { int x = 745; int y = 345; int w = 250; int h = 480; HDC hdc = GetDC(NULL); HDC hCaptureDC = CreateCompatibleDC(hdc); // 修复1:创建和捕获区域等大的位图 HBITMAP hBitmap = CreateCompatibleBitmap(hdc, w, h); SelectObject(hCaptureDC, hBitmap); // 修复2:目标绘制坐标设为0,0 BitBlt(hCaptureDC,0,0,w,h, hdc,x,y,SRCCOPY|CAPTUREBLT); BITMAPINFO BmpInfo = {0}; BmpInfo.bmiHeader.biSize = sizeof(BmpInfo.bmiHeader); BmpInfo.bmiHeader.biCompression = BI_RGB; // 修复3:显式设置位图参数 BmpInfo.bmiHeader.biWidth = w; BmpInfo.bmiHeader.biHeight = -h; // 负数表示像素从上到下排列,不需要后续倒序输出 BmpInfo.bmiHeader.biPlanes = 1; BmpInfo.bmiHeader.biBitCount = 32; BYTE* lpPixels = new BYTE[w * h * 4]; GetDIBits(hCaptureDC, hBitmap, 0, h, (LPVOID)lpPixels, &BmpInfo, DIB_RGB_COLORS); ofstream out("out0.txt"); // 修复4:简化遍历逻辑,直接输出蓝色通道 for(int i = 0; i < h; i++) { for(int j = 0; j < w; j++) { int pos = (i * w + j) * 4; out << (int)lpPixels[pos] << " "; } out << "\n"; } out.close(); // 修复5:释放所有资源 DeleteObject(hBitmap); DeleteDC(hCaptureDC); ReleaseDC(NULL, hdc); delete[] lpPixels; cout << "took a screenshot\n"; return 0; }
内容的提问来源于stack exchange,提问作者help
相关产品推荐
相关产品推荐

