【#UWP】 ビットマップの表示色を変える (Win2D.uwp 経由で Direct2D を使う)
例えば、 モノクロ 2 値やグレイスケールの画像を用意しておいて、表示するときに色を変えたいとかあるわけですよ。
上の画像は、 白と透明の 2 値画像ですが、 そのまま黒バックの上に表示すると、 次の画像のようになります (真ん中にカラーピッカーを追加しています)。
メモリー上のビットマップ内部では、 それぞれのピクセルは (R,G,B) = (0xff, 0xff, 0xff) か (0, 0, 0) のどちらかになっています。 そこで例えば、 (0xff, 0xff, 0xff) のピクセルだけを (0xff, 0, 0) に変えてやれば、 赤い画像に変わるわけです。
が、 それをピクセルごとにちまちまやってたんでは、 時間が掛かってしょうがありません。
昔、 8 x 8 = 64 ピクセルとか、 16 x 16 = 256 ピクセルとかを扱ってればよかった時代には、 当時の超非力な CPU でも、 256 回のループなんてのはまぁなんとかなりました (←いつの時代だよ!? w)。
今や、 1000 x 1000 ピクセルのビットマップとか平気で扱わなきゃならない時代。 1000 x 1000 ピクセルを全部舐めたら 100 万回ですよ!?
そんなわけで、 Direct2D の出番です♪
C# で書いている UWP アプリから DirectX を使うには、 SharpDX ってのもあります。
SharpDX は、 ほぼ DirectX をラップしただけの API なので、 生 DirectX プログラミングできるスキルがないと、 使うのはちょっと大変です。
例: WinRT/Metro TIPS:SharpDXを使ってDirectXで音声ファイルを再生するには?[ユニバーサルWindowsアプリ開発]
で、 それよりもっと WinRT API 寄りにガッツリとラップしてくれたのが、 Win2D です。
横文字得意な人向け ⇒ Introducing Win2D: GPU accelerated 2D graphics programming in the Windows Runtime - Building Apps for WindowsBuilding Apps for Windows (2014/9/5)
Win2D でどんなことが出来るのかは、 サンプルアプリを見るのが早いです。
⇒ Win2D Example Gallery
てことで、 Win2D を使って画像の色を変換するコードを作ってみましょう。
VS 2017 + C# 7 で書いています。
■ Win2D.uwp を導入する
NuGet から Win2D.uwp パッケージ をプロジェクトに導入します。
■ Win2D のキャンバスを配置する
XAML に Win2D の Canvas コントロールを置きます。
※ Windows.UI.Xaml.Controls の Canvas コントロールとは、 まったくの別物です。
まず、Microsoft.Graphics.Canvas.UI.Xaml 名前空間のエイリアスを定義して……
<Page
……略……
xmlns:Win2DC="using:Microsoft.Graphics.Canvas.UI.Xaml"
>
適当なところにWin2D の Canvas コントロールを置きます。
<Grid>
<Win2DC:CanvasControl x:Name="win2DCanvas" />
</Grid>
■ Win2D のキャンバスに画像を表示してみる
その一連の処理は、 Win2D Canvas コントロールの CreateResources イベントと Draw イベントで行います。
まず CreateResources イベントが叩かれるので、 そこで画像ファイルを Win2D の CanvasBitmap オブジェクトに読み込ませる処理をスタートします (非同期で書いて、 そのタスクを Win2D に返します)。
そして Draw イベントで、 DrawingSession オブジェクトの DrawImage メソッドを呼び出して、
先ほどの CanvasBitmap オブジェクトを描画させます (DrawingSession オブジェクトは、 Draw イベントの引数として渡されます)。
public MainPage()
{
this.InitializeComponent();
// 1. Win2D のビットマップ (ここに画像を読み込ませる)
CanvasBitmap bitmap = null;
// 2. Win2D Canvas の CreateResources イベントで画像を読み込む
win2DCanvas.CreateResources += (s, e) =>
{
// s is CanvasControl
// e is CanvasCreateResourcesEventArgs
e.TrackAsyncAction(LoadImageAsync(s).AsAsyncAction());
// 実際に画像を読み込むメソッド
async Task LoadImageAsync(CanvasControl canvas)
{
bitmap = await CanvasBitmap.LoadAsync(canvas, "Assets/ClockPanel.png");
// ここでは 1 個だけだが、必要なだけ何個でも!
}
};
// 3. Win2D Canvas の Draw イベントで bitmap を表示する
win2DCanvas.Draw += (s, e) =>
{
// s is CanvasControl
// e is CanvasDrawEventArgs
e.DrawingSession.DrawImage(bitmap, 0, 0);
};
}
■ 表示する画像に Direct2D のエフェクトを掛ける
さきほどは、 Win2D の CanvasBitmap オブジェクトをそのまま表示しました。
エフェクトを掛けるには、 CanvasBitmap オブジェクトにエフェクトを掛けた結果を、 先ほどと同様に DrawingSession.DrawImage メソッドに渡せば OK です。
例えば、 白色をカラーピッカーで選んだ色に変えるには、 Win2D の ColorMatrixEffect を使います。
// 上のコードの win2DCanvas.Draw イベントハンドラーだけを修正
// 3. Win2D Canvas の Draw イベントで bitmap を表示する
win2DCanvas.Draw += (s, e) =>
{
// s is CanvasControl
// e is CanvasDrawEventArgs
// 単にビットマップをそのまま表示するなら、↓これだけ
//e.DrawingSession.DrawImage(bitmap, 0, 0);
// ビットマップにエフェクトを掛ける
Color c = colorPicker.Color;
float r = c.R / 255.0f;
float g = c.G / 255.0f;
float b = c.B / 255.0f;
var colorMatrixEffect = new ColorMatrixEffect
{
Source = bitmap,
ColorMatrix = new Matrix5x4
{
M11 = r, M12 = 0, M13 = 0, M14 = 0,
M21 = 0, M22 = g, M23 = 0, M24 = 0,
M31 = 0, M32 = 0, M33 = b, M34 = 0,
M41 = 0, M42 = 0, M43 = 0, M44 = 1,
M51 = 0, M52 = 0, M53 = 0, M54 = 0
},
};
// エフェクトを掛けた結果を表示する
e.DrawingSession.DrawImage(colorMatrixEffect, 0, 0);
};
■ Win2D のキャンバスに再描画させる
再描画させるには、 Win2D Canvas オブジェクトの Invalidate メソッドを呼び出します (すると、 Draw イベントが叩かれます)。
例えば、 カラーピッカーで選択している色が変わったときに再描画させるには、
// 4. 必要に応じて Win2D Canvas を再描画
colorPicker.ColorChanged += (s, e) =>
{
win2DCanvas.Invalidate();
};
■ 完成♪
サンプルコードの全体は、 GitHub の Win2DColorMatrixEffect に置いてあります。
| 固定リンク
« 【#UWP】 CompactOverlay モード: Picture in Picture というか、「最前面に表示」するウィンドウを作る | トップページ | 【.NET Core】 プロジェクトを作ると 「project.assets.json が見つかりません」 エラー »
「プログラミング」カテゴリの記事
- 【.NET / Win8.1 ストアアプリ】 HttpClient で TLS 1.1 / 1.2 に対応するには(2018.06.17)
- 【VS2017 15.7pv2】 XAML のランタイム ツールに 「ヒートマップ」 が増えた(2018.03.28)
- 【.NET Core】 プロジェクトを作ると 「project.assets.json が見つかりません」 エラー(2018.02.10)
- 【#UWP】 ビットマップの表示色を変える (Win2D.uwp 経由で Direct2D を使う)(2017.08.23)
- 【#UWP】 CompactOverlay モード: Picture in Picture というか、「最前面に表示」するウィンドウを作る(2017.08.16)
「* プログラミング ( Metro スタイル )」カテゴリの記事
- 【.NET / Win8.1 ストアアプリ】 HttpClient で TLS 1.1 / 1.2 に対応するには(2018.06.17)
- 【VS2017 15.7pv2】 XAML のランタイム ツールに 「ヒートマップ」 が増えた(2018.03.28)
- 【#UWP】 ビットマップの表示色を変える (Win2D.uwp 経由で Direct2D を使う)(2017.08.23)
- 【#UWP】 CompactOverlay モード: Picture in Picture というか、「最前面に表示」するウィンドウを作る(2017.08.16)
- 【#UWP】 15063用の Acrylic Effect を、ちゃんと実装してみる(2017.08.05)
コメント