如何从IDCompositionSurface获取像素数据?DirectComposition调用后Surface被清空
解决DirectComposition Surface调用GetDC后被清空的问题
你的问题核心是未完整执行DirectComposition Surface的绘制流程,以及GDI与DirectComposition交互时的状态处理不当。以下是具体原因和解决方法:
问题原因
- 仅调用
BeginDraw和GetDC,未执行ReleaseDC和EndDraw,导致Surface处于未提交的异常状态,内容被丢弃。 - 即使传入
FALSE给GetDC,若后续未正确结束绘制流程,DirectComposition仍会认为Surface内容未被确认,最终清空数据。
正确的GDI方式提取像素
要保留Surface内容并完成提取,必须严格遵循BeginDraw → GetDC → 操作 → ReleaseDC → EndDraw的完整流程:
HRESULT hr = DCSurface->BeginDraw(&rect, IID_PPV_ARGS(&dxSurface), &point); if (SUCCEEDED(hr)) { HDC hdcSurface = nullptr; // 传入FALSE保留Surface原有内容 hr = dxSurface->GetDC(FALSE, &hdcSurface); if (SUCCEEDED(hr)) { // 提取选中区域像素到内存缓冲区 BITMAPINFO bmi = {}; bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); bmi.bmiHeader.biWidth = rect.right - rect.left; bmi.bmiHeader.biHeight = -(rect.bottom - rect.top); // 匹配GDI顶部原点坐标系 bmi.bmiHeader.biPlanes = 1; bmi.bmiHeader.biBitCount = 32; bmi.bmiHeader.biCompression = BI_RGB; const int pixelCount = (rect.right - rect.left) * (rect.bottom - rect.top); std::vector<BYTE> pixelBuffer(pixelCount * 4); // 32位RGBA格式 GetDIBits(hdcSurface, nullptr, 0, rect.bottom - rect.top, pixelBuffer.data(), &bmi, DIB_RGB_COLORS); // 在这里处理pixelBuffer中的像素数据 dxSurface->ReleaseDC(nullptr); // 必须释放GDI DC } DCSurface->EndDraw(); // 必须提交绘制操作,确认Surface内容 }
更可靠的DXGI映射方式
如果GDI交互仍有兼容性问题,建议使用DXGI原生的Map/Unmap方法提取像素,避免GDI与DirectComposition的状态冲突:
HRESULT hr = DCSurface->BeginDraw(&rect, IID_PPV_ARGS(&dxSurface), &point); if (SUCCEEDED(hr)) { DXGI_MAPPED_RECT mappedRect; // 以只读方式映射Surface,保留原有内容 hr = dxSurface->Map(&mappedRect, DXGI_MAP_READ); if (SUCCEEDED(hr)) { const int width = rect.right - rect.left; const int height = rect.bottom - rect.top; std::vector<BYTE> pixelBuffer(height * mappedRect.Pitch); memcpy(pixelBuffer.data(), mappedRect.pBits, pixelBuffer.size()); // 逐行处理像素(注意Pitch可能大于width*4,需按行偏移读取) for (int y = 0; y < height; ++y) { BYTE* rowData = pixelBuffer.data() + y * mappedRect.Pitch; // 处理当前行的RGBA像素 } dxSurface->Unmap(); } DCSurface->EndDraw(); }
针对链式Visual的特殊处理
如果你的文本内容分布在垂直链式的多个Visual上,单个Surface的像素只是局部内容,需要先将整个Visual树渲染到离屏Surface,再提取完整的选中区域:
// pDCDevice为你的DirectComposition设备,pRootVisual为链式Visual的根节点 IDCompositionSurface* pOffscreenSurface = nullptr; HRESULT hr = pDCDevice->CreateSurface( desiredWidth, desiredHeight, DXGI_FORMAT_B8G8R8A8_UNORM, DXGI_ALPHA_MODE_PREMULTIPLIED, &pOffscreenSurface ); if (SUCCEEDED(hr)) { // 将整个Visual树渲染到离屏Surface hr = pRootVisual->RenderToSurface(pOffscreenSurface, nullptr); if (SUCCEEDED(hr)) { // 对pOffscreenSurface执行上述像素提取操作 // ... } pOffscreenSurface->Release(); }
内容的提问来源于stack exchange,提问作者window_handle
相关产品推荐
相关产品推荐

