如何使用 FilePicker 將影像載入 Direct2D 效果
示範如何使用 Windows::Storage::P ickers::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 方法建立 IWICBitmapDecoderDecoder 物件。
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.
}