IWICImagingFactory::CreateDecoderFromStream() fails, error message message is not helpful

0

I'm trying to load a ID2D1Bitmap from a bitmap resource. To do so, I consulted an MSDN guide which told me to use the Windows Imaging Component (IWIC) to process the image before Direct2D uses it.

However, it fails when I call CreateDecoderFromStream(), and it returns a strange error message – 0x88982f50 – that tells me nothing. I've searched Google and used DirectX Error Lookup. The DirectX Error Lookup tool only tells me this:

HRESULT: 0x88982f50 (2291674960)
Name: Unknown
Description: n/a
Severity code: Failed
Facility Code: FACILITY_DWRITE (2200)
Error Code: 0x2f50 (12112)

This is the code I'm using to try and load an ID2D1Bitmap from a resource:

int LoadBitmapFromResource( IWICImagingFactory *pIWICFactory, ID2D1RenderTarget *pRT, int resID, ID2D1Bitmap **ppD2DBitmap )
{
    int errmsg;

    HRSRC hbmp;
    HGLOBAL hbmpdata;
    void *pbmp; //system memory pointer to bitmap resource
    DWORD bmpsize;
    IWICStream *pStream;
    IWICBitmapDecoder *pbmpdecoder;
    IWICBitmapFrameDecode *pSource;
    IWICFormatConverter *pConverter;

    hbmp = FindResourceW( GetModuleHandleW(NULL), MAKEINTRESOURCEW(resID), RT_BITMAP );
    if( NULL == hbmp )
    {
        printf("LoadBitmapFromResource::FindResourceW() error: %d\r\n", GetLastError() );
        return GetLastError();
    }

    hbmpdata = LoadResource( GetModuleHandleW(NULL), hbmp );
    if( NULL == hbmpdata )
    {
        printf("LoadBitmapFromResource::LoadResource() error: %d\r\n", GetLastError() );
        return GetLastError();
    }

    pbmp = LockResource( hbmpdata );
    if( NULL == pbmp )
    {
        printf("LoadBitmapFromResource::LockResource() error: %d\r\n", GetLastError() );
        return GetLastError();
    }

    bmpsize = SizeofResource( GetModuleHandleW(NULL), hbmp );
    if( NULL == bmpsize )
    {
        printf("LoadBitmapFromResource::SizeofResource() error: %d\r\n", GetLastError() );
        return GetLastError();
    }

    errmsg = pIWICFactory->CreateStream( &pStream );
    if( !SUCCEEDED(errmsg) )
    {
        printf("LoadBitmapFromResource::CreateStream() error: %x\r\n", errmsg );
        return errmsg;
    }

    errmsg = pStream->InitializeFromMemory( (BYTE*)pbmp, bmpsize );
    if( !SUCCEEDED(errmsg) )
    {
        printf("LoadBitmapFromResource::InitializeFromMemory() error: %x\r\n", errmsg );
        return errmsg;
    }

    errmsg = pIWICFactory->CreateDecoderFromStream( pStream, NULL, WICDecodeMetadataCacheOnLoad, &pbmpdecoder );
    if( !SUCCEEDED(errmsg) )
    {
        printf("LoadBitmapFromResource::CreateDecoderFromStream() error: %x\r\n", errmsg );
        return errmsg;
    }

    errmsg = pbmpdecoder->GetFrame( 0, &pSource );
    if( !SUCCEEDED(errmsg) )
    {
        printf("LoadBitmapFromResource::GetFrame() error: %x\r\n", errmsg );
        return errmsg;
    }

    errmsg = pIWICFactory->CreateFormatConverter( &pConverter );
    if( !SUCCEEDED(errmsg) )
    {
        printf("LoadBitmapFromResource::CreateFormatConverter() error: %x\r\n", errmsg );
        return errmsg;
    }

    errmsg = pConverter->Initialize( pSource, GUID_WICPixelFormat32bppPBGRA, WICBitmapDitherTypeNone, NULL, 0.0f, WICBitmapPaletteTypeMedianCut );
    if( !SUCCEEDED(errmsg) )
    {
        printf("LoadBitmapFromResource::Initialize() error: %x\r\n", errmsg );
        return errmsg;
    }

    errmsg = pRT->CreateBitmapFromWicBitmap( pConverter, ppD2DBitmap );
    if( !SUCCEEDED(errmsg) )
    {
        printf("LoadBitmapFromResource::CreateBitmapFromWicBitmap() error: %x\r\n", errmsg );
        return errmsg;
    }

    pConverter->Release();
    pSource->Release();
    pbmpdecoder->Release();
    pStream->Release();

    return 0;
}
c++
winapi
com
directx
direct2d
asked on Stack Overflow Apr 2, 2012 by Joshua • edited Apr 2, 2012 by Joshua

3 Answers

0

It turns out I should not be using the WIC decoder for my bitmap resource, because it is apparently raw pixel data that cannot be decoded.

answered on Stack Overflow Apr 8, 2012 by Joshua
0

(I understand this post of a bit old, but I'm putting this here in case it helps someone else or the OP if he happens to ever see this again.)

I have the EXACT same code as you for loading an ID2D1Bitmap from a resource in your exe file using WIC, except mine works perfectly. I can load a bitmap from my exe file flawlessly. The one difference in your code that I see that is different from mine is that instead of using a (BYTE*) cast, I use a reinterpret_cast.

So instead of

errmsg = pStream->InitializeFromMemory( (BYTE*)pbmp, bmpsize );
    if( !SUCCEEDED(errmsg) )
    {
        printf("LoadBitmapFromResource::InitializeFromMemory() error: %x\r\n", errmsg );
        return errmsg;
    }

I would try doing

errmsg = pStream->InitializeFromMemory( reinterpret_cast<BYTE*>(pbmp), bmpsize );
    if( !SUCCEEDED(errmsg) )
    {
        printf("LoadBitmapFromResource::InitializeFromMemory() error: %x\r\n", errmsg );
        return errmsg;
    }
answered on Stack Overflow Oct 28, 2012 by Nkosi Dean
0

This problem happens because the bitmap data returned by LockResource() does not contains the first 14 bytes bitmap header. You can compare the data returned from LockResource() and the original bitmap file to see that. Here is the simple test code in C. You can add it after SizeofResource() then check the out.bmp file, which is an invalid bitmap file. And because of the bad image data, it does not have any valid decoder (WINCODEC_ERR_COMPONENTNOTFOUND).

    FILE* file;
    fopen_s( &file, "out.bmp", "wb");
    fwrite((const char*)(pbmp), 1, bmpsize, file);
    fclose(file);

There are two obvious solutions.

  1. Do not create IWICStream/IWICBitmapDecoder from resource. Instead, using external bitmap file directly to create them. Check MSDN's sample code about that. https://docs.microsoft.com/en-us/windows/win32/direct2d/how-to-load-a-direct2d-bitmap-from-a-file

  2. Add the bitmap header in front of the resource data. Something like:

     BITMAPFILEHEADER header;
     header.bfType = 0x4D42; // 'BM'
     header.bfSize = bmpsize + 14; // resource data size + 14 bytes header
     header.bfReserved1 = 0;
     header.bfReserved2 = 0;
     header.bfOffBits = 14 + 40; // details in bitmap format
    
     BYTE* buffer = new BYTE[header.bfSize];
    
     memcpy(buffer, &header, 14);
     memcpy(buffer + 14, pbmp, bmpsize);
    
     // Initialize the stream with the memory pointer and size.
     hr = pStream->InitializeFromMemory(
         reinterpret_cast<BYTE*>(buffer),
         header.bfSize
     );
    

Be careful, the 'buffer' has to be alive during the life cycle of IWICStream.

answered on Stack Overflow Jan 27, 2021 by Yih Horng • edited Jan 28, 2021 by Yih Horng

User contributions licensed under CC BY-SA 3.0