2014-02-13 4 views
1

Вопрос очень похож на this, но тот пока не получил ответа. Мой вопрос: у меня есть D2D DXGI RenderTarget от d2dfactory-> CreateDxgiSurfaceRenderTarget(), и я хочу сохранить его содержимое в файл изображения с помощью WIC. Я просто читал this и this, поэтому мне кажется, что я не могу просто создать ID2D1Bitmap в WIC-объекте рендеринга и использовать ID2D1Bitmap :: CopyFromRenderTarget() для копирования с целевой цели рендеринга, которую я хочу сохранить, потому что они используют разные ресурсы. Так вот что я придумал с помощью ID2D1RenderTarget :: CreateSharedBitmap():Direct2D: Как сохранить содержимое ID2D1RenderTarget в файл изображения?

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 render target поддерживает только программный режим, а DXGI-рендер нацелен только на аппаратный режим. Является ли это причиной отказа вышеупомянутого вызова CreateSharedBitmap()? Как сохранить содержимое поверхности DXGI в файл изображения с помощью D2D?

ответ

2
  1. С некоторыми ограничениями вы можете использовать D3DX11SaveTextureToFile. Используйте QI на своей поверхности, чтобы получить ID3D11Resource.

  2. На этой же странице они рекомендуют библиотеку DirectXTex в качестве замены, CaptureTexture затем SaveToXXXFile (где XXX - WIC, DDS или TGA). Так что это еще один вариант.

  3. Кроме того, если ваша поверхность была создана как совместимая с GDI, вы можете использовать IDXGISurface1::GetDC. (Используйте QI на вашем IDXGISurface, чтобы получить IDXGISurface1). Сохранение DC в файл остается в виде упражнения для читателя.

Не забывайте использовать Debug Layer для помощи с загадочными кодами возврата, как E_INVALIDARG.

0

Вы могли бы попробовать это (у меня нет):

  • Сделайте свой старый DXGISurface.
  • Сделайте вспомогательную цель рендеринга ID2D1DeviceContext.
  • Используйте ID2D1DeviceContext :: CreateBitmapFromDxgiSurface для создания ID2D1Bitmap1, связанного с поверхностью DXGI.
  • Нарисуйте свой DXGISurface. Вы должны получить то же самое на ID2D1Bitmap1.
  • Используйте ID2D1Bitmap1 :: Map, чтобы получить указатель на память пикселов.
  • Скопируйте пиксельные данные в файл или в wicbitmap для кодирования (jpeg, tiff и т. Д.)