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

如何从IDCompositionSurface获取像素数据?DirectComposition调用后Surface被清空

解决DirectComposition Surface调用GetDC后被清空的问题

你的问题核心是未完整执行DirectComposition Surface的绘制流程,以及GDI与DirectComposition交互时的状态处理不当。以下是具体原因和解决方法:

问题原因

  1. 仅调用BeginDraw和GetDC,未执行ReleaseDC和EndDraw,导致Surface处于未提交的异常状态,内容被丢弃。
  2. 即使传入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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.16 10:48:16