概要
@Kyome さんのRunCat の記事
・Windowsのタスクバーでもネコ走らせてみた🐈 - Qiita
https://qiita.com/Kyome/items/47aac4979933dac12263
を見ていて、個人的に猫に自由に任意の色を付けたくなったので、WinForm (GDI+) で カラー オーバーレイ
が出来ないか試してみた。
カラー オーバーレイ
とは?
Photoshopの レイヤー効果
でおなじみ(?)のやつ。
レイヤーの描画ピクセルのに色情報を任意の色に上書きするやつ。
私は良くレイヤーの描画モードを スクリーン
にした単色レイヤーを重ね合わせえて色味調整を行うことがよくあるのだけど。カラー オーバーレイ
だとカラーピッカーで選択中の色がリアルタイムで反映されるので、 スクリーン
レイヤーの色味調整でよく使ってる。
開発環境
プログラムは @Kyome22 さんの RunCat for windows を拝借させていただきました。ありがとうございます!
- Windows10 Pro v1809
- Visual Studio 20019 Community
- .NET Framework 4.7.2 (AnyCPU)
- ソース
- RunCat for windows @Kyome22
https://github.com/Kyome22/RunCat_for_windows
※forkさせて頂きました。 - RunCat4WinColors (RunCat for windows をforkした私のリポジトリ)
https://bitbucket.org/libraplanet/runcat4wincolors/
- RunCat for windows @Kyome22
概略
-
Graphics.DrawImage
のオプションで使えるSystem.Drawing.Imaging.ImageAttributes
で描画時に色を置換させる。 - 置換情報は
ImageAttributes.SetRemapTable()
にSystem.Drawing.Imaging.ColorMap
をセットして行う。 - 画像ソースは 白1色 + α の32bit画像
- 白に対して、置換色表はα = 0~255の 256パターン 用意する。
- 指定色のα値も反映させるため、置換後の色のα値にもかけ合わせる。
ColorMap[] map = new ColorMap[256];
for (int j = 0; j < map.Length; j++)
{
colorMap[j] = new ColorMap()
{
OldColor = Color.FromArgb(j, 255, 255, 255),
NewColor = Color.FromArgb(j * newColor.A / 255, newColor.R, newColor.G, newColor.B),
};
}
こんな塩梅。
Color.Transparent
もちゃんと効くのがありがたい。ただ、今回 カラー オーバーレイ(風)
としているのは、オーバーレイ対象が描画ピクセルでなく白だけだから。白(+α)以外の色があるとダメなので、実は オーバーレイ
としては若干用足らず(苦笑)。
サンプル ソース
カラー オーバーレイを試すにあたり、 @Kyome22 さんの RunCat for windows を勝手に利用させていただきました。ありがとうございます!
- RunCat4WinColors (RunCat for windows をforkしたプロジェクト)
https://bitbucket.org/libraplanet/runcat4wincolors/
バック バッファ を Imageオブジェクト
で白猫の画像の枚数分予め作っておき、下記メソッドが呼ばれたら バックバッファ の内容を更新し、Iconオブジェクト
を再生成する。 (バック バッファ はタスクトレイなので一応16x16。)
private void SetIconColor(Color catColor, Color bgColor)
{
Bitmap[] images = new Bitmap[]
{
Resources.cat16_0,
Resources.cat16_1,
Resources.cat16_2,
Resources.cat16_3,
Resources.cat16_4,
};
ImageAttributes attr = new ImageAttributes();
// remap color table
{
ColorMap[] colorMap = new ColorMap[256];
for (int j = 0; j < colorMap.Length; j++)
{
colorMap[j] = new ColorMap()
{
OldColor = Color.FromArgb(j, 255, 255, 255),
NewColor = Color.FromArgb(j * catColor.A / 255, catColor.R, catColor.G, catColor.B),
};
}
attr.SetRemapTable(colorMap);
}
// recreate icons
for (int i = 0; i < imgIconBufs.Length; i++)
{
Bitmap imgBuf = imgIconBufs[i];
Bitmap imgCat = images[i];
Icon ico = icons[i];
// bg
{
Graphics g = Graphics.FromImage(imgBuf);
g.Clear(bgColor);
g.DrawImage(imgCat, new Rectangle(new Point(0, 0), imgCat.Size), 0, 0, imgCat.Width, imgCat.Height, GraphicsUnit.Pixel, attr);
}
if(icons[i] != null)
{
// 再作成時、古いHICONは必ず廃棄する!
DestroyIcon(icons[i].Handle);
icons[i] = null;
}
icons[i] = Icon.FromHandle(imgBuf.GetHicon());
}
}
感想
一応それっぽいのは出来たけど、Bitmapクラス
から 生成した Iconクラス
を明示的に破棄するためにWin32APIの DestroyIcon
を呼ぶ必要があって プラットフォーム 呼び出し
( P/Invoke
) を使ってしまったのが若干つらい。とは言っても、64bit モジュールがちゃんとがある普通のWin32API だからそんなに気にしなくてもだけど。でもやっぱり.NETは可能な限りマネージド コードだけで行きたい。。。(びば!AnyCPU!)
ただ、最初はピクセル操作になると思っていたので Marshal.Copy
するくらいならと Unsafe
も覚悟していたけど、一応カラー オーバーレイ(?) 部分だけはマネージド コードだけなので、そこは助かった。今度は ColorMatrix
も試してみたい。ColorMapで愚直に対応表を作るとすると。2^32 - 1
で 4,294,967,295 パターンにもなり、とても現実的ではないので。。。
参考
-
Kyome22/RunCat_for_windows: A cute running cat animation on your windows taskbar.
https://github.com/Kyome22/RunCat_for_windows -
[C#]タスクトレイアイコンの画像を動的に変更する
http://nanoappli.com/blog/archives/1975 -
色を入れ替えて画像を描画する - .NET Tips (VB.NET,C#...)
https://dobon.net/vb/dotnet/graphics/setremaptable.html -
色を反転させた画像(ネガティブイメージ)を表示する - .NET Tips (VB.NET,C#...)
https://dobon.net/vb/dotnet/graphics/drawnegativeimage.html -
ColorMatrixによる色の変換 - C# - hesperus.net
https://www.hesperus.net/csharp/color_matrix.aspx