How to load an image into Direct2D effects using the FilePicker

Shows how to use the Windows::Storage::Pickers::FileOpenPicker to load an image into Direct2D effects. If you want to let the user select an image file from storage in a Windows Store app, we recommend that you use the FileOpenPicker.

What you need to know

Technologies

Prerequisites

Instructions

Step 1: Open the file picker

Create a FileOpenPicker object and set the ViewMode, SuggestedStartLocation, and the FileTypeFilter for selecting images. Call the PickSingleFileAsync method.

    FileOpenPicker^ openPicker = ref new FileOpenPicker();
    openPicker->ViewMode = PickerViewMode::Thumbnail;
    openPicker->SuggestedStartLocation = PickerLocationId::PicturesLibrary;
    openPicker->FileTypeFilter->Append(".jpg");
    auto pickOperation = openPicker->PickSingleFileAsync();

After the PickSingleFileAsync completes, you get a file stream from the IAsyncOperation interface it returns.

Step 2: Get a file stream

Declare a completion handler to run after the file picker async operation returns. Use the GetResults method to retrieve the file and to get the file stream object.

    pickOperation->Completed = ref new AsyncOperationCompletedHandler<StorageFile^>(
          [=](IAsyncOperation<StorageFile^> ^operation, AsyncStatus status)
    {
        auto file = operation->GetResults();
        if (file) // If file == nullptr, the user did not select a file.
        {
                             auto openOperation = file->OpenAsync(FileAccessMode::Read);
                             openOperation->Completed = ref new
                                      AsyncOperationCompletedHandler<IRandomAccessStream^>(
                                      [=](IAsyncOperation<IRandomAccessStream^> ^operation, AsyncStatus status)
                             {
                                      auto fileStream = operation->GetResults();

                                      // Pass IRandomAccessStream^ into DirectXApp for decoding/processing.
                                      OpenFile(fileStream);
                             });
        }
    });

In the next step you convert the IRandomAccessStream object to an IStream that you can pass to WIC.

Step 3: Convert the file stream

Use the CreateStreamOverRandomAccessStream function to convert the file stream. Windows Runtime APIs represent streams with IRandomAccessStream, while WIC consumes IStream.

    ComPtr<IStream> istream;
    DX::ThrowIfFailed(
        CreateStreamOverRandomAccessStream(
        reinterpret_cast<IUnknown*>(fileStream),
        IID_PPV_ARGS(&istream)
        )
    );

Note

To use the CreateStreamOverRandomAccessStream function, you should include shcore.h in your project.

 

Step 4: Create a WIC decoder and get the frame

Create an IWICBitmapDecoder object using the IWICImagingFactory::CreateDecoderFromStream method.

    ComPtr<IWICBitmapDecoder> decoder;
    DX::ThrowIfFailed(
          m_wicFactory->CreateDecoderFromStream(
                    istream.Get(),
                    nullptr,
                    WICDecodeMetadataCacheOnDemand,
                    &decoder
                    )
          );

Get the first frame of the image from the decoder using the IWICBitmapDecoder::GetFrame method.

    ComPtr<IWICBitmapFrameDecode> frame;
    DX::ThrowIfFailed(
        decoder->GetFrame(0, &frame)
        );

Step 5: Create a WIC converter and initialize

Convert the image to the BGRA color format using WIC. IWICBitmapFrameDecode will return the native pixel format of the image, like JPEGs are stored in GUID_WICPixelFormat24bppBGR. However, as a performance optimization with Direct2D we recommend that you convert to WICPixelFormat32bppPBGRA.

  1. Create a IWICFormatConverter object using the IWICImagingFactory::CreateFormatConverter method.

        ComPtr<IWICFormatConverter> converter;
        DX::ThrowIfFailed(
            m_wicFactory->CreateFormatConverter(&converter)
            ); 
    
    
  2. Initialize the format converter to use the WICPixelFormat32bppPBGRA and pass in the bitmap frame.

       DX::ThrowIfFailed(
            converter->Initialize(
                frame.Get(),
                GUID_WICPixelFormat32bppPBGRA,
                WICBitmapDitherTypeNone,
                nullptr,
                0.0f,
                WICBitmapPaletteTypeCustom  // premultiplied BGRA has no paletting, so this is ignored
                )
            );
    

The IWICFormatConverter interface is derived from the IWICBitmapSource interface, so you can pass the converter to the bitmap source effect.

Step 6: Create effect and pass in an IWICBitmapSource

Use the CreateEffect method to create a bitmap source ID2D1Effect object using the Direct2D device context.

Use the ID2D1Effect::SetValue method to set the D2D1_BITMAPSOURCE_PROP_WIC_BITMAP_SOURCE property to the WIC format converter.

Note

The bitmap source effect doesn't take an input from the SetInput method like many Direct2D effects. Instead, the IWICBitmapSource object is specified as a property.

 

    ComPtr<ID2D1Effect> bitmapSourceEffect;

    DX::ThrowIfFailed(
        m_d2dContext->CreateEffect(CLSID_D2D1BitmapSource, &bitmapSourceEffect)
        );

    DX::ThrowIfFailed(
        bitmapSourceEffect->SetValue(D2D1_BITMAPSOURCE_PROP_WIC_BITMAP_SOURCE, converter.Get())
        );

    // Insert code using the bitmap source in an effect graph.

Now that you have the bitmap source effect, you can use it as input to any ID2D1Effect and create an effect graph.

Complete example

Here is the full code for this example.

ComPtr<ID2D1Effect> bitmapSourceEffect;

void OpenFilePicker()
{
    FileOpenPicker^ openPicker = ref new FileOpenPicker();
    openPicker->ViewMode = PickerViewMode::Thumbnail;
    openPicker->SuggestedStartLocation = PickerLocationId::PicturesLibrary;
    openPicker->FileTypeFilter->Append(".jpg");
    auto pickOperation = openPicker->PickSingleFileAsync();
    
    pickOperation->Completed = ref new AsyncOperationCompletedHandler<StorageFile^>(
          [=](IAsyncOperation<StorageFile^> ^operation, AsyncStatus status)
    {
        auto file = operation->GetResults();
        if (file)
        {
                             auto openOperation = file->OpenAsync(FileAccessMode::Read);
                             openOperation->Completed = ref new
                                      AsyncOperationCompletedHandler<IRandomAccessStream^>(
                                      [=](IAsyncOperation<IRandomAccessStream^> ^operation, AsyncStatus status)
                             {
                                      auto fileStream = operation->GetResults();

                                      // Pass IRandomAccessStream^ into DirectXApp for decoding/processing.
                                      OpenFile(fileStream);
                             });
        }
    });
}

void OpenFile(Windows::Storage::Streams::IRandomAccessStream^ fileStream)
{
    ComPtr<IStream> istream;
    DX::ThrowIfFailed(
        CreateStreamOverRandomAccessStream(
            reinterpret_cast<IUnknown*>(fileStream),
            IID_PPV_ARGS(&istream)
            )
        );

    ComPtr<IWICBitmapDecoder> decoder;
    DX::ThrowIfFailed(
          m_wicFactory->CreateDecoderFromStream(
                    istream.Get(),
                    nullptr,
                    WICDecodeMetadataCacheOnDemand,
                    &decoder
                    )
          );

    ComPtr<IWICBitmapFrameDecode> frame;
    DX::ThrowIfFailed(
        decoder->GetFrame(0, &frame)
        );

    ComPtr<IWICFormatConverter> converter;
    DX::ThrowIfFailed(
        m_wicFactory->CreateFormatConverter(&converter)
        );

    DX::ThrowIfFailed(
        converter->Initialize(
            frame.Get(),
            GUID_WICPixelFormat32bppPBGRA,
            WICBitmapDitherTypeNone,
            nullptr,
            0.0f,
            WICBitmapPaletteTypeCustom  // premultiplied BGRA has no paletting, so this is ignored
            )
        );

       ComPtr<ID2D1Effect> bitmapSourceEffect;

    DX::ThrowIfFailed(
        m_d2dContext->CreateEffect(CLSID_D2D1BitmapSource, &bitmapSourceEffect)
        );

    DX::ThrowIfFailed(
        bitmapSourceEffect->SetValue(D2D1_BITMAPSOURCE_PROP_WIC_BITMAP_SOURCE, converter.Get())
        );

    // Insert code using the bitmap source in an effect graph.
}