Direct2D:如何将ID2D1RenderTarget的内容保存到图像文件?

时间:2014-02-13 23:55:09

标签: directx direct2d wic dxgi

问题与this非常相似,但那个问题尚未得到解答。我的问题是,我有来自d2dfactory-> CreateDxgiSurfaceRenderTarget()的D2D DXGI RenderTarget,我想使用WIC将其内容保存到图像文件中。我只是在阅读thisthis,所以在我看来我不能在WIC渲染目标上创建ID2D1Bitmap并使用ID2D1Bitmap :: CopyFromRenderTarget()从输入渲染目标中复制I想要保存,因为他们使用不同的资源。所以这就是我使用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()失败的原因吗?我应该如何将DXGI表面内容保存到带有D2D的图像文件呢?

2 个答案:

答案 0 :(得分:2)

  1. 有一些限制,您可以使用D3DX11SaveTextureToFile。在表面使用QI获取ID3D11Resource

  2. 在同一页面上,他们建议DirectXTex库替换,CaptureTexture然后SaveToXXXFile(其中XXX是WIC,DDS或TGA)。这是另一种选择。

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

  4. 请务必使用Debug Layer获取有关E_INVALIDARG等神秘回复代码的帮助。

答案 1 :(得分:0)

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

  • 制作旧的DXGISurface。
  • 制作辅助ID2D1DeviceContext渲染目标。
  • 使用ID2D1DeviceContext :: CreateBitmapFromDxgiSurface创建与DXGI表面关联的ID2D1Bitmap1。
  • 在DXGISurface上绘图。您应该在ID2D1Bitmap1上获得相同的内容。
  • 使用ID2D1Bitmap1 :: Map获取指向pixeldata的内存指针。
  • 将pixeldata复制到文件,或复制到wicbitmap进行编码(jpeg,tiff等)