スムーズなアニメーション、高フレーム レート、高パフォーマンスのメディア キャプチャと再生を使用して、ユニバーサル Windows プラットフォーム (UWP) アプリを作成します。
アニメーションをスムーズにする
UWP アプリの主な側面は、スムーズな操作です。 これには、"指にくっつく" タッチ操作、スムーズな画面切り替えとアニメーション、入力フィードバックを提供する小さなモーションが含まれます。 XAML フレームワークには、アプリのビジュアル要素のコンポジションとアニメーション専用のコンポジション スレッドと呼ばれるスレッドがあります。 コンポジション スレッドは UI スレッド (フレームワークと開発者コードを実行するスレッド) とは別であるため、複雑なレイアウト パスや拡張計算に関係なく、アプリは一貫したフレーム レートとスムーズなアニメーションを実現できます。 このセクションでは、コンポジション スレッドを使用して、アプリのアニメーションを滑らかに保つ方法を示します。 アニメーションの詳細については、「 アニメーションの概要」を参照してください。 集中的な計算を実行しながらアプリの応答性を高める方法については、「 UI スレッドの応答性を維持する」を参照してください。
依存アニメーションの代わりに独立したアニメーションを使用する
アニメーション化されるプロパティに対する変更はシーン内の残りのオブジェクトに影響しないため、独立したアニメーションは作成時に最初から最後まで計算できます。 したがって、独立したアニメーションは、UI スレッドではなくコンポジション スレッドで実行できます。 これにより、コンポジション スレッドが一貫した周期で更新されるため、スムーズな状態が維持されます。
これらの種類のアニメーションはすべて、独立している必要があります。
キー フレームを使用したオブジェクト アニメーション
ゼロ時間のアニメーション
Canvas.Left プロパティと Canvas.Top プロパティへのアニメーション
UIElement.Opacity プロパティへのアニメーション
型 ブラシ のプロパティに対するアニメーションは、SolidColorBrush.Color サブプロパティをターゲットにします。
これらの戻り値型のサブプロパティを対象とする場合の、次の UIElement プロパティへのアニメーション。
- RenderTransform の
- Transform3D
- プロジェクション
- クリップ
- RenderTransform の
依存アニメーションはレイアウトに影響するため、UI スレッドからの追加の入力なしでは計算できません。 依存アニメーションには、 Width や Height などのプロパティに対する変更 が含まれます。 既定では、依存するアニメーションは実行されず、アプリ開発者からのオプトインが必要です。 有効にすると、UI スレッドのブロックが解除されたままの場合はスムーズに実行されますが、フレームワークまたはアプリが UI スレッドで他の多くの作業を行っている場合は、吃音が始まります。
XAML フレームワークのほぼすべてのアニメーションは既定では独立していますが、この最適化を無効にするために実行できるアクションがいくつかあります。 これらのシナリオに特に注意してください。
- 依存アニメーションを UI スレッドで実行できるように EnableDependentAnimation プロパティを設定します。 これらのアニメーションを独立したバージョンに変換します。 たとえば、オブジェクトの幅と高さではなく、ScaleTransform.ScaleX と ScaleTransform.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 アプリでは、常に MediaPlayerElement の IsFullWindow プロパティを使用して、ウィンドウ全体のレンダリングを有効または無効にします。 これにより、メディアの再生中にシステム レベルの最適化が使用されます。
XAML フレームワークは、レンダリングされる唯一のコンテンツである場合にビデオ コンテンツの表示を最適化できます。その結果、使用する電力が少なくなり、フレーム レートが高くなるエクスペリエンスが実現します。 最も効率的なメディア再生のために、 MediaPlayerElement のサイズを画面の幅と高さに設定し、他の XAML 要素を表示しないようにします
クローズド キャプションや一時トランスポート コントロールなど、画面の全幅と高さを占める MediaPlayerElement に XAML 要素をオーバーレイする正当な理由があります。 メディアの再生を最も効率的な状態に戻す必要がない場合は、これらの要素 ( Visibility="Collapsed"
設定) を非表示にしてください。
非アクティブ化と電力の節約を表示する
アプリがビデオを再生しているときなど、ユーザーアクションが検出されなくなったときにディスプレイが非アクティブにならないようにするには、 DisplayRequest.RequestActive を呼び出します。
電源とバッテリーの寿命を節約するには、 DisplayRequest.RequestRelease を呼び出して、不要になったらすぐにディスプレイ要求を解放する必要があります。
表示要求を解放する必要がある状況を次に示します。
- ビデオの再生は、たとえば、帯域幅が制限されているため、ユーザーの操作、バッファリング、調整によって一時停止されます。
- 再生が停止します。 たとえば、ビデオの再生が完了しているか、プレゼンテーションが終了したとします。
- 再生エラーが発生しました。 たとえば、ネットワーク接続の問題やファイルの破損などです。
埋め込みビデオの側面に他の要素を配置する
多くの場合、アプリでは、ページ内でビデオが再生される埋め込みビューが提供されます。 MediaPlayerElement がページのサイズではなく、他の XAML オブジェクトが描画されているため、全画面表示の最適化が明らかに失われました。 MediaPlayerElement の周囲に罫線を描画して、意図せずにこのモードに入るのにご注意ください。
埋め込みモードの場合は、ビデオの上に XAML 要素を描画しないでください。 その場合、フレームワークはシーンを構成するために少し余分な作業を強制されます。 ビデオの上ではなく、埋め込みメディア要素の下にトランスポート コントロールを配置することは、このような状況に合わせて最適化する良い例です。 この画像では、赤いバーは一連のトランスポート コントロール (再生、一時停止、停止など) を示しています。
を用いた MediaPlayerElement
全画面表示ではないメディアの上にこれらのコントロールを配置しないでください。 代わりに、メディアがレンダリングされている領域の外側のどこかにトランスポート コントロールを配置します。 次の図では、コントロールはメディアの下に配置されます。
MediaPlayerElement のソースの設定を遅らせる
メディア エンジンは高価なオブジェクトであり、XAML フレームワークは dll の読み込みと大きなオブジェクトの作成を可能な限り遅らせます。 MediaPlayerElement は、ソースが Source プロパティを使用して設定された後に、この作業を強制されます。 ユーザーが本当にメディアを再生する準備ができたときに、これを設定すると、MediaPlayerElement に関連するコストの大部分をできるだけ遅らせることができます。
MediaPlayerElement.PosterSource の設定
設定 MediaPlayerElement.PosterSource にすると、XAML は、それ以外の場合に使用されていた GPU リソースを解放できます。 この API を使用すると、アプリはできるだけ少ないメモリを使用できます。
メディア スクラブを改善する
スクラブは、メディア プラットフォームが本当に応答性を高めるのに常に困難な作業です。 一般に、スライダーの値を変更することでこれを実現します。 これを可能な限り効率的にする方法に関するいくつかのヒントを次に示します。
- MediaPlayerElement.MediaPlayer の位置を照会するタイマーに基づいて、Slider の値を更新します。 タイマーには適切な更新頻度を使用してください。 Position プロパティは、再生中に 250 ミリ秒ごとにのみ更新されます。
- スライダーのステップ周波数のサイズは、ビデオの長さに合わせてスケーリングする必要があります。
- PointerPressed、PointerMoved、PointerReleased イベントをサブスクライブして、ユーザーがスライダーのサムをドラッグしたときに PlaybackRate プロパティを 0 に設定します。
- PointerReleased イベント ハンドラーで、スクラブ中に最適なスライダー操作を実現するために、メディアの位置をスライダーの位置と一致させるように手動で設定します。
ビデオ解像度とデバイスの解像度を一致させる
ビデオのデコードには多くのメモリと GPU サイクルがかかるため、表示される解像度に近いビデオ形式を選択します。 リソースを使用して 1080 ビデオをデコードしても、はるかに小さいサイズにスケールダウンする場合は意味がありません。 多くのアプリでは、同じビデオが異なる解像度でエンコードされていません。ただし、使用可能な場合は、表示される解像度に近いエンコードを使用します。
推奨される形式を選択する
メディア形式の選択は機密性の高いトピックであり、多くの場合、ビジネス上の意思決定によって決まります。 UWP パフォーマンスの観点からは、プライマリ ビデオ形式として H.264 ビデオを、推奨されるオーディオ形式として AAC と MP3 をお勧めします。 ローカル ファイルの再生では、MP4 はビデオ コンテンツに推奨されるファイル コンテナーです。 H.264 デコードは、最新のグラフィックス ハードウェアを介して高速化されます。 また、VC-1 デコード用のハードウェア アクセラレーションは幅広く利用できますが、市場に出回っているグラフィックス ハードウェアの大規模なセットでは、アクセラレーションは、フル スチーム レベルのハードウェア オフロード (VLD モード) ではなく、多くの場合、部分アクセラレーション レベル (または IDCT レベル) に制限されます。
ビデオ コンテンツ生成プロセスを完全に制御できる場合は、圧縮効率と GOP 構造のバランスを適切に保つ方法を理解する必要があります。 B 画像を使用して GOP サイズを比較的小さくすると、シーク モードやトリック モードのパフォーマンスが向上する可能性があります。
ゲームなどで短い待機時間のオーディオ効果を含める場合は、圧縮されていない PCM データを含む WAV ファイルを使用して、圧縮オーディオ形式に一般的な処理オーバーヘッドを削減します。
イメージ リソースを最適化する
イメージを適切なサイズにスケーリングする
イメージは非常に高い解像度でキャプチャされるため、イメージ データをデコードするときに 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>
DecodePixelWidth と DecodePixelHeight の単位は、既定では物理ピクセルです。 DecodePixelType プロパティを使用すると、この動作を変更できます。DecodePixelType を論理に設定すると、他の XAML コンテンツと同様に、システムの現在のスケール ファクターを自動的に考慮したデコード サイズになります。 したがって、たとえば、画像が表示される Image コントロールの Height プロパティと Width プロパティに一致させたい場合は、通常、DecodePixelType を 論理 に設定するのが適切です。そして、DecodePixelWidth と DecodePixelHeight を一致させる必要があります。 物理ピクセルを使用する既定の動作では、システムの現在のスケール ファクターを自分で考慮する必要があります。ユーザーが表示設定を変更した場合に備えて、スケール変更通知をリッスンする必要があります。
DecodePixelWidth/Height が画面に表示される画像よりも大きく明示的に設定されている場合、アプリは不必要に余分なメモリ (ピクセルあたり最大 4 バイト) を使用します。これにより、大きな画像に対してすぐにコストがかかります。 また、画像はバイリニア スケーリングを使用してスケールダウンされ、大規模な要因でぼやけて表示される可能性があります。
DecodePixelWidth/DecodePixelHeight が明示的に設定されている場合は、画像が画面に表示されるよりも小さいと、スケールアップされ、ピクセル化されて表示される可能性があります。
適切なデコード サイズを事前に決定できない場合は、XAML の自動的な適正サイズデコードに任せる必要があります。これを使用することで、DecodePixelWidth/DecodePixelHeight が明示的に指定されていない場合でも、適切なサイズで画像をデコードするよう最善を尽くします。
事前に画像コンテンツのサイズがわかっている場合は、明示的なデコード サイズを設定する必要があります。 また、指定されたデコード サイズが他の XAML 要素サイズに対して相対的な場合は、DecodePixelType を 論理 と併せて設定する必要があります。 たとえば、Image.Width と Image.Height でコンテンツ サイズを明示的に設定した場合、DecodePixelType を DecodePixelType.Logical に設定して、Image コントロールと同じ論理ピクセル ディメンションを使用し、BitmapImage.DecodePixelWidth または BitmapImage.DecodePixelHeight を明示的に使用して、イメージのサイズを制御して、メモリを大幅に節約できます。
デコードされたコンテンツのサイズを決定するときは、Image.Stretch を考慮する必要があることに注意してください。
最適サイズのデコード
明示的なデコード サイズを設定しない場合、XAML は、イメージをデコードして、含まれているページの初期レイアウトに従って画面上に表示される正確なサイズにメモリを節約しようとします。 可能であれば、この機能を利用するようにアプリケーションを記述することをお勧めします。 次のいずれかの条件が満たされている場合、この機能は無効になります。
は、BitmapImage または UriSourceを使用してコンテンツSetSourceAsync 設定した後、ライブ XAML ツリーに接続されます。 - イメージは 、SetSource などの同期デコードを使用してデコードされます。
- 不透明度 を 0 に設定するか、ホストイメージ要素、ブラシ、または親要素のいずれかに 表示 を 折りたたみ に設定することで、イメージは非表示になります。
- イメージ コントロールまたはブラシは、Noneの Stretch を使用します。
- このイメージは、NineGridとして使用されます。
-
CacheMode="BitmapCache"
は、image 要素または任意の親要素に設定されます。 - イメージ ブラシは四角形以外です (図形やテキストに適用される場合など)。
上記のシナリオでは、明示的なデコード サイズを設定することが、メモリ節約を実現する唯一の方法です。
ソースを設定する前に、常に BitmapImage をライブ ツリーにアタッチする必要があります。 マークアップで画像要素またはブラシを指定すると、それが自動的に適用されます。 以下に、"ライブ ツリーの例" という見出しの下に例を示します。 ストリーム ソースを設定するときは、 常に SetSource を使用せず 、代わりに SetSourceAsync を使用する必要があります。 また、ImageOpened イベントが発生するのを待っている間は、画像コンテンツ (不透明度がゼロまたは非表示) を非表示にしないようにすることをお勧めします。 これを行うことは判断が求められます。そうすると、自動サイズ調整によるデコードの恩恵を受けることはありません。 アプリで最初に画像コンテンツを非表示にする必要がある場合は、可能であればデコード サイズも明示的に設定する必要があります。
生きた木の例
例 1 (適切) - マークアップで指定されたユニフォームリソース識別子 (URI)。
<Image x:Name="myImage" UriSource="Assets/cool-image.png"/>
例 2 のマークアップ—コードビハインドで指定された URI。
<Image x:Name="myImage"/>
例 2 の背後コード (適切) - UriSource を設定する前に BitmapImage をツリーに接続する。
var bitmapImage = new BitmapImage();
myImage.Source = bitmapImage;
bitmapImage.UriSource = new URI("ms-appx:///Assets/cool-image.png", UriKind.RelativeOrAbsolute);
コードビハインドの例 2(悪い例)— BitmapImage の UriSource をツリーに接続する前に設定する。
var bitmapImage = new BitmapImage();
bitmapImage.UriSource = new URI("ms-appx:///Assets/cool-image.png", UriKind.RelativeOrAbsolute);
myImage.Source = bitmapImage;
キャッシュの最適化
キャッシュの最適化は、 UriSource を使用してアプリ パッケージまたは Web からコンテンツを読み込むイメージに対して有効です。 URI は基になるコンテンツを一意に識別するために使用され、内部的には XAML フレームワークはコンテンツを複数回ダウンロードまたはデコードしません。 代わりに、キャッシュされたソフトウェアまたはハードウェア リソースを使用してコンテンツを複数回表示します。
この最適化の例外は、画像が異なる解像度で複数回表示される場合です (明示的に指定することも、自動の適切なサイズのデコードを使用して指定することもできます)。 各キャッシュ エントリにはイメージの解像度も格納されます。必要な解像度に一致するソース URI を持つイメージが XAML で見つからない場合は、そのサイズで新しいバージョンがデコードされます。 ただし、エンコードされた画像データは再度ダウンロードされません。
そのため、アプリ パッケージからイメージを読み込むときに UriSource を 使用する必要があり、不要な場合はファイル ストリームと SetSourceAsync を使用しないようにする必要があります。
仮想化されたパネル内のイメージ (ListView など)
イメージがツリーから削除された場合 (アプリによって明示的に削除された場合、または最新の仮想化されたパネル内にあり、ビューからスクロールしたときに暗黙的に削除された場合) は、XAML は不要になったイメージのハードウェア リソースを解放することでメモリ使用量を最適化します。 メモリはすぐに解放されるのではなく、イメージ要素の 1 秒後にツリー内に存在しなくなったフレームの更新中に解放されます。
そのため、最新の仮想化パネルを使用して、イメージ コンテンツのリストをホストするように努める必要があります。
ソフトウェアでラスター化されたイメージ
イメージが四角形以外のブラシまたは NineGrid に使用されている場合、イメージにはソフトウェア ラスタライズ パスが使用され、イメージはまったくスケーリングされません。 さらに、ソフトウェアとハードウェアの両方のメモリにイメージのコピーを格納する必要があります。 たとえば、画像が楕円のブラシとして使用されている場合、大きくなる可能性のある完全な画像は内部に 2 回保存されます。 NineGrid または四角形以外のブラシを使用する場合、アプリはイメージを、レンダリングされるサイズに合わせて事前にスケーリングする必要があります。
バックグラウンド スレッドのイメージの読み込み
XAML には内部最適化があり、ソフトウェア メモリ内の中間サーフェスを必要とせずに、ハードウェア メモリ内のサーフェスに対してイメージの内容を非同期的にデコードできます。 これにより、ピーク時のメモリ使用量とレンダリング待機時間が短縮されます。 次のいずれかの条件が満たされている場合、この機能は無効になります。
- このイメージは、NineGridとして使用されます。
-
CacheMode="BitmapCache"
は、image 要素または任意の親要素に設定されます。 - イメージ ブラシは四角形以外です (図形やテキストに適用される場合など)。
ソフトウェアビットマップソース
SoftwareBitmapSource クラスは、BitmapDecoder、カメラ API、XAML などの異なる WinRT 名前空間間で相互運用可能な非圧縮イメージを交換します。 このクラスは、通常 WriteableBitmapに必要な追加のコピー
ソース情報を提供する SoftwareBitmap は、カスタム IWICBitmap を使用して再読み込み可能なバッキング ストアを提供するように構成することもできます。これにより、アプリはメモリを適切に再マップできます。 これは高度な C++ ユース ケースです。
アプリは、SoftwareBitmap と SoftwareBitmapSource を使用して、イメージを生成および利用する他の WinRT API と相互運用する必要があります。 あなたのアプリは、非圧縮イメージデータを読み込む際に、WriteableBitmapを使用する代わりに、SoftwareBitmapSource を使用する必要があります。
サムネイルに GetThumbnailAsync を使用する
画像のスケーリングのユース ケースの 1 つは、サムネイルの作成です。 DecodePixelWidth と DecodePixelHeight を使用して小さなバージョンの画像を提供することもできますが、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 つのデコードされたイメージに関連付けることができますが、同じデータを含み、メモリ ストリームごとに異なるデコードされたイメージを作成する複数のメモリ ストリームに対して同じ操作を行うことはできません。