System.Drawing.BitmapをWPF用に変換

.NETで画像リソースやOpenCVLink の.NETラッパーEmguLink から画像データを得ようとするとSystem.Drawing.Bitmapインスタンスになるのですが、WPFで直接読み込む方法がないようです。というわけで変換になるのですが、これがちと曲者っぽいので備忘録。

Stream経由

コードが短くて済むのは一旦StreamにBMP形式(昨今メモリは潤沢にあるのでPNG等圧縮する必要はないかと)で保存、それを読みこませる方法。

using System.Windows.Controls;
using System.Drawing;
using System.IO;
(省略)
Bitmap bmp = (何か);
using (Stream st = new MemoryStream())
{
    bmp.Save(st, ImageFormat.Bmp);
    st.Seek(0, SeekOrigin.Begin);
    image1.Source = BitmapFrame.Create(st, BitmapCreateOptions.None, BitmapCacheOption.OnLoad);
}

この方法が曲者なのはBitmapFrame.CreateがStream読み込みを同期でするのか非同期なのかよく分からない所。非同期で上のコードだと読み込み完了前にStreamが破棄される可能性が高いので失敗(例外は出ず画像が表示されない)。とは言え読み込み終わってもStreamは自動的には閉じられないようなので、放おっておくとガベージコレクション任せということでしょうか。

ネット上の画像を同期読み込みするとBitmapFrame.Createで処理がブロックされるため非同期にするのでしょうけど、同期と非同期の切替条件が今ひとつはっきりしない。私の環境(Windows7 x64、Visual C# 2010 Express、.NET Framework 4 Client Profile)だとFileStreamとMemoryStreamは同期、WebResponseから得るStreamは非同期になるようでしたが、環境や将来的に変わるかもしれない。

非同期になると読み込み中はBitmapFrameインスタンスのIsDownloadingがtrueになり、完了時にDownloadCompletedイベントが飛ぶ(同期だと飛ばない)みたいなのでプロパティをチェックしてイベントハンドラでStreamを閉じるという方法もありますが、イベントハンドラをセットする前に読み込みが完了する可能性がゼロではないため、ちと不安。まぁCreateの直後にやればまず大丈夫でしょうけど。

HBitmap経由

Unmanagedに抵抗がなければ、こちらの方がある意味悩まなくて済むかと。

using System.Windows.Controls;
using System.Drawing;
using System.IO;
(省略)
[System.Runtime.InteropServices.DllImport("gdi32.dll")]
public static extern bool DeleteObject(IntPtr hObject);
(省略)
Bitmap bmp = (何か);
IntPtr hBitmap = bmp.GetHbitmap();
try
{
    image1.Source = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(
        hBitmap,
        IntPtr.Zero,
        Int32Rect.Empty,
        System.Windows.Media.Imaging.BitmapSizeOptions.FromEmptyOptions());
}
finally
{
    DeleteObject(hBitmap);
}

LateBoundBitmapDecoderLink なんてもの別途用意しているんだから、自動で同期・非同期を切り替えるのはやらなくていいと思う、個人的には。

[参考]

— posted by mu at 01:05 pm   commentComment [2]  pingTrackBack [0]

この記事に対するコメント・トラックバック [2件]

Up1. osamuk — 2013/07/22@21:01:00

BitmapDecoder内で、ストリームが(!stream.CanSeek)のときLateBoundBitmapDecoderが使われてました。

Owner Comment mu  2013/08/04@15:12:32

なるほど、CanSeekで見分けているのか。参考になりました。

この記事に対する TrackBack URL:

設定によりTB元のページに、こちらの記事への言及(この記事へのリンク)がなければ、TB受付不可となりますのであらかじめご了承下さい。

コメントをどうぞ。 名前(ペンネーム)と画像認証のひらがな4文字は必須で、ウェブサイトURLはオプションです。

ウェブサイト (U):

タグは使えません。http://・・・ は自動的にリンク表示となります

:) :D 8-) ;-) :P :E :o :( (TT) ):T (--) (++!) ?;w) (-o-) (**!) ;v) f(--; :B l_P~ (QQ)

     

[X] [Top ↑]

T: Y: ALL: Online:
ThemeSwitch
  • Basic
Created in 0.0179 sec.
prev
2012.3
next
        1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 31