如何使用 FilePicker 将图像加载到 Direct2D 效果中
演示如何使用 Windows::Storage::Pickers::FileOpenPicker 将图像加载到 Direct2D 效果中。 如果您想要让用户从 Windows 应用商店应用中的存储中选择图像文件,建议使用 FileOpenPicker。
需要了解的事项
技术
先决条件
- 您需要 ID2D1DeviceContext 对象来创建效果。
- 您需要 IWICImagingFactory 对象来创建 WIC 对象。
说明
步骤 1:打开文件选取器
创建 FileOpenPicker 对象并设置 ViewMode、SuggestedStartLocation 和 FileTypeFilter 以选择图像。 调用 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 对象转换为可传递给 WIC 的 IStream。
步骤 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。
使用 IWICImagingFactory::CreateFormatConverter 方法创建 IWICFormatConverter 对象。
ComPtr<IWICFormatConverter> converter; DX::ThrowIfFailed( m_wicFactory->CreateFormatConverter(&converter) );
初始化格式转换器以使用 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 格式转换器。
注意
位图源效果不会从 SetInput 方法获取输入,如许多 Direct2D 效果。 而是将 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.
}