2

这个问题与此非常相似,但尚未得到答案。我的问题是,我有一个来自 d2dfactory->CreateDxgiSurfaceRenderTarget() 的 D2D DXGI RenderTarget,我想使用 WIC 将其内容保存到图像文件中。我只是在阅读这个这个,所以在我看来,我不能只在 WIC 渲染目标上创建一个 ID2D1Bitmap 并使用 ID2D1Bitmap::CopyFromRenderTarget() 从我要保存的输入渲染目标复制,因为他们正在使用不同的资源。所以这是我使用 ID2D1RenderTarget::CreateSharedBitmap() 得出的结果:

HRESULT SaveRenderTargetToFile(
    ID2D1RenderTarget* pRTSrc,
    LPCWSTR uri
    )
{
    HRESULT hr = S_OK;

    ComPtr<IWICBitmap> spWICBitmap;
    ComPtr<ID2D1RenderTarget> spRT;
    ComPtr<IWICBitmapEncoder> spEncoder;
    ComPtr<IWICBitmapFrameEncode> spFrameEncode;
    ComPtr<IWICStream> spStream;

    //
    // Create WIC bitmap to save and associated render target
    //

    UINT bitmapWidth = static_cast<UINT>(pRTSrc->GetSize().width + .5f);
    UINT bitmapHeight = static_cast<UINT>(pRTSrc->GetSize().height + .5f);

    HR(m_spWICFactory->CreateBitmap(
        bitmapWidth,
        bitmapHeight,
        GUID_WICPixelFormat32bppPBGRA,
        WICBitmapCacheOnLoad,
        &spWICBitmap
        ));

    D2D1_RENDER_TARGET_PROPERTIES prop = D2D1::RenderTargetProperties();
    prop.pixelFormat = D2D1::PixelFormat(
        DXGI_FORMAT_B8G8R8A8_UNORM,
        D2D1_ALPHA_MODE_PREMULTIPLIED
        );
    prop.type = D2D1_RENDER_TARGET_TYPE_DEFAULT;
    prop.usage = D2D1_RENDER_TARGET_USAGE_NONE;
    HR(m_spD2D1Factory->CreateWicBitmapRenderTarget(
        spWICBitmap,
        prop,
        &spRT
        ));

    //
    // Create a shared bitmap from this RenderTarget
    //
    ComPtr<ID2D1Bitmap> spBitmap;
    D2D1_BITMAP_PROPERTIES bp = D2D1::BitmapProperties();
    bp.pixelFormat = prop.pixelFormat;

    HR(spRT->CreateSharedBitmap(
        __uuidof(IWICBitmap),
        static_cast<void*>(spWICBitmap.GetRawPointer()),
        &bp,
        &spBitmap
        ));    // <------------------------- This fails with E_INVALIDARG

    //
    // Copy the source RenderTarget to this bitmap
    //
    HR(spBitmap->CopyFromRenderTarget(nullptr, pRTSrc, nullptr));

    //
    // Draw this bitmap to the output render target
    //

    spRT->BeginDraw();
    spRT->Clear(D2D1::ColorF(D2D1::ColorF::GreenYellow));
    spRT->DrawBitmap(spBitmap);
    HR(spRT->EndDraw());

    //
    // Save image to file
    //

    HR(m_spWICFactory->CreateStream(&spStream));
    WICPixelFormatGUID format = GUID_WICPixelFormat32bppPBGRA;
    HR(spStream->InitializeFromFilename(uri, GENERIC_WRITE));

    HR(m_spWICFactory->CreateEncoder(GUID_ContainerFormatPng, nullptr, &spEncoder));
    HR(spEncoder->Initialize(spStream, WICBitmapEncoderNoCache));
    HR(spEncoder->CreateNewFrame(&spFrameEncode, nullptr));
    HR(spFrameEncode->Initialize(nullptr));
    HR(spFrameEncode->SetSize(bitmapWidth, bitmapHeight));
    HR(spFrameEncode->SetPixelFormat(&format));
    HR(spFrameEncode->WriteSource(spWICBitmap, nullptr));
    HR(spFrameEncode->Commit());
    HR(spEncoder->Commit());
    HR(spStream->Commit(STGC_DEFAULT));

done:
    return hr;
}

这段代码有什么问题吗?(我敢肯定有很多 :)) MSDN 上的某处说 WIC 渲染目标仅支持软件模式,而 DXGI 渲染目标仅支持硬件模式。这就是上述对 CreateSharedBitmap() 的调用失败的原因吗?那么我应该如何使用 D2D 将 DXGI 表面内容保存到图像文件中呢?

4

2 回答 2

2
  1. 有一些限制,您可以使用D3DX11SaveTextureToFile. 在你的表面上使用 QI 来获得ID3D11Resource.

  2. 在同一页面上,他们推荐DirectXTex库作为替代,CaptureTexture 然后 SaveToXXXFile(其中 XXX 是 WIC、DDS 或 TGA)。所以这是另一种选择。

  3. 此外,如果您的表面已创建为与 GDI 兼容,则可以使用IDXGISurface1::GetDC. (在您的 IDXGISurface 上使用 QI 来获取 IDXGISurface1)。将 DC 保存到文件中作为练习留给读者。

请记住使用调试层来帮助处理神秘的返回码,例如E_INVALIDARG.

于 2014-02-14T19:40:24.657 回答
0

你可以试试这个(我没有):

  • 制作您的旧 DXGISurface。
  • 制作辅助 ID2D1DeviceContext 渲染目标。
  • 使用 ID2D1DeviceContext::CreateBitmapFromDxgiSurface 创建与 DXGI 表面关联的 ID2D1Bitmap1。
  • 在您的 DXGISurface 上绘图。您应该在 ID2D1Bitmap1 上得到相同的结果。
  • 使用 ID2D1Bitmap1::Map 获取指向像素数据的内存指针。
  • 将像素数据复制到文件中,或复制到 wicbitmap 以进行编码(jpeg、tiff 等)
于 2014-03-27T16:43:49.137 回答