WriteableBitmapExを使ってみた
WPFで、画像データをにピクセル単位でアクセスする場合にはWriteableBitampを使いますが、
このクラス、いまいち使い勝手が悪い。。。
ピクセルデータに連続してアクセスする場合とかは、
わざわざunsafeコンテキストでBackBufferプロパティにアクセスしたり、、、と面倒だし。
このライブラリを使えば、ピクセル操作や、DrawLine, DrawCurveなどの図形描画の便利なメソッドで使えるようになります。
WriteableBitmapクラスの拡張メソッドとして作られているので、
「普通にWriteableBitmapクラスにこんなメソッドがあればいいのに」と思っていたのがそのまま実現された感じです。
WriteableBitmapEx
http://writeablebitmapex.codeplex.com/
Codeplexのページに使い方のサンプルが載ってますが、
WPFではうまく動作しない部分もあったので、備忘録として色々メモしときます。
対応環境
Silverlight/WindowsPhone/WPF/Metroアプリ(Windowsストアアプリ)に対応してるとのこと。
Silverlightで使ってるのはよく見かけますが、WPFでの使用例をあまり見かけないので、
簡単にまとめてみました。
準備
Nugetでインポートできるので、Nugetで検索して追加するだけでOK
・使い方
WriteableBitmapのインスタンス作成
WriteableBitmap wb = BitmapFactory.New(512, 512);
WriteableBitmapのコンストラクタは、WPF/Silverlightで形式が異なるけど、
このFactoryを使用することで、どっちでも使える書き方になります。
また、WPF版のWriteableBitampExでは、Pbgr32のフォーマットをで画像を扱わないといけないのですが、
そのフォーマットで作ってくれます。
別のフォーマットのWriteableBitmapのインスタンスは、以下のメソッドでフォーマットを変換してから使います。
ConvertToPbgra32Format
画像のクリア
指定した色で塗りつぶすときは、以下のように書く。
wb.Clear(Colors.Black);
画面をクリアするだけのサンプル
(xamlファイルには、imgTargetという名前のImageコントロールだけを配置)
public partial class MainWindow : Window { WriteableBitmap wb; public MainWindow() { InitializeComponent(); wb = BitmapFactory.New(512, 512); using (wb.GetBitmapContext()) { wb.Clear(Colors.Black); } imgTarget.Source = wb; } }
画像の読み込み
FromResourceというメソッドもあるみたいだけど、
WPFで使うとなぜか実行時に例外が出て落ちてしまう。。。
WriteableBitmapExのサンプルで用いている方法
このライブラリのソースと一緒に公開されてるサンプルでは、以下のようなメソッドを使ってリソースの画像を読み込んでました。
WriteableBitmap LoadBitmap(string path) { var img = new BitmapImage(); img.BeginInit(); img.CreateOptions = BitmapCreateOptions.None; var s = Application.GetResourceStream(new Uri(path, UriKind.Relative)).Stream; img.StreamSource = s; img.EndInit(); return BitmapFactory.ConvertToPbgra32Format(img); }
BitmapImageで読み込んでから変換する方法
アプリのリソースから画像を読み込みたい場合などでは、以下のような書き方をすると楽かも。
・ファイルシステム上の画像ファイルを指定する場合
wb = BitmapFactory.ConvertToPbgra32Format(new BitmapImage(new Uri(画像ファイルのパス, UriKind.Absolute)));
・リソースとしてアセンブリに含めた画像を参照する場合
wb = BitmapFactory.ConvertToPbgra32Format(new BitmapImage(new Uri("pack://application:,,,/Images/sample.jpg")));
↑リソースの画像を参照するときはpack URIで指定しないといけないっぽい。
GetBitmapContextメソッド
ピクセル操作の前に、GetBitmapContextメソッドを呼んで、最後にDisposeを呼ぶ必要がある。
⇒操作する範囲を、usingステートメントで囲う!!
using (bmp.GetBitmapContext()) { // ここで、描画に関する処理を書く }
描画
ピクセル単位の操作
SetPixel/GetPixelメソッド
こんな風に使える。
wb.SetPixel(10, 10, Colors.Red);
Color c = wb.GetPixel(10, 10);
線の描画とか
wb.DrawLine(0, 0, 512, 512, Colors.Red);
他にも、アンチエイリアスを行って描画する、DrawLineAaや、ブレゼンハムのアルゴリズムで描画するDrawLineBresenhamなどがある。
三角形/四角形/ポリゴン描画用メソッドもある。
wb.DrawTriangle(255, 0, 0, 511, 511, 511, Colors.Blue);
任意の4頂点の四角形
wb.DrawQuad(10, 0, 0, 511, 511, 511, 500, 0, Colors.Red);
幅・高さを指定して四角形を描画
wb.DrawRectangle(10, 10, 200, 300, Colors.Green);
楕円や曲線を描画するメソッド
wb.DrawEllipse(20, 20, 80, 50, Colors.Yellow);
他にも、ベジェ曲線の描画などのメソッドもあるけど省略。。。
塗りつぶしをする場合は、Draw○○ではなくFill○○というメソッドを使用する。
wb.FillRectangle(20, 20, 100, 100, Colors.White);
その他、画像に対する処理
・トリミング
画像の一部をトリミングして、別のインスタンスに代入するメソッド
var cropped = wb.Crop(50, 10, 200, 200);
・リサイズ
var resized = wb.Resize(200, 200, WriteableBitmapExtensions.Interpolation.Bilinear);
・回転
↓のメソッドは、90度単位での回転用のメソッド
var rotated = wb.RotateFree(90);
自由度回転を行うメソッド
var rotated = wb.RotateFree(20);
・反転
var flipped = wb.Flip(WriteableBitmapExtensions.FlipMode.Horizontal);
他にも、画像処理などで便利そうなメソッドもいっぱいあるみたい。