如何在屏幕显示像素向量?绘制截图顶部黑屏问题求助
问题原因与修复方案
你的代码存在三个核心问题,导致绘制时截图顶部出现黑屏:
1. 兼容位图创建时使用了错误的DC
setScreenSnippet中,CreateCompatibleBitmap(mem_dc, width, height)的mem_dc是刚创建的空兼容DC,默认关联单色位图,生成的位图无法存储32位RGB数据,导致部分区域显示黑色。
修复:改用屏幕DC创建兼容位图,确保格式与屏幕一致:
HBITMAP bitmap = CreateCompatibleBitmap(screen_dc, width, height);
2. DIB像素存储方向错误
当BITMAPINFO.bmiHeader.biHeight为正数时,DIB像素数据是从图像底部到顶部倒序存储的。你获取的像素顺序与绘制需求的顺序颠倒,导致图像错位,顶部出现黑屏。
修复:将biHeight设为负数,让DIB按从顶部到底部的顺序存储像素,与vector的线性存储一致:
在recvScreenSnippet和setScreenSnippet中,都修改:
bmi.bmiHeader.biHeight = -height;
3. DC资源清理逻辑错误
setScreenSnippet中没有保存SelectObject返回的旧位图句柄,无法正确恢复DC状态;且循环后的清理代码永远不会执行,存在资源泄漏。
修复:保存旧位图句柄,清理时恢复;调整循环逻辑(示例中添加了10秒后自动退出的条件)。
修改后的完整代码
截图生成函数
std::vector<RGBQUAD> recvScreenSnippet(int x, int y, int width, int height) { std::vector<RGBQUAD> v_screen_data(width*height); HDC screen_dc = GetDC(NULL); HDC mem_dc = CreateCompatibleDC(NULL); HBITMAP hBmp = CreateCompatibleBitmap(screen_dc, width, height); auto oldBmp = SelectObject(mem_dc, hBmp); // 32位 & 正序存储(biHeight为负) BITMAPINFO bmi{}; bmi.bmiHeader.biBitCount = 32; bmi.bmiHeader.biCompression = BI_RGB; bmi.bmiHeader.biPlanes = 1; bmi.bmiHeader.biHeight = -height; // 修改为负数 bmi.bmiHeader.biWidth = width; bmi.bmiHeader.biSize = sizeof(BITMAPINFO); BitBlt(mem_dc, 0, 0, width, height, screen_dc, x, y, SRCCOPY); GetDIBits(mem_dc, hBmp, 0, height, &v_screen_data[0], &bmi, DIB_RGB_COLORS); // 正确清理资源 SelectObject(mem_dc, oldBmp); DeleteObject(hBmp); DeleteDC(mem_dc); ReleaseDC(0, screen_dc); return v_screen_data; }
屏幕绘制函数
void setScreenSnippet(int x, int y, int width, int height, std::vector<RGBQUAD> &v_pixel_data) { HDC screen_dc = GetDC(0); HDC mem_dc = CreateCompatibleDC(0); // 32位 & 正序存储(biHeight为负) BITMAPINFO bmi{}; bmi.bmiHeader.biBitCount = 32; bmi.bmiHeader.biCompression = BI_RGB; bmi.bmiHeader.biPlanes = 1; bmi.bmiHeader.biHeight = -height; // 修改为负数 bmi.bmiHeader.biWidth = width; bmi.bmiHeader.biSize = sizeof(BITMAPINFO); // 使用screen_dc创建兼容位图 HBITMAP bitmap = CreateCompatibleBitmap(screen_dc, width, height); auto oldMemBmp = SelectObject(mem_dc, bitmap); // 保存旧位图句柄 SetDIBits(mem_dc, bitmap, 0, height, &v_pixel_data[0], &bmi, DIB_RGB_COLORS); // 示例:运行10秒后退出循环 DWORD start_time = GetTickCount(); while (GetTickCount() - start_time < 10000) { BitBlt(screen_dc, x, y, width, height, mem_dc, 0, 0, SRCCOPY); Sleep(1); } // 正确清理资源 SelectObject(mem_dc, oldMemBmp); // 恢复DC原来的位图 DeleteObject(bitmap); DeleteDC(mem_dc); ReleaseDC(0, screen_dc); }
调用代码
int main() { Sleep(5000); std::vector<RGBQUAD> v_pixel_data = recvScreenSnippet(600,600,400,400); setScreenSnippet(100, 600, 400, 400, v_pixel_data); system("pause"); return 0; }
内容的提问来源于stack exchange,提问作者Lenarolla
相关产品推荐
相关产品推荐

