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;
}
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.
(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;
}
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.
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
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.
User contributions licensed under CC BY-SA 3.0