アニメーション、メディア、画像の最適化

スムーズなアニメーション、高いフレーム レート、およびパフォーマンスの高いメディア キャプチャと再生を備えたユニバーサル Windows プラットフォーム (UWP) アプリを作成します。

アニメーションのスムーズ化

UWP アプリの重要な側面は、スムーズな対話式操作です。 これには、"指の動きに忠実な" タッチ操作、スムーズな切り替えやアニメーション、入力のフィードバックを返す小さな動作などがあります。 XAML フレームワークには、アプリの視覚要素の合成とアニメーション専用の、合成スレッドと呼ばれるスレッドがあります。 合成スレッドは UI スレッド (フレームワークと開発者コードを実行するスレッド) からは独立しているため、レイアウト パスや拡張計算が複雑でも、一貫したフレーム レートとスムーズなアニメーションをアプリで実現できます。 このセクションでは、合成スレッドを使って、アプリのアニメーションをスムーズにする方法について説明します。 アニメーションについて詳しくは、「アニメーションの概要」をご覧ください。 計算を集中的に実行している間のアプリの応答性の向上については、「UI スレッドの応答性の確保」をご覧ください。

依存型ではなく、独立型アニメーションを使う

アニメーション化されるプロパティに対する変更は、シーン内の残りのオブジェクトに影響を与えないため、独立型アニメーションは作成時の最初から最後まで計算できます。 そのため、独立型アニメーションは UI スレッドではなく合成スレッドで実行されます。 合成スレッドは一定の間隔で更新されるため、アニメーションをスムーズに実行し続けることができます。

次のようなアニメーションはすべて独立性が保証されます。

  • キー フレームを使ったオブジェクト アニメーション

  • 再生時間が 0 のアニメーション

  • Canvas.Left プロパティと Canvas.Top プロパティに対するアニメーション

  • UIElement.Opacity プロパティに対するアニメーション

  • SolidColorBrush.Color サブプロパティをターゲット設定した場合の、Brush 型のプロパティに対するアニメーション

  • これらの戻り値の型のサブプロパティをターゲット設定した場合の、次の UIElement プロパティに対するアニメーションには以下のようなものがあります。

依存型アニメーションはレイアウトに影響するため、計算に UI スレッドからの追加の入力が必要です。 依存型アニメーションには、WidthHeight などのプロパティへの変更があります。 依存型アニメーションは、既定では実行されず、アプリ開発者からのオプトインが必要です。 有効になると、UI スレッドがブロックされない限りスムーズに実行されますが、フレームワークやアプリの UI スレッドで他の作業が大量に行われると引っかかりが発生します。

XAML フレームワーク内のほぼすべてのアニメーションは、既定で独立して実行されますが、この最適化が無効になる操作がいくつかあります。 特に次のようなシナリオに注意してください。

  • 依存型アニメーションを UI スレッドで実行できるように EnableDependentAnimation プロパティを設定する。 そうしたアニメーションは、独立型バージョンに変換します。 たとえば、オブジェクトの WidthHeight ではなく、ScaleTransform.ScaleXScaleTransform.ScaleY をアニメーション化します。 画像やテキストなどのオブジェクトも拡大/縮小できます。 ScaleTransform がアニメーション化されている間のみ、フレームワークによってバイリニア スケーリングが適用されます。 画像やテキストは、常にきれいに表示されるように、最終的なサイズでもう一度ラスター化されます。
  • フレームごとに更新する。これは、実質的には依存型アニメーションです。 これの例には、CompositonTarget.Rendering イベントのハンドラーでの変換の適用があります。
  • CacheMode プロパティを BitmapCache に設定した要素で独立型と見なされるアニメーションを実行する。 これは、フレームごとにキャッシュをもう一度ラスター化する必要があるため、依存型と見なされます。

WebView または MediaPlayerElement はアニメーション化しない

WebView コントロール内の Web コンテンツは、XAML フレームワークによって直接レンダリングされることはないため、画面の他の部分と合成する追加の作業が必要になります。 この追加の作業は画面上でコントロールをアニメーション化する際に行われ、同期の問題 (HTML コンテンツがページ上の XAML コンテンツの他の部分と同期して動かないなど) が発生する可能性があります。 WebView コントロールをアニメーション化する必要がある場合は、アニメーションを実行している間、そのコントロールを WebViewBrush に置き換えます。

MediaPlayerElement のアニメーション化も同様に適切ではない方法です。 パフォーマンスが低下するだけでなく、再生中のビデオ コンテンツに裂け目のようなアーティファクトが発生することがあります。

この記事の MediaPlayerElement に関する推奨事項は、MediaElement にも適用されます。 MediaPlayerElement は Windows 10 バージョン 1607 でのみ利用できます。以前のバージョンの Windows 用のアプリを作成する場合は、MediaElement を使う必要があります。

無限アニメーションは慎重に使う

大部分のアニメーションは指定された時間内で実行されますが、Timeline.Duration プロパティを Forever に設定すると、アニメーションを無限に実行できます。 この無限アニメーションを使うのはできるだけ避けてください。これらが CPU リソースを消費し続けることで、CPU が低電力またはアイドル状態に移行できず、非常に短い時間でバッテリーを使い果たす可能性があるためです。

CompositionTarget.Rendering のハンドラーの追加は、無限アニメーションの実行と同じような効果があります。 通常、UI スレッドは実行する作業がある場合にのみアクティブになりますが、このイベントのハンドラーを追加すると、すべてのフレームが強制的に実行されます。 実行する作業がない場合はハンドラーを削除し、再び必要になったときに再登録してください。

アニメーション ライブラリを使う

Windows.UI.Xaml.Media.Animation 名前空間には、他の Windows アニメーションとの一貫性を備えた外観を持つ、高パフォーマンスかつスムーズなアニメーションのライブラリが含まれています。 関連クラスは名前に "Theme" が含まれています。関連クラスについては、「アニメーションの概要」をご覧ください。 このライブラリは、アプリの最初の表示や、状態とコンテンツの切り替えにアニメーションを設定するなど、一般的なアニメーション シナリオの多くに対応しています。 パフォーマンスを高め UWP UI との一貫性を強化するために、できるだけこのアニメーション ライブラリを使うことをお勧めします。

アニメーション ライブラリは、利用可能なすべてのプロパティをアニメーション化できるわけではありません。 アニメーション ライブラリが適用されない XAML シナリオについては、「ストーリーボードに設定されたアニメーション」を参照してください。

CompositeTransform3D のプロパティを個別にアニメーション化する

CompositeTransform3D の各プロパティを個別にアニメーション化して、必要なアニメーションのみを適用できます。 詳しい説明と例については、「UIElement.Transform3D」をご覧ください。 変換のアニメーション化について詳しくは、「ストーリーボードに設定されたアニメーション」および「キーフレームとイージング関数のアニメーション」をご覧ください。

メディア リソースの最適化

オーディオ、ビデオ、画像は、ほとんどのアプリがユーザーを引き付けるために使うコンテンツです。 メディアのキャプチャ レートが向上し、コンテンツが標準解像度から高解像度に移行しているため、そうしたコンテンツを格納、デコード、再生するために必要なリソースの量が増えています。 XAML フレームワークは UWP のメディア エンジンに追加された最新機能を基に構築されているため、アプリでそれらの機能を無料で利用できます。 ここでは、UWP アプリでメディアを活用するためのヒントをいくつか紹介します。

メディア ストリームの解放

メディア ファイルは、アプリが通常使うリソースの中で最も一般的かつ負荷の高いリソースに分類されます。 メディア ファイル リソースによってアプリのメモリ使用量のサイズが大幅に増大することがあるため、アプリの使用が終わったらすぐにメディアへのハンドルを忘れずに解放する必要があります。

たとえば、アプリが RandomAccessStream または IInputStream オブジェクトを使っている場合は、アプリの使用が終わったらこのオブジェクトで close メソッドを呼び出して、下位にあるオブジェクトを解放します。

可能な場合はビデオ再生を全画面表示

UWP アプリでは、フル ウィンドウのレンダリングを有効または無効にする場合、常に MediaPlayerElementIsFullWindow プロパティを使います。 そうすることで、メディアの再生中にシステム レベルの最適化が使われることが保証されます。

XAML フレームワークでは、レンダリングの対象がビデオ コンテンツだけの場合は、ビデオ コンテンツの表示を最適化することができます。その結果、消費電力が低減され、フレーム レートが改善されます。 メディアの再生を最適化するには、MediaPlayerElement のサイズを画面の幅と高さに設定し、他の XAML 要素を表示しないようにします。

画面全体を占める MediaPlayerElement の上に XAML 要素 (クローズド キャプションや一時的なトランスポート コントロールなど) をオーバーレイすることには正当な理由があります。 これらの要素でメディアの再生を最適な状態に戻す必要がない場合は、これらの要素を非表示にしてください (Visibility="Collapsed" を設定する)。

ディスプレイの非アクティブ化と消費電力の節約

アプリでビデオを再生しているときなど、無操作状態が検出されてもディスプレイの電源が切れないようにするためには、DisplayRequest.RequestActive を呼び出します。

消費電力とバッテリーの駆動時間を節約するため、不要になったらすぐに DisplayRequest.RequestRelease を呼び出して表示要求を解放してください。

表示要求を解放する必要があるのは、次のような場合です。

  • ユーザーの操作、バッファリング、限られた帯域幅のための調整などでビデオの再生が一時停止になる。
  • 再生が停止する。 たとえば、ビデオの再生が完了したり、プレゼンテーションが終了したりする。
  • 再生エラーが発生した。 たとえば、ネットワーク接続の問題や破損したファイル。

埋め込みビデオの横に他の要素を配置

アプリには、ページ内でビデオを再生する埋め込みビューが用意されていることがあります。 その場合は、MediaPlayerElement がページのサイズではなく、他に描画される XAML オブジェクトがあるため、全画面表示の最適化が行われません。 MediaPlayerElement の周りに境界線を描画すると、意図せずにこのモードになることに注意してください。

埋め込みモードの場合は、ビデオの上に重ねて XAML 要素を描画しないでください。 描画すると、画面を合成するためにフレームワークが追加作業を行うことになります。 この場合は、ビデオの上に重ねずに、たとえば、埋め込みメディア要素の下にトランスポート コントロールを配置すると、最適化が行われます。 次の画像では、赤色のバーが一連のトランスポート コントロール (再生、一時停止、停止など) を示しています。

MediaPlayerElement with overlaying elements

メディアが全画面ではないときは、メディアの上にこれらのコントロールを重ねて配置しないでください。 代わりに、メディアがレンダリングされる領域の外にトランスポート コントロールを配置します。 次の画像では、コントロールがメディアの下に配置されています。

MediaPlayerElement with neighboring elements

MediaPlayerElement のソースの遅延設定

メディア エンジンは負荷の高いオブジェクトです。XAML フレームワークでは、dll の読み込みと大きなオブジェクトの作成を可能な限り遅らせます。 MediaPlayerElement では、ソースが Source プロパティによって設定されると、この処理が強制的に実行されます。 ユーザーがメディアを再生する準備が実際に整った時点でソースを設定すると、MediaPlayerElement に関連する負担の大部分を可能な限り遅らせることができます。

MediaPlayerElement.PosterSource の設定

MediaPlayerElement.PosterSource を設定すると、XAML は一部の GPU リソースを解放できます。解放しないと、それらのリソースは使われたままになります。 この API を使うことで、アプリが使うメモリを最小限に抑えることができます。

メディアのスクラブの改善

メディア プラットフォームの応答性を高めるにあたってスクラブは常に困難を伴うタスクです。 一般的には、Slider の値を変更することで、これを実現します。 次に、スクラブ操作をできるだけ効率的にするためのヒントをいくつか示します。

  • Slider の値を MediaPlayerElement.MediaPlayerPosition を照会するタイマーに基づいて更新します。 タイマーに適切な更新頻度を設定します。 Position プロパティは再生中に 250 ミリ秒ごとにのみ更新します。
  • Slider のステップ間隔のサイズは、ビデオの長さに合わせて変える必要があります。
  • スライダーの PointerPressedPointerMovedPointerReleased イベントを取得して、ユーザーがスライダーのつまみをドラッグしたときに PlaybackRate プロパティを 0 に設定します。
  • PointerReleased イベント ハンドラーで、スクラブ中のつまみのスナップ動作を最適化するために、メディアの位置をスライダーの位置の値に手動で設定します。

ビデオ解像度とデバイス解像度の一致

ビデオのデコードにはメモリと GPU サイクルを大量に使うため、ビデオ形式には、表示するときのものに近い解像度を選んでください。 小さいサイズにスケールダウンするのに、リソースを使って 1080 のビデオをデコードするのは無駄です。 多くのアプリでは同じビデオを異なる解像度でエンコードできませんが、可能であれば、表示される解像度に近いエンコードを使うようにしてください。

メディア形式の選択は慎重な判断が必要になる場合があり、多くはビジネス上の意思決定が優先されます。 UWP のパフォーマンスの点から見ると、H.264 ビデオが最優先のビデオ形式で、推奨されるオーディオ形式は AAC と MP3 になります。 ローカル ファイルを再生するためのビデオ コンテンツのファイル コンテナーは MP4 がお勧めです。 最新のグラフィックス ハードウェアのほとんどは H.264 デコードのアクセラレーションに対応しています。 また、VC-1 デコードのハードウェア アクセラレーションは広く利用できるようになっているものの、市場のグラフィックス ハードウェアの多くで、アクセラレーションがフルストリーム レベルのハードウェア オフロード (VLD モード) ではなく、部分的なアクセラレーションのレベル (IDCT レベル) に制限されています。

ビデオ コンテンツ生成プロセスを完全に制御できる場合は、圧縮の効率性と GOP 構造を最適なバランスで両立する方法を見つける必要があります。 B ピクチャを持つ GOP のサイズを比較的小さくすることで、シークまたはトリック モードのパフォーマンスを向上できます。

ゲームなどで、待機時間の短い短時間のオーディオ エフェクトを含める場合、WAV ファイルと非圧縮の PCM データを使います。これにより圧縮オーディオ形式で一般的に発生する処理のオーバーヘッドを削減できます。

イメージ リソースを最適化する

画像の適切なサイズへの拡大/縮小

画像を非常に高い解像度でキャプチャすると、アプリで画像データをデコードする際の CPU 負荷が大きくなり、ディスクから画像を読み込んだときに大容量のメモリが使用されます。 ただし、画像を元のサイズよりも小さいサイズでのみ表示する場合、高解像度の画像をデコードしてメモリに保存するのは無意味です。 代わりに、DecodePixelWidth プロパティと DecodePixelHeight プロパティを使って、画面上に描画される正確なサイズの画像のバージョンを作成します。

してはいけない例:

<Image Source="ms-appx:///Assets/highresCar.jpg"
       Width="300" Height="200"/>    <!-- BAD CODE DO NOT USE.-->

代わりに、このように実行します。

<Image>
    <Image.Source>
    <BitmapImage UriSource="ms-appx:///Assets/highresCar.jpg"
                 DecodePixelWidth="300" DecodePixelHeight="200"/>
    </Image.Source>
</Image>

DecodePixelWidthDecodePixelHeight の単位は、既定では物理ピクセルです。 DecodePixelType プロパティを使って、この動作を変更できます。DecodePixelTypeLogical に設定すると、他の XAML コンテンツと同様に、デコード サイズで自動的に現在の倍率が考慮されます。 したがって、一般的には、DecodePixelTypeLogical に設定することをお勧めします。たとえば、DecodePixelWidthDecodePixelHeight を、画像が表示される Image コントロールの Height プロパティと Width プロパティと一致させるような場合です。 物理ピクセルを使用する既定の動作では、システムの現在の倍率を自分で考慮する必要があります。また、ユーザーが表示設定を変更する場合に備えて、スケール変更通知をリッスンする必要があります。

DecodePixelWidth/Height が明示的に画面に表示される画像よりも大きく設定されている場合、アプリは不必要に余分なメモリ (1 ピクセルあたり最大 4 バイト) を使用するため、大きい画像では急速に負荷が大きくなります。 また、画像はバイリニア スケーリングを使って縮小されるため、倍率が大きくなるとぼやけて見える原因となる可能性があります。

DecodePixelWidth/DecodePixelHeight が明示的に画面に表示される画像よりも小さく設定されている場合、画像は拡大され、ピクセル化されたように見える可能性があります。

事前に適切なデコード サイズを特定できない場合には、明示的な DecodePixelWidth/DecodePixelHeight が指定されていないときに、適切なサイズでの画像のデコードをベスト エフォート形式で試行する、XAML の適切なサイズの自動デコードを遅延させる必要があります。

事前に画像コンテンツのサイズがわかっている場合は、明示的にデコード サイズを設定する必要があります。 指定したデコード サイズが他の XAML 要素のサイズを基準としている場合は、併せて DecodePixelTypeLogical に設定することも必要です。 たとえば、Image.Width と Image.Height を使ってコンテンツのサイズを明示的に設定する場合、DecodePixelType を DecodePixelType.Logical に設定して Image コントロールと同じ論理ピクセル サイズを使用し、明示的に BitmapImage.DecodePixelWidth や BitmapImage.DecodePixelHeight を使って画像のサイズを制御することによって、大量のメモリ消費を抑えることができる可能性があります。

デコードされたコンテンツのサイズを決定するときに、Image.Stretch を考慮する必要があることに注意してください。

適切なサイズのデコード

明示的なデコード サイズを設定していない場合、XAML では、画像を表示するページの初期レイアウトに従って、画面に表示される正確なサイズで画像をデコードすることにより、メモリの消費を最大限に抑えようとします。 可能な限り、この機能を使用するような方法でアプリケーションを作成することをお勧めします。 次の条件のいずれかが満たされる場合、この機能は無効になります。

  • SetSourceAsync または UriSource を使ってコンテンツを設定した後、BitmapImage がライブ XAML ツリーに接続されている。
  • 画像が SetSource などの同期デコードを使用してデコードされる。
  • ホスト画像要素、ブラシ、親要素のいずれかで、Opacity を 0 に設定するか、VisibilityCollapsed に設定することによって、画像が非表示になっている。
  • 画像コントロールまたはブラシで使用する StretchNone になっている。
  • 画像が NineGrid として使用されている。
  • 画像要素またはいずれかの親要素で CacheMode="BitmapCache" が設定されている。
  • イメージ ブラシが四角形以外である (テキストや図形に適用する場合など)。

上記のシナリオでメモリの節約を実現するための方法は、明示的にデコード サイズを設定することだけです。

ソースを設定する前に、常に BitmapImage をライブ ツリーにアタッチする必要があります。 画像要素またはブラシがマークアップで指定されているときは、常にこれが自動的に適用されます。 例については、後の「ライブ ツリーの例」という見出しのトピックをご覧ください。 ストリーム ソースを設定する場合は、常に SetSource を使わずに、代わりに SetSourceAsync を使います。 ImageOpened イベントの発生を待機している間、画像コンテンツを非表示にする (不透明度を 0 にしたり、表示を折りたたむ) ことを回避することをお勧めします。 これを行うかどうかは議論の余地があります。これを行った場合、自動的に適切なサイズに調整されたデコードのメリットが得られません。 アプリで最初に画像コンテンツを非表示にする必要がある場合、可能であれば、明示的にデコード サイズも設定してください。

ライブ ツリーの例

例 1 (良い例): マークアップで指定された Uniform Resource Identifier (URI)。

<Image x:Name="myImage" UriSource="Assets/cool-image.png"/>

例 2 マークアップ: 分離コードで指定された URI。

<Image x:Name="myImage"/>

例 2 コードビハインド (良い例): ツリーに BitmapImage を接続してから UriSource を設定する。

var bitmapImage = new BitmapImage();
myImage.Source = bitmapImage;
bitmapImage.UriSource = new URI("ms-appx:///Assets/cool-image.png", UriKind.RelativeOrAbsolute);

例 2 分離コード (悪い例): BitmapImage の UriSource を設定した後に、ツリーに BitmapImage を接続。

var bitmapImage = new BitmapImage();
bitmapImage.UriSource = new URI("ms-appx:///Assets/cool-image.png", UriKind.RelativeOrAbsolute);
myImage.Source = bitmapImage;

キャッシュの最適化

キャッシュの最適化は、UriSource を使って、アプリ パッケージまたは Web からコンテンツを読み込む画像について有効です。 URI は基になるコンテンツを一意に識別するために使用され、XAML フレームワークは内部でコンテンツを複数回ダウンロードまたはデコードしません。 代わりに、キャッシュされたソフトウェアまたはハードウェア リソースを使用して、コンテンツが複数回表示されます。

この最適化の例外は、画像がさまざまな解像度で複数回表示される場合 (これは明示的に指定することも、自動的に適切なサイズに調整されたデコードで指定することもできます) です。 キャッシュの各エントリには、画像の解像度も格納されます。XAML で必要な解像度に一致するソース URI を持つ画像が見つからない場合は、そのサイズで新しいバージョンがデコードされます。 ただし、エンコードされた画像データをもう一度ダウンロードすることはありません。

そのため、アプリ パッケージから画像を読み込む場合は、UriSource の使用を採用する必要があります。また、必要ではない場合に、ファイル ストリームと SetSourceAsync を使用しないでください。

仮想化されたパネル内の画像 (ListView など)

画像がツリーから削除された場合 (アプリによって明示的に削除された場合、最新の仮想化されたパネルにある場合やビューの外部にスクロールされて暗黙的に削除された場合)、XAML では、不要になった画像のハードウェア リソースを解放することによってメモリ使用量を最適化します。 メモリはすぐに解放されるのではなく、画像要素がツリーに存在しなくなってから 1 秒後に実行されるフレームの更新時にリリースされます。

そのため、最新の仮想化されたパネルを使用して、画像コンテンツの一覧をホストする必要があります。

ソフトウェアでラスタライズされた画像

画像が四角形以外のブラシや NineGrid 用に使用されている場合、画像の拡大縮小が行われない、ソフトウェア ラスタライズ パスが使用されます。 さらに、ソフトウェアとハードウェアの両方のメモリに画像のコピーを保存して必要があります。 たとえば、画像が楕円形のブラシとして使われる場合、大きい可能性がある画像全体は内部で 2 回保存されます。 NineGrid または四角形以外のブラシを使用する場合は、アプリで画像を事前に拡大縮小し、レンダリング時のおよそのサイズにしておく必要があります。

バックグラウンド スレッドによる画像の読み込み

XAML には内部の最適化機能があり、ソフトウェア メモリ内の中間サーフェスを使用せずに、ハードウェア メモリ内のサーフェスに非同期的に画像の内容をデコードすることができます。 これにより、ピーク メモリ使用量とレンダリングの待機時間が減少します。 次の条件のいずれかが満たされる場合、この機能は無効になります。

  • 画像が NineGrid として使用されている。
  • 画像要素またはいずれかの親要素で CacheMode="BitmapCache" が設定されている。
  • イメージ ブラシが四角形以外である (テキストや図形に適用する場合など)。

SoftwareBitmapSource

SoftwareBitmapSource クラスは、さまざまな WinRT 名前空間 (BitmapDecoder など)、カメラ API、XAML の間で、相互運用可能な非圧縮画像を交換します。 このクラスを使用すると、WriteableBitmap で通常必要となる余分なコピーが不要になり、ピーク メモリ使用量とソースから画面表示までの待機時間が削減されます。

ソース情報を提供する SoftwareBitmap は、カスタム IWICBitmap を使用するように構成して、再読み込み可能なバッキング ストアを提供することもできます。これにより、アプリは必要に応じてメモリを再マップできます。 これは、高度な C++ の使用事例です。

画像を生成および使用する他の WinRT API と相互運用するには、アプリで SoftwareBitmapSoftwareBitmapSource を使う必要があります。 また、アプリで非圧縮画像データを読み込むときには、WriteableBitmap を使用する代わりに、SoftwareBitmapSource を使用する必要があります。

GetThumbnailAsync を使ったサムネイル

画像を拡大/縮小する使用事例として、サムネイルの作成があります。 DecodePixelWidthDecodePixelHeight を使って画像の縮小版を作ることができますが、UWP には、サムネイルを取得するためのもっと効率的な API が用意されています。 GetThumbnailAsync はファイル システムに既にキャッシュされている画像のサムネイルを提供します。 この方法では、画像を開いたり、デコードしたりする必要がないため、XAML の API よりもパフォーマンスが向上します。

FileOpenPicker picker = new FileOpenPicker();
picker.FileTypeFilter.Add(".bmp");
picker.FileTypeFilter.Add(".jpg");
picker.FileTypeFilter.Add(".jpeg");
picker.FileTypeFilter.Add(".png");
picker.SuggestedStartLocation = PickerLocationId.PicturesLibrary;

StorageFile file = await picker.PickSingleFileAsync();

StorageItemThumbnail fileThumbnail = await file.GetThumbnailAsync(ThumbnailMode.SingleItem, 64);

BitmapImage bmp = new BitmapImage();
bmp.SetSource(fileThumbnail);

Image img = new Image();
img.Source = bmp;
Dim picker As New FileOpenPicker()
picker.FileTypeFilter.Add(".bmp")
picker.FileTypeFilter.Add(".jpg")
picker.FileTypeFilter.Add(".jpeg")
picker.FileTypeFilter.Add(".png")
picker.SuggestedStartLocation = PickerLocationId.PicturesLibrary

Dim file As StorageFile = Await picker.PickSingleFileAsync()

Dim fileThumbnail As StorageItemThumbnail = Await file.GetThumbnailAsync(ThumbnailMode.SingleItem, 64)

Dim bmp As New BitmapImage()
bmp.SetSource(fileThumbnail)

Dim img As New Image()
img.Source = bmp

1 回だけの画像のデコード

画像が複数回デコードされないようにするには、メモリ ストリームを使わずに、URI から Image.Source プロパティを割り当てます。 XAML フレームワークでは、複数の場所にある同じ URI をデコードされた 1 つの画像に関連付けることができます。しかし、同じデータを含む複数のメモリ ストリームに対しては同じ処理を行うことができず、メモリ ストリームごとにデコードされた画像を作成します。