ファイルから解放可能なBitmapImageを読み込む。
About
ふつう、アプリケーション内で画像ファイルから WriteableBitmap や BitmapSource、Bitmap のインスタンスを作る場合には、対象のファイルはアプリケーション(プロセス)が占有し、ロックされて削除などすることができなくなります。これでは非常に不便です。そこでアプリケーションから解放して、対象のファイルを操作可能な状態にするように、画像データを読み込む方法についてまとめます。
- &ref(): File not found: "WpfApplication_LoadImageTest.zip" at page "Programming/.NetFramework/WPF/WriteableBitmap/LoadReleaseableBitmapImage";
- VisualStudio2012
- .Net4.5
HowTo
サンプルプロジェクトには、サンプル用の画像が用意されています。問題の解決法にはいくつかパターンがあるのですが、大きな差はないので主な2つをピックしました。いずれも特に解説することはないのですが、基本的には、Streamを利用して画像情報をメモリ上に展開し、それを複製した後に開放する、といった手順です。詳細は確認していませんが、BitmapImageをそのままコンストラクタから作ると、FileStreamが解放されない、などしているのではないでしょうか。
パターン1ではWriteableBitmapのインスタンスを生成しています。厳密にはBitmapFrameクラスの"Createメソッド"を利用して、ImageSource(BitmapSource)のインスタンスを生成しています。
パターン2ではBitmapImageをコンストラクタ以外から初期化しています。
string filePath = Environment.GetCommandLineArgs()[0] + "/../lena.bmp"; //アプリケーションが画像ファイルを占有するパターン。 BitmapImage bmpImage = new BitmapImage(new Uri(filePath)); this.image.Source = bmpImage; //占有しないパターン-1 MemoryStream data = new MemoryStream(File.ReadAllBytes(filePath)); WriteableBitmap wbmp = new WriteableBitmap(BitmapFrame.Create(data)); data.Close(); this.image.Source = wbmp; //占有しないパターン-2 BitmapImage bmpImage = new BitmapImage(); FileStream stream = File.OpenRead(filePath); bmpImage.BeginInit(); bmpImage.CacheOption = BitmapCacheOption.OnLoad; bmpImage.StreamSource = stream; bmpImage.EndInit(); stream.Close(); this.image.Source = bmpImage;
(補足)ImageSourceの問題
原因は良くわかっていませんが、パターン1の"BitmapFrame.Createメソッド"からBitmapSourceを生成し、それを直接UI上のImage.Sourceに代入すると、読み込んだはずの画像が反映されないパターンがあります。画像サイズなどの情報は適切に取得できていることが確認できたうえで、画面にフィードバックが返らないので、問題の調査にも一苦労します。
MemoryStream data = new MemoryStream(File.ReadAllBytes(filePath)); BitmapSource source = BitmapFrame.Create(data); data.Close(); this.image.Source = source;
この問題は先のパターン1のようにWriteableBitmapにしてしまえば解決することが分かりましたが、それ以上のことは何もわかっていません。ただ同じような問題にあたる人のために記録を残しています。StreamがCloseされたタイミングでBitmapSourceが画像データへの参照を失う、ということは考えにくいのですがね…(PixelHeightなどのデータが取れるため)。
- Reference