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

Directx Direct2D:如何将ID2D1RenderTarget的内容保存到图像文件?,directx,direct2d,wic,dxgi,Directx,Direct2d,Wic,Dxgi,这个问题非常类似于,但那个问题还没有得到回答。我的问题是,我有一个来自D2DFFactory->CreateDxgiSurfaceRenderTarget()的D2D DXGI RenderTarget,我想使用WIC将其内容保存到图像文件中。我只是在阅读,所以在我看来,我不能在WIC渲染目标上创建ID2D1Bitmap,并使用ID2D1Bitmap::CopyFromRenderTarget()从我要保存的输入渲染目标复制,因为它们使用的是不同的资源。下面是我使用ID2D1RenderTarg

这个问题非常类似于,但那个问题还没有得到回答。我的问题是,我有一个来自D2DFFactory->CreateDxgiSurfaceRenderTarget()的D2D DXGI RenderTarget,我想使用WIC将其内容保存到图像文件中。我只是在阅读,所以在我看来,我不能在WIC渲染目标上创建ID2D1Bitmap,并使用ID2D1Bitmap::CopyFromRenderTarget()从我要保存的输入渲染目标复制,因为它们使用的是不同的资源。下面是我使用ID2D1RenderTarget::CreateSharedBitmap()得出的结论:

HRESULT SaveRenderTargetFile(
ID2D1RenderTarget*pRTSrc,
LPCWSTR uri
)
{
HRESULT hr=S_正常;
ComPtr spWICBitmap;
ComPtr spRT;
ComPtr-spEncoder;
ComPtr-spFrameEncode;
ComPtr-spStream;
//
//创建WIC位图以保存和关联渲染目标
//
UINT bitmapWidth=静态_cast(pRTSrc->GetSize().width+.5f);
UINT bitmapHeight=静态_cast(pRTSrc->GetSize().height+.5f);
HR(m_SPWIC工厂->创建位图(
位图宽度,
位图高度,
GUID_WICPixelFormat32bppPBGRA,
WICBitmapCacheOnLoad,
&spWICBitmap
));
D2D1_RENDER_TARGET_PROPERTIES prop=D2D1::RenderTargetProperties();
prop.pixelFormat=D2D1::pixelFormat(
DXGI_格式_B8G8R8A8_UNORM,
D2D1α模式预乘
);
prop.type=D2D1_RENDER_TARGET_type_DEFAULT;
prop.usage=D2D1_RENDER_TARGET_usage_NONE;
HR(m_spD2D1Factory->CreateWicBitmapRenderTarget(
spWICBitmap,
道具
&spRT
));
//
//从此渲染目标创建共享位图
//
ComPtr-sp位图;
D2D1_位图_属性bp=D2D1::BitmapProperties();
bp.pixelFormat=prop.pixelFormat;
HR(spRT->CreateSharedBitmap(
__uuidof(IWICBitmap),
静态_cast(spWICBitmap.GetRawPointer()),
&英国石油公司,
&SP位图
));//CopyFromRenderTarget(nullptr、pRTSrc、nullptr));
//
//将此位图绘制到输出渲染目标
//
spRT->BeginDraw();
spRT->Clear(D2D1::ColorF(D2D1::ColorF::绿黄色));
spRT->DrawBitmap(spBitmap);
HR(spRT->EndDraw());
//
//将图像保存到文件
//
人力资源部(m_spWICFactory->CreateStream(&spStream));
WICPixelFormatGUID format=GUID\u WICPixelFormat32bppPBGRA;
HR(spStream->InitializeFromFilename(uri,通用写入));
HR(m_spWICFactory->CreateEncoder(GUID_包含performatpng、nullptr和spEncoder));
HR(spEncoder->初始化(spStream,WICBitmapEncoderNoCache));
HR(spEncoder->CreateNewFrame(&spFrameEncode,nullptr));
HR(spFrameEncode->Initialize(nullptr));
HR(spFrameEncode->SetSize(位图宽度、位图高度));
HR(spFrameEncode->SetPixelFormat(&format));
HR(spFrameEncode->WriteSource(spWICBitmap,nullptr));
HR(spFrameEncode->Commit());
HR(spEncoder->Commit());
HR(spStream->Commit(STGC_默认值));
完成:
返回人力资源;
}
这个代码有什么问题吗?(我肯定有很多:))在MSDN上的某个地方,它说WIC render target只支持软件模式,而DXGI render target只支持硬件模式。这就是上面调用CreateSharedBitmap()失败的原因吗?我应该如何用D2D将DXGI曲面内容保存到图像文件中

  • 有一些限制,您可以使用。在曲面上使用QI获取
    ID3D11资源

  • 在同一页上,他们推荐使用
    DirectXTex
    library作为替代品,CaptureTexture然后保存toxxFile(其中XXX是WIC、DDS或TGA)。这是另一种选择

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

  • 请记住使用以获得有关诸如
    E_INVALIDARG

    等神秘返回代码的帮助。您可以尝试以下方法(我没有):

    • 把你的旧脸谱画出来
    • 生成一个辅助ID2D1DeviceContext渲染目标
    • 使用ID2D1DeviceContext::CreateBitmapFromDxgiSurface创建与DXGI曲面关联的ID2D1Bitmap1
    • 在你的脸上画。您应该在ID2D1Bitmap1上获得相同的结果
    • 使用ID2D1Bitmap1::Map获取指向像素数据的内存指针
    • 将像素数据复制到文件或wicbitmap进行编码(jpeg、tiff等)
    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;
    }