WPFでローカルファイルの画像を表示する方法まとめ
WPFでローカルファイルの画像を表示する方法まとめ
XAML の Image 要素 ( System.Windows.Controls.Image
) の Source プロパティ( System.Windows.Media.ImageSource
型)にソースを指定すると画像が表示できる。
ソースの指定の仕方が何種類かある。
- XAML 上で Source に画像のファイルパスを指定
- Source に
System.Windows.Media.Imaging.BitmapImage
を Binding - Source に
System.Windows.Media.Imaging.BitmapSource
を Binding - Source に
System.Windows.Media.ImageSource
を Binding
継承関係
System.Windows.Media.ImageSource
> System.Windows.Media.Imaging.BitmapSource
> System.Windows.Media.Imaging.BitmapImage
System.Windows.Media.Imaging.BitmapImage
はSystem.Windows.Media.Imaging.BitmapSource
を継承している。System.Windows.Media.Imaging.BitmapSource
はSystem.Windows.Media.ImageSource
を継承している。
結局のところどの方法も BitmapImage を生成している。(「XAML 上で Source に画像のファイルパスを指定」を除く) BitmapImage の生成の仕方にもいくつかの方法がある。
ソースの指定の仕方
XAML 上で Source に画像のファイルパスを指定
<!-- XAML --> <Image Source="C:/hoge.jpg"/>
- これが一番簡単だと思います。
- 表示中はファイルがロックされる。
- 表示する大きさに関わらず source image と同じ大きさの decoded image が生成される。
- サムネイルのように小さく表示したいだけならメモリの使い方に無駄があるということになる。
- ファイルパスも Binding できるっぽいっすね。
ダメな例
<!-- XAML --> <Image x:Name="image"/>
// cs this.image.Source = "C:/hoge.jpg";
詳しくはこちらの公式ドキュメント Image.Source Property (Windows) コードでの Source の設定(リンク切れ)
Source に System.Windows.Media.Imaging.BitmapImage
を Binding
<!-- XAML --> <Image Source="{Binding Path=BmpImg}"/>
// CS public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); Sample sample = new Sample(); sample.BmpImg = sample.GetBitmapImage(@"C:\hoge.jpg"); this.DataContext = sample; } class Sample { public BitmapImage BmpImg { get; set; } public BitmapImage GetBitmapImage(string file) { var bmpImg = new BitmapImage(); bmpImg.BeginInit(); // オプションその 1 : 読込元のファイルがロックされない。 bmpImg.CacheOption = BitmapCacheOption.OnLoad; // オプションその 2 : decoded image の幅を指定できる。サムネイル用に小さく表示する場合などのメモリ節約に有効。 bmpImg.DecodePixelWidth = 50; // オプションその 3 : わからん bmpImg.CreateOptions = BitmapCreateOptions.None; bmpImg.UriSource = new Uri(file); bmpImg.EndInit(); // オプションその 4 : スレッドをまたいで BitmapImage を受け渡す場合に必要な操作。 // この例では意味ないと思います。知らんけど。 // 例えば、このメソッドを非同期にするなら必要になる。 bmpImg.Freeze(); return bmpImg; } } }
- ネットによく書いてあるやつ。
- このままだとメモリリークする、らしい。俺が遭遇したWPFイメージコントロールのメモリーリークと回避法(?)の1つ - C#でプログラミングあれこれ
関連
- WPF での画像読み込みをバックグラウンドで処理する – ちとくのホームページ
- [WPF] BitmapImage の生成・初期化を非同期で行う際のメモリの問題について - pierre3のブログ
- ファイルから解放可能なBitmapImageを読み込む。 - Neareal
Source に System.Windows.Media.Imaging.BitmapSource
を Binding
BitmapImage から BitmapSource へのただのアップキャストなので「Source に System.Windows.Media.Imaging.BitmapImage
を Binding」と同じ。
public BitmapSource BmpSrc { get; set; } public BitmapSource GetBitmapImage(string file) { var bmpImg = new BitmapImage(); // 省略 return bmpImg; // ただのアップキャストとなので暗黙的にキャストできる }
- BitmapImage で渡すか、 BitmapSource で渡すかの違いはよくわからない。
- 詳しい・・・イメージング | プログラミングの宝石箱 Wiki | FANDOM powered by Wikia
Source に System.Windows.Media.ImageSource
を Binding
ただのアップキャスト。大したことないから書かない。これ書いたの昔だから忘れた。
BitmapImage の生成
普通に
これ書いたの昔だから忘れた。
GDI+
Bitmap 型 ( System.Drawing.Bitmap )
- System.Drawing.Imgae を継承
- 画像ファイルのパスを指定して Bitmap 型のインスタンスを生成する。
// GDI ビットマップオブジェクトへのハンドルを返す。
IntPtr GetHbitmap();
Graphics 型 ( System.Drawing.Graphics )
- GDI+ 描画サーフェイス
- Win32由来 GDIとWPFの違い
- C#でBitmapで描いた画像をImageコントロールに表示してみた
static Graphics FromImage(Image image) void DrawImage(Image image, int x, int y, int width, int height)
System.Windows.Interop.Imaging
イメージ オブジェクトの作成に対するマネージとアンマネージの相互運用サポートを提供します。 * マネージリソースとアンマネージリソースの定義 - 周回遅れのブルース * System.Drawing.BitmapとImageSourceを相互変換する - nuits.jp blog
実装
下記の三つのメソッドはどれも縮小率を指定している。 書き方が微妙に違ってはいるが違いはない様子?
public static ImageSource GetImageSourceFromFile(string fileName, double reduction) { if (reduction <= 0) return null; BitmapSource source = null; using (var bmp = new Bitmap(fileName)) { var h = (int)(bmp.Height / reduction); var w = (int)(bmp.Width / reduction); var dest = new Bitmap(w, h); var g = Graphics.FromImage(dest); g.DrawImage(bmp, 0, 0, w, h); var hBmp = dest.GetHbitmap(); try { source = Imaging.CreateBitmapSourceFromHBitmap( hBmp, IntPtr.Zero, Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions() ); } finally { DeleteObject(hBmp); } } return source; } public static ImageSource GetImageSourceFromFile_TEST(string fileName, double reduction) { if (reduction <= 0) return null; BitmapSource source = null; using (var bmp = new Bitmap(fileName)) { var h = (int)(bmp.Height / reduction); var w = (int)(bmp.Width / reduction); var dest = new Bitmap(w, h); var g = Graphics.FromImage(dest); g.DrawImage(bmp, 0, 0, w, h); var hBmp = dest.GetHbitmap(); try { source = Imaging.CreateBitmapSourceFromHBitmap( hBmp, IntPtr.Zero, Int32Rect.Empty, BitmapSizeOptions.FromWidthAndHeight(h, w) ); } finally { DeleteObject(hBmp); } } return source; } public static ImageSource GetImageSourceFromFile_TEST2(string fileName, double reduction) { if (reduction <= 0) return null; BitmapSource source = null; using (var bmp = new Bitmap(fileName)) { var h = (int)(bmp.Height / reduction); var w = (int)(bmp.Width / reduction); var dest = new Bitmap(bmp.Width, bmp.Height); var g = Graphics.FromImage(dest); g.DrawImage(bmp, 0, 0, bmp.Width, bmp.Height); var hBmp = dest.GetHbitmap(); try { source = Imaging.CreateBitmapSourceFromHBitmap( hBmp, IntPtr.Zero, Int32Rect.Empty, BitmapSizeOptions.FromWidthAndHeight(h, w) ); } finally { DeleteObject(hBmp); } } return source; }
参考
- Ktouth Brand. on Web - VC#2008でWPFアプリに画像リソースを埋め込む
- 片鱗懐古のブログ: wpf : MemoryCacheを使ってBitmapSourceをキャッシュ
- WPF での画像読み込みをバックグラウンドで処理する – ちとくのホームページ
- WPFで非同期&キャンセル可能な画像の読み込みを行う - SourceChord
- WPFでBitmapFrame.Createなどの画像ロード処理を強制的にキャンセルさせる - SourceChord
- WPFでの画像処理の基本 - nuits.jp blog
- [WPF][C#]WPFで画像ビューワ作ってみた その2
- C#/WPFで作るデスクトップマスコット入門
- WPFで画像の読み込みを非同期で行いたい。async/awaitでのやりかた。
- ファイルから解放可能なBitmapImageを読み込む。 - Neareal
- byteデータをImageコントロールにBindingする - がりらぼ
WPFパフォーマンス関連の記事まとめ - Qiita に載っていたやつ
- 俺が遭遇したWPFイメージコントロールのメモリーリークと回避法(?)の1つ - C#でプログラミングあれこれ
- “Memory leak” with BitmapImage and MemoryStream — Faithlife Code Blog
- New WPF Features: Cached Composition – Lester's XAML Blog
- How can I keep a WPF Image from blocking if the ImageSource references an unreachable Url? - Stack Overflow
- Speeding up image loading in WPF using thumbnails – DDITDev
関係あるかわからんが
- チュートリアル: WPF アプリケーション内のアプリケーション データのキャッシュ | Microsoft Docs
- Download Debugging Tools for Windows - WinDbg | Microsoft Docs
- Debugging Tools for Windows(WinDbg)を導入する(Windows10世代) | riscascape.net
- graphics - How to use the GDI+ drawing in WPF? - Stack Overflow
- Finding Memory Leaks in WPF-based applications – WPF Performance and .NET Framework Client Profile
- バックグラウンド スレッドで UI 要素を作るとメモリリークする (WPF) | grabacr.nét
WrappingStream のやつ
- ご本人の GitHub のページ : WrappingStream class
- “Memory leak” with BitmapImage and MemoryStream — Faithlife Code Blog
- WrappingStream Implementation — Faithlife Code Blog