locked
Loading PNG images from C++ in a Windows Store App ?

    Question


  • I need the PNG images as an array of pixels to create textures in Direct3D. Apparently I can't compile libpng because of the zlib dependency which is written in old C style syntax which is incompatible with the "Consume Windows Store runtime" compile option.

    So... I need something from the Windows store framework to load images and get the pixels. So far Bitmapimage or WriteableBitmap have absolutely no way to extract the data out. So what other ways are there ? I saw that in C# there are extra classes like BitmapDecoder which I don't have in C++. What else could I use ?

    Sunday, January 20, 2013 11:46 AM

Answers

  • The XAML sample just demonstrates how to load images into XAML objects. Like I said, there's no BitmapDecoder class in C++ and apparently it looks like all the code about getting the pixels is hidden. Talk about overusing the private keyword.

    The WIC part, welll... it took me a while to figure out the complete code to extract pixels. The code in that sample needs an actual Factory to work, and I had to do more research to find out how that one gets initialized.

    Here is some complete code that loads a png file and extracts it's pixels just in case someone else stumbles upon this :

    #include <wincodec.h>
        #include <wincodecsdk.h>
        #pragma comment(lib, "WindowsCodecs.lib")
        #include <atlbase.h>

    IWICImagingFactory *pFactory = NULL;
        IWICBitmapDecoder *pDecoder = NULL;

        HRESULT hr = CoCreateInstance(
            CLSID_WICImagingFactory,
            NULL,
            CLSCTX_INPROC_SERVER,
            IID_IWICImagingFactory,
            (LPVOID*)&pFactory
            );

        if (SUCCEEDED(hr))
        {

            hr = pFactory->CreateDecoderFromFilename( L"test.png",
                            NULL,
                            GENERIC_READ,
                            WICDecodeMetadataCacheOnDemand,
                            &pDecoder);
        }

        if (SUCCEEDED(hr))
        {
            UINT uiFrameCount = 0;
            hr = pDecoder->GetFrameCount(&uiFrameCount);
            if (uiFrameCount > 0)
            {
                IWICBitmapFrameDecode *Frame = NULL;
                pDecoder->GetFrame( 0, &Frame );
                UINT X, Y;
                Frame->GetSize( &X, &Y);    
                WICPixelFormatGUID PF;
                Frame->GetPixelFormat( &PF );
                int Channels = 3;            
                if (PF == GUID_WICPixelFormat32bppRGBA || PF == GUID_WICPixelFormat32bppBGRA)
                    Channels = 4;
                UINT BufferSize = X * Y * Channels;
                BYTE *Buffer = new BYTE[ BufferSize ];
                hr = Frame->CopyPixels( NULL, Channels * X, BufferSize, Buffer );            
            }
        }

    EDIT: Doesn't work for ARM builds :|

    Any ideas for Windows Phone 8 though ?



    Sunday, January 20, 2013 10:47 PM

All replies

  • Use WIC (Windows Imaging Component).

    However, you'll be out of luck if you hope to create a WinPhone8 version of your Metro app since WIC isn't available on it. Just another what were they thinking thing...

    Sunday, January 20, 2013 6:38 PM
  • BitmapDecoder is available in C++. I believe it is demonstrated in the Xaml images sample at http://code.msdn.microsoft.com/windowsapps/0f5d56ae-5e57-48e1-9cd9-993115b027b9 . For DX you can also use WICvas described at How to load a bitmap from a file: http://msdn.microsoft.com/en-us/library/windows/desktop/dd756686(v=vs.85).aspx
    Sunday, January 20, 2013 8:07 PM
    Owner
  • The XAML sample just demonstrates how to load images into XAML objects. Like I said, there's no BitmapDecoder class in C++ and apparently it looks like all the code about getting the pixels is hidden. Talk about overusing the private keyword.

    The WIC part, welll... it took me a while to figure out the complete code to extract pixels. The code in that sample needs an actual Factory to work, and I had to do more research to find out how that one gets initialized.

    Here is some complete code that loads a png file and extracts it's pixels just in case someone else stumbles upon this :

    #include <wincodec.h>
        #include <wincodecsdk.h>
        #pragma comment(lib, "WindowsCodecs.lib")
        #include <atlbase.h>

    IWICImagingFactory *pFactory = NULL;
        IWICBitmapDecoder *pDecoder = NULL;

        HRESULT hr = CoCreateInstance(
            CLSID_WICImagingFactory,
            NULL,
            CLSCTX_INPROC_SERVER,
            IID_IWICImagingFactory,
            (LPVOID*)&pFactory
            );

        if (SUCCEEDED(hr))
        {

            hr = pFactory->CreateDecoderFromFilename( L"test.png",
                            NULL,
                            GENERIC_READ,
                            WICDecodeMetadataCacheOnDemand,
                            &pDecoder);
        }

        if (SUCCEEDED(hr))
        {
            UINT uiFrameCount = 0;
            hr = pDecoder->GetFrameCount(&uiFrameCount);
            if (uiFrameCount > 0)
            {
                IWICBitmapFrameDecode *Frame = NULL;
                pDecoder->GetFrame( 0, &Frame );
                UINT X, Y;
                Frame->GetSize( &X, &Y);    
                WICPixelFormatGUID PF;
                Frame->GetPixelFormat( &PF );
                int Channels = 3;            
                if (PF == GUID_WICPixelFormat32bppRGBA || PF == GUID_WICPixelFormat32bppBGRA)
                    Channels = 4;
                UINT BufferSize = X * Y * Channels;
                BYTE *Buffer = new BYTE[ BufferSize ];
                hr = Frame->CopyPixels( NULL, Channels * X, BufferSize, Buffer );            
            }
        }

    EDIT: Doesn't work for ARM builds :|

    Any ideas for Windows Phone 8 though ?



    Sunday, January 20, 2013 10:47 PM
  • Here is a link to the documentation for BitmapDecoder class for C++

    And here is an example of its use (both C# and C++) in accessing the pixels in a byte array.

    Monday, January 21, 2013 12:56 AM