Search code examples
windowscomponentsimagingwic

IWICBitmapScaler doesn't work for 96bppRGBFloat format?


I encountered a probem when I was using the WIC lib. And I found that I can't scale R32G32B32 images using IWICBitmapScaler... The code example shows below:

{
    IWICImagingFactory* m_pWICFactory;
    HRESULT hr = S_OK;
    // Initialize COM
    hr = CoInitialize(nullptr);
    assert(SUCCEEDED(hr));
    // Initialize Factory
    hr = CoCreateInstance(CLSID_WICImagingFactory, nullptr, CLSCTX_INPROC_SERVER,
        __uuidof(IWICImagingFactory), (void**)&m_pWICFactory);
    assert(SUCCEEDED(hr));

    // 4x4 R32G32B32 image
    XMFLOAT3 srcImg[] = { XMFLOAT3(1, 1, 1), XMFLOAT3(1, 1, 1), XMFLOAT3(1, 1, 1), XMFLOAT3(1, 1, 1),
        XMFLOAT3(1, 1, 1), XMFLOAT3(1, 1, 1), XMFLOAT3(1, 1, 1), XMFLOAT3(1, 1, 1),
        XMFLOAT3(1, 1, 1), XMFLOAT3(1, 1, 1), XMFLOAT3(1, 1, 1), XMFLOAT3(1, 1, 1), 
        XMFLOAT3(1, 1, 1), XMFLOAT3(1, 1, 1), XMFLOAT3(1, 1, 1), XMFLOAT3(1, 1, 1), };

    // 2x2 R32G32B32 image
    XMFLOAT3 dstImg[4];

    CComPtr<IWICBitmap> pSrcBitmap;
    hr = m_pWICFactory->CreateBitmapFromMemory(4, 4, GUID_WICPixelFormat96bppRGBFloat, 4 * sizeof(XMFLOAT3),
        4 * sizeof(XMFLOAT3)* 4, (BYTE*)srcImg, &pSrcBitmap);

    IWICBitmapSource *pSrcBitmapSource = pSrcBitmap.p;

    // scale to 2x2
    CComPtr<IWICBitmapScaler> pScaler;
    hr = m_pWICFactory->CreateBitmapScaler(&pScaler);
    hr = pScaler->Initialize(pSrcBitmapSource, 2, 2, WICBitmapInterpolationModeFant);
    pSrcBitmapSource = pScaler.p;

    // copy back
    WICRect rect = { 0, 0, 2, 2 };
    hr = pSrcBitmapSource->CopyPixels(&rect, 2 * sizeof(XMFLOAT3), 2 * sizeof(XMFLOAT3)* 2, (BYTE*)dstImg);

}

And I just get -1.#QNAN000 in the dstImg buffer :( I'm not sure whether I did something wrong, or the IWICBitmapScaler just don't support such format?

Another ploblem is that when I use IWICFormatConverter to convert R32G32B32A32 (i.e. 128bppRGBFloat) images to R32Gray (i.e.32bppGrayFloat)format, it always clamp the value to [0, 1], is this a desired behavior? (Why???)

(My platform: Win 8.1 64bit + VS2013)


Solution

  • You are incorrectly assuming that the IWICBitmapScaler always returns the data in the same pixel format as it's input. It does not. You have to call GetPixelFormat to find out how the result is going to be formatted. Also, when working with a COM API you must be checking the HRESULT for every call that returns one to catch problems.

    CComPtr<IWICBitmapScaler> pScaler;
    hr = m_pWICFactory->CreateBitmapScaler(&pScaler);
    if ( FAILED(hr) )
        ...
    hr = pScaler->Initialize(pSrcBitmapSource, 2, 2, ICBitmapInterpolationModeFant);
    if ( FAILED(hr) )
        ...
    pSrcBitmapSource = pScaler.p;
    
    WICPixelFormatGUID pfScaler;
    hr = scaler->GetPixelFormat( &pfScaler );
    if ( FAILED(hr) )
        ...
    
    // In many cases, pfScaler will not be the same GUID as your pSrcBItmapSource.
    

    You should take a look at DirctXTex for extensive examples of using WIC.