c++ - ID2D1HwndRenderTarget::CreateBitmapFromWicBitmap()

标签 c++ winapi direct2d

我正在尝试使用 WIC 从文件中加载图片并使用 Direct2D 在屏幕上显示它。我关注MSDN example但我遇到函数 CreateBitmapFromWicBitmap() 的问题。

无论pixel formats是哪种组合我在 ID2D1HwndRenderTarget 创建和 IWICFormatConverter::Initialize() 函数调用期间使用,函数 CreateBitmapFromWicBitmap() 返回 0x88982f80 错误(WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT).

我使用用于绘图的相同 ID2D1HwndRenderTarget 调用该函数。我应该创建另一个渲染目标吗?

在此link的评论区,有人写道 CreateBitmapFromWicBitmap() 应该由 DXGI 表面渲染目标调用。这是否意味着此函数根本无法与 ID2D1HwndRenderTarget 一起使用?

编辑:

void LoadBitmapFromFile(ID2D1HwndRenderTarget* target, ID2D1Bitmap** ppBitmap)
{
    IWICImagingFactory* factory;
    IWICBitmapDecoder* decoder;
    IWICBitmapFrameDecode* frame;
    IWICFormatConverter* converter;

    CoInitializeEx(0, COINIT_MULTITHREADED);
    CoCreateInstance(CLSID_WICImagingFactory1,
                     NULL,
                     CLSCTX_INPROC_SERVER,
                     IID_IWICImagingFactory,
                     reinterpret_cast<void**>(&factory));

    factory->CreateDecoderFromFilename(L".png",
                                       NULL,
                                       GENERIC_READ,
                                       WICDecodeMetadataCacheOnLoad,
                                       &decoder);

    decoder->GetFrame(0, &frame);

    factory->CreateFormatConverter(&converter);

    converter->Initialize(frame,
                          GUID_WICPixelFormat32bppPBGRA,
                          WICBitmapDitherTypeNone,
                          NULL,
                          0.f,
                          WICBitmapPaletteTypeMedianCut);

    target->CreateBitmapFromWicBitmap(frame, 0, ppBitmap);
}

ID2D1HwndRenderTarget 是这样创建的:

ID2D1Factory* factory;
ID2D1HwndRenderTarget* target;

D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, &factory);

factory->CreateHwndRenderTarget(
    D2D1::RenderTargetProperties(D2D1_RENDER_TARGET_TYPE_HARDWARE,
                                 D2D1::PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_PREMULTIPLIED)), 
    D2D1::HwndRenderTargetProperties(hwnd, D2D1::SizeU(width, height)),
    &target);

最佳答案

CreateBitmapFromWicBitmap 需要 converter 作为第一个参数,而不是 frame

使用 CLSID_WICImagingFactory 而不是 CLSID_WICImagingFactory1。编译器将选择正确的值。在我的例子中,它选择了 CLSID_WICImagingFactory2

IWICImagingFactory* factory 的变量名隐藏了一个同名的全局变量。这可能不会导致错误,但最好更改它...

需要释放句柄。

HRESULT LoadBitmapFromFile(const wchar_t *filename, ID2D1HwndRenderTarget* target, ID2D1Bitmap** pBitmap)
{
    HRESULT hr = S_FALSE;
    IWICImagingFactory* wic_factory = NULL;
    IWICBitmapDecoder* decoder = NULL;
    IWICBitmapFrameDecode* frame = NULL;
    IWICFormatConverter* converter = NULL;

    hr = CoCreateInstance(CLSID_WICImagingFactory, NULL, CLSCTX_INPROC_SERVER, IID_IWICImagingFactory, reinterpret_cast<void**>(&wic_factory));
    if FAILED(hr) goto clenaup;

    hr = wic_factory->CreateDecoderFromFilename(filename, NULL, GENERIC_READ, WICDecodeMetadataCacheOnLoad, &decoder);
    if FAILED(hr) goto clenaup;

    hr = decoder->GetFrame(0, &frame);
    if FAILED(hr) goto clenaup;

    hr = wic_factory->CreateFormatConverter(&converter);
    if FAILED(hr) goto clenaup;

    hr = converter->Initialize(frame, GUID_WICPixelFormat32bppPBGRA, WICBitmapDitherTypeNone, NULL, 0.f, WICBitmapPaletteTypeMedianCut);
    if FAILED(hr) goto clenaup;

    hr = target->CreateBitmapFromWicBitmap(converter, 0, pBitmap);
    if FAILED(hr) goto clenaup;

clenaup:
    safe_release(decoder);
    safe_release(converter);
    safe_release(frame);
    safe_release(wic_factory);
    return hr;
}

CoInitializeEx(0, COINIT_MULTITHREADED) 可以在初始化时调用一次。

ID2D1Factory* factory;
ID2D1HwndRenderTarget* target;

void initialize(HWND hwnd)
{
    CoInitializeEx(0, COINIT_MULTITHREADED);

    RECT rc;
    GetClientRect(hwnd, &rc);

    D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, &factory);
    factory->CreateHwndRenderTarget(
        D2D1::RenderTargetProperties(D2D1_RENDER_TARGET_TYPE_HARDWARE,
        D2D1::PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_PREMULTIPLIED)),
        D2D1::HwndRenderTargetProperties(hwnd, D2D1::SizeU(rc.right, rc.bottom)),
        &target);
}

void on_render()
{
    target->BeginDraw();
    target->Clear(D2D1::ColorF(D2D1::ColorF::White));

    ID2D1Bitmap* pBitmap = NULL;
    if (SUCCEEDED(LoadBitmapFromFile(L"filename.png", target, &pBitmap)))
    {
        D2D1_SIZE_F size = pBitmap->GetSize();
        target->DrawBitmap(pBitmap, D2D1::RectF(0, 0, size.width, size.height));
        safe_release(pBitmap);
    }

    target->EndDraw();
}

关于c++ - ID2D1HwndRenderTarget::CreateBitmapFromWicBitmap(),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39832514/

相关文章:

c++ - 可变长度模板参数列表?

c++ - 错误 : no member function declared in class

c++ - 如何获取DLL的版本?

c++ - COM 端口上的 Win32 重叠读取文件返回 ERROR_OPERATION_ABORTED

c++ - Directwrite:获取字体的高度

c++ - 在 C++ 中重载 >> 运算符有问题吗?

c++ - 用c++中的类对小于30的奇数进行迭代和平方

winapi - Richedit 2.0 在 WM_SETTEXT 后撤消

c# - C# 中的平滑视频渲染

c# - 如何使用 Windows Store C++ 在没有窗口句柄的情况下渲染路径几何