如何使用 FilePicker 将图像加载到 Direct2D 效果中

演示如何使用 Windows::存储::P ickers::FileOpenPicker将图像加载到 Direct2D 效果 中。 若要让用户从 Windows Store 应用中的存储中选择映像文件,建议使用 FileOpenPicker

需要了解的事项

技术

必备组件

Instructions

步骤 1:打开文件选取器

创建 FileOpenPicker对象,并设置用于选择图像的 ViewMode 、SuggestedStartLocationFileTypeFilter。 调用 PickSingleFileAsync 方法。

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

PickSingleFileAsync完成后,会从它返回的 IAsyncOperation接口获取文件流。

步骤 2:获取文件流

声明在文件选取器异步操作返回后运行的完成处理程序。 使用 GetResults 方法检索文件并获取文件流对象。

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

下一步将 IRandomAccessStream对象转换为可以传递给 WICIStream。

步骤 3:转换文件流

使用 CreateStreamOverRandomAccessStream 函数转换文件流。 Windows运行时 API 使用 IRandomAccessStream表示流,而 WIC使用 IStream

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

备注

若要使用 CreateStreamOverRandomAccessStream函数,应在项目中包括 shcore.h。

步骤 4:创建 WIC 解码器并获取帧

使用 IWICImagingFactory::CreateDecoderFromStream方法创建 IWICBitmapDecoder对象。

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

使用 IWICBitmapDecoder::GetFrame 方法从解码器获取图像的第一帧。

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

步骤 5:创建 WIC 转换器并初始化

使用 WIC将图像转换为 BGRA 颜色格式。 IWICBitmapFrameDecode 将返回图像的本机像素格式,例如 JPEG 存储在 GUID _ WICPixelFormat24bppBGR 中。 但是,作为 Direct2D 的性能优化,我们建议转换为 WICPixelFormat32bppPBGRA。

  1. 使用 IWICImagingFactory::CreateFormatConverter 方法创建 IWICFormatConverter对象。

        ComPtr<IWICFormatConverter> converter;
        DX::ThrowIfFailed(
            m_wicFactory->CreateFormatConverter(&converter)
            ); 
    
    
  2. 初始化格式转换器以使用 WICPixelFormat32bppPBGRA 并传递位图帧。

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

IWICFormatConverter接口派生自 IWICBitmapSource接口,因此可以将转换器传递给 位图源效果。

步骤 6:创建效果并传递 IWICBitmapSource

使用 CreateEffect方法使用 Direct2D设备上下文 创建 图源 ID2D1Effect 对象

使用 ID2D1Effect::SetValue 方法将 D2D1 _ BITMAPSOURCE _ PROP _ WIC _ BITMAP _ SOURCE 属性设置为 WIC 格式转换器

备注

图源效果不会像许多 Direct2D效果一样采用 SetInput方法的输入。 相反 ,IWICBitmapSource 对象被指定为属性。

    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.

现在,你具有 位图源 效果,可以使用它作为任何 ID2D1Effect 的输入并创建效果图。

完整示例

下面是此示例的完整代码。

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.
}