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

Windows桌面应用中使用Direct Manipulation缩放时如何更新清晰内容?

Direct Manipulation缩放场景下的绘制问题解决

关于IDXGISurface1的使用是否正确

IDXGISurface1本身是合法的DirectComposition绘制载体,但你的问题出在没有结合Direct Manipulation的视口变换参数进行绘制,以及忽略了BeginDraw返回的关键信息。你的代码直接固定绘制到(0,0)位置且使用固定尺寸,完全没考虑当前视口的缩放比例、平移偏移,也没利用BeginDraw给出的rect(需要更新的区域)和point(Surface内的坐标偏移),这才导致绘制内容位置错误、比例异常。

结合DirectComposition与Direct Manipulation的正确绘制流程

要解决缩放模糊和位置错误问题,核心是根据Direct Manipulation的视口状态,绘制对应逻辑区域的高清内容,步骤如下:

1. 确保Direct Manipulation的内容尺寸配置正确

你的例子中,原始内容是4个200x200图片,逻辑尺寸应该设为800x800,视口尺寸是400x400。这样当缩放2倍时,视口实际显示的是200x200的逻辑区域,对应物理像素400x400,此时需要绘制该逻辑区域的高清内容(而非拉伸原始低清像素)。

2. 在OnViewportUpdated中获取视口变换参数

通过IDirectManipulationViewport::GetTransform获取当前的缩放、平移矩阵,或者直接调用GetViewportRect和GetContentRect计算需要绘制的逻辑区域。

3. 正确使用IDXGISurface1进行绘制

  • 必须利用BeginDraw返回的rect和point:rect是需要更新的屏幕区域,point是Surface内的起始坐标偏移,绘制时要对应到这个偏移位置,而非固定(0,0)。
  • 根据缩放比例调整绘制分辨率:比如缩放因子为2时,绘制的内容分辨率应该是逻辑区域的2倍,避免GDI拉伸导致像素化。
  • 推荐用Direct2D替代GDI:GDI在高DPI和缩放场景下处理能力有限,Direct2D支持矢量绘制和高清位图渲染,结合DirectComposition更高效。

修正后的GDI绘制示例(针对你的场景)

ComPtr<IDXGISurface1> dxSurface;
RECT updateRect;
POINT surfaceOffset;
HRESULT hr = screenSurface->BeginDraw(&updateRect, IID_PPV_ARGS(&dxSurface), &surfaceOffset);
if (SUCCEEDED(hr))
{
    HDC hSurfaceDC = nullptr;
    hr = dxSurface->GetDC(FALSE, &hSurfaceDC);
    if (SUCCEEDED(hr))
    {
        // 从Direct Manipulation视口获取当前缩放因子(示例为2倍)
        float scaleX = 2.0f;
        float scaleY = 2.0f;

        // 计算需要绘制的物理区域尺寸
        int physicalWidth = static_cast<int>(updateRect.right - updateRect.left);
        int physicalHeight = static_cast<int>(updateRect.bottom - updateRect.top);

        // 创建与Surface兼容的DC和位图,避免格式不匹配
        HDC hBitmapDC = CreateCompatibleDC(hSurfaceDC);
        if (hBitmapDC != nullptr)
        {
            HBITMAP hBitmap = CreateCompatibleBitmap(hSurfaceDC, physicalWidth, physicalHeight);
            HBITMAP hBitmapOld = (HBITMAP)SelectObject(hBitmapDC, hBitmap);

            // 绘制高清内容到兼容DC
            SelectObject(hBitmapDC, GetStockObject(DC_BRUSH));
            SetDCBrushColor(hBitmapDC, RGB(255, 0, 0));
            Rectangle(hBitmapDC, 0, 0, physicalWidth, physicalHeight);

            // 将内容BitBlt到Surface的指定偏移位置
            BitBlt(hSurfaceDC, surfaceOffset.x, surfaceOffset.y,
                physicalWidth, physicalHeight, hBitmapDC, 0, 0, SRCCOPY);

            // 清理资源
            SelectObject(hBitmapDC, hBitmapOld);
            DeleteObject(hBitmap);
            DeleteDC(hBitmapDC);
        }

        dxSurface->ReleaseDC(nullptr);
    }
    screenSurface->EndDraw();
}

更优方案:使用Direct2D绘制

// 假设已初始化Direct2D设备和上下文
ComPtr<ID2D1DeviceContext> d2dContext;
ComPtr<ID2D1Bitmap1> d2dBitmap;

// 从IDXGISurface1创建Direct2D位图
HRESULT hr = d2dContext->CreateBitmapFromDxgiSurface(dxSurface.Get(), nullptr, &d2dBitmap);
if (SUCCEEDED(hr))
{
    d2dContext->SetTarget(d2dBitmap.Get());
    d2dContext->BeginDraw();
    d2dContext->Clear(D2D1::ColorF(D2D1::ColorF::Transparent));

    // 获取并应用Direct Manipulation的视口变换矩阵
    D2D1_MATRIX_3X2_F transform;
    // 此处需从Direct Manipulation视口获取当前变换矩阵赋值给transform
    d2dContext->SetTransform(transform);

    // 绘制逻辑尺寸的内容,Direct2D会自动适配缩放后的物理像素
    d2dContext->FillRectangle(
        D2D1::RectF(0, 0, 200, 200),
        redBrush.Get() // 假设已创建红色画刷
    );

    d2dContext->EndDraw();
}

关键注意点

  • 始终根据Direct Manipulation的视口状态(缩放、平移)调整绘制内容的区域和分辨率。
  • 不要忽略BeginDraw返回的updateRect和surfaceOffset,这是DirectComposition告知你需要更新的精确区域和坐标偏移。
  • 高DPI场景下,优先使用Direct2D而非GDI,避免像素化和位置偏移问题。

内容的提问来源于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.29 08:10:01