IWICImagingFactory::CreateDecoderFromStream()失败,错误消息消息没有帮助

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

本文关键字:消息 错误 有帮助 失败 CreateDecoderFromStream IWICImagingFactory      更新时间:2023-10-16

我正在尝试从位图资源加载ID2D1Bitmap。为此,我查阅了MSDN指南,该指南告诉我在Direct2D使用图像之前使用Windows映像组件(IWIC)来处理图像。

然而,当我调用CreateDecoderFromStream()时,它失败了,它返回一条奇怪的错误消息0x88982f50,告诉我任何信息。我搜索了谷歌,并使用DirectX错误查找。DirectX错误查找工具只告诉我这一点:

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

这是我用来尝试从资源加载ID2D1Bitmap的代码:

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: %drn", GetLastError() );
        return GetLastError();
    }
    hbmpdata = LoadResource( GetModuleHandleW(NULL), hbmp );
    if( NULL == hbmpdata )
    {
        printf("LoadBitmapFromResource::LoadResource() error: %drn", GetLastError() );
        return GetLastError();
    }
    pbmp = LockResource( hbmpdata );
    if( NULL == pbmp )
    {
        printf("LoadBitmapFromResource::LockResource() error: %drn", GetLastError() );
        return GetLastError();
    }
    bmpsize = SizeofResource( GetModuleHandleW(NULL), hbmp );
    if( NULL == bmpsize )
    {
        printf("LoadBitmapFromResource::SizeofResource() error: %drn", GetLastError() );
        return GetLastError();
    }
    errmsg = pIWICFactory->CreateStream( &pStream );
    if( !SUCCEEDED(errmsg) )
    {
        printf("LoadBitmapFromResource::CreateStream() error: %xrn", errmsg );
        return errmsg;
    }
    errmsg = pStream->InitializeFromMemory( (BYTE*)pbmp, bmpsize );
    if( !SUCCEEDED(errmsg) )
    {
        printf("LoadBitmapFromResource::InitializeFromMemory() error: %xrn", errmsg );
        return errmsg;
    }
    errmsg = pIWICFactory->CreateDecoderFromStream( pStream, NULL, WICDecodeMetadataCacheOnLoad, &pbmpdecoder );
    if( !SUCCEEDED(errmsg) )
    {
        printf("LoadBitmapFromResource::CreateDecoderFromStream() error: %xrn", errmsg );
        return errmsg;
    }
    errmsg = pbmpdecoder->GetFrame( 0, &pSource );
    if( !SUCCEEDED(errmsg) )
    {
        printf("LoadBitmapFromResource::GetFrame() error: %xrn", errmsg );
        return errmsg;
    }
    errmsg = pIWICFactory->CreateFormatConverter( &pConverter );
    if( !SUCCEEDED(errmsg) )
    {
        printf("LoadBitmapFromResource::CreateFormatConverter() error: %xrn", errmsg );
        return errmsg;
    }
    errmsg = pConverter->Initialize( pSource, GUID_WICPixelFormat32bppPBGRA, WICBitmapDitherTypeNone, NULL, 0.0f, WICBitmapPaletteTypeMedianCut );
    if( !SUCCEEDED(errmsg) )
    {
        printf("LoadBitmapFromResource::Initialize() error: %xrn", errmsg );
        return errmsg;
    }
    errmsg = pRT->CreateBitmapFromWicBitmap( pConverter, ppD2DBitmap );
    if( !SUCCEEDED(errmsg) )
    {
        printf("LoadBitmapFromResource::CreateBitmapFromWicBitmap() error: %xrn", errmsg );
        return errmsg;
    }
    pConverter->Release();
    pSource->Release();
    pbmpdecoder->Release();
    pStream->Release();
    return 0;
}

事实证明,我不应该将WIC解码器用于位图资源,因为它显然是无法解码的原始像素数据。

我有与您完全相同的代码,用于使用WIC从exe文件中的资源加载ID2D1Bitmap,只是我的代码工作得很好。我可以完美地从我的exe文件中加载位图。我在您的代码中看到的与我的代码不同的一点是,我使用的不是(BYTE*)强制转换,而是repret_cast。

所以不是

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

我会尝试做

errmsg = pStream->InitializeFromMemory( reinterpret_cast<BYTE*>(pbmp), bmpsize );
    if( !SUCCEEDED(errmsg) )
    {
        printf("LoadBitmapFromResource::InitializeFromMemory() error: %xrn", errmsg );
        return errmsg;
    }

发生此问题的原因是LockResource()返回的位图数据不包含前14个字节的位图标头。您可以将从LockResource()返回的数据与原始位图文件进行比较。这是C中的简单测试代码。您可以将其添加到SizeofResource()之后,然后检查out.bmp文件,这是一个无效的位图文件。由于图像数据不好,它没有任何有效的解码器(WINCODEC_ERR_COMPONENTNOTFOUND)。

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

有两个明显的解决方案。

  1. 不要从资源创建IWICStream/IWICBitmapDecoder。相反,直接使用外部位图文件来创建它们。请查看MSDN的示例代码。https://learn.microsoft.com/en-us/windows/win32/direct2d/how-to-load-a-direct2d-bitmap-from-a-file

  2. 在资源数据前面添加位图标头。类似于:

     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
     );
    

小心,在IWICStream的生命周期中,"缓冲区"必须是活的。