最近はWebアプリの作成にも挑戦していますが、デザインセンスが悪いのか変な色使いしかできません。ではどうするか? こんなときは他のうまくやっていそうなサイトを参考にさせていただきましょう。ところが実際に同じ色にしようとしてもカラーコードがわからない場合があります。そこでクリックしたらその部分の色を表示するデスクトップアプリを自作することにしました。
やり方はマウスフックをしてどこであってもマウスボタンが押されたらイベント処理ができるようにします。マウスボタンが押されたらスクリーン全体をBitmapとして保存してクリックされた座標の色を調べます。実際に動かしてみると同じ色でべた塗りしている部分は問題なく色を取得できますが、写真などピクセルごとに色が異なる場合、直感とは大きく異なる色が取得されることがあります。
マウスフックに必要なものを最初に準備します。
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 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 |
using System.Runtime.InteropServices; using System.Diagnostics; public partial class Form1 : Form { const int WH_MOUSE_LL = 14; [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] private static extern IntPtr SetWindowsHookEx(int idHook, MouseHookProc lpfn, IntPtr hMod, uint dwThreadId); [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] private static extern bool UnhookWindowsHookEx(IntPtr hhk); [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam); [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)] private static extern IntPtr GetModuleHandle(string lpModuleName); [StructLayout(LayoutKind.Sequential)] private struct POINT { public int x; public int y; } IntPtr hookId = IntPtr.Zero; public IntPtr HookProcedure(int nCode, IntPtr wParam, IntPtr lParam) { int WM_LBUTTONDOWN = 0x0201; int WM_RBUTTONDOWN = 0x0204; if (nCode >= 0 && (wParam == (IntPtr)WM_LBUTTONDOWN || wParam == (IntPtr)WM_RBUTTONDOWN)) { // ここでマウスボタンが押されたらこの部分が実行される // Hook_ButtonDown(); } return CallNextHookEx(hookId, nCode, wParam, lParam); } // これがないとGCにより回収されてしまってCallbackOnCollectedDelegate例外で詰む delegate IntPtr MouseHookProc(int nCode, IntPtr wParam, IntPtr lParam); MouseHookProc mouseHookProc = null; public void Hook() { if (hookId == IntPtr.Zero) { using (Process curProcess = Process.GetCurrentProcess()) using (ProcessModule curModule = curProcess.MainModule) { mouseHookProc = HookProcedure; hookId = SetWindowsHookEx(WH_MOUSE_LL, mouseHookProc, GetModuleHandle(curModule.ModuleName), 0); } } } public void UnHook() { UnhookWindowsHookEx(hookId); hookId = IntPtr.Zero; } } |
次にデザイナで以下のようなものをつくります。
コンストラクタ内で結果を表示するラベルやPictureBoxの初期化をおこないます。クリックされたらクリックされた座標と色、ARGBを表示します。
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 32 33 34 35 36 37 |
public partial class Form1 : Form { public Form1() { InitializeComponent(); // 常にフォームを最前面で表示する this.TopMost = true; // すぐにマウスフックを開始する Hook(); // 初期の文字列を設定 labelPos.Text = "X = 0 Y = 0"; labelA.Text = "A = "; labelR.Text = "R = "; labelG.Text = "G = "; labelB.Text = "B = "; labelColorCode .Text= ""; // 見た目問題。見やすくするために太字フォントにする Font font = new Font(labelA.Font, FontStyle.Bold); labelPos.Font = font; labelColorCode.Font = font; labelA.Font = font; labelR.Font = font; labelG.Font = font; labelB.Font = font; // これも見た目の問題。例えば赤は赤色で表示する labelR.ForeColor = Color.Red; labelG.ForeColor = Color.Green; labelB.ForeColor = Color.Blue; pictureBox1.BorderStyle = BorderStyle.Fixed3D; } } |
終了するときはアンフックします。
1 2 3 4 5 6 7 8 9 |
public partial class Form1 : Form { protected override void OnClosed(EventArgs e) { UnHook(); base.OnClosed(e); } } |
これは指定された座標の色を取得するメソッドです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
public partial class Form1 : Form { Color GetColor(int x, int y) { // プライマリスクリーン全体 Bitmap bitmap = new Bitmap(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height); Graphics graphics = Graphics.FromImage(bitmap); // 画面全体をコピーする graphics.CopyFromScreen(new Point(0, 0), new Point(0, 0), bitmap.Size); // グラフィックスの解放 graphics.Dispose(); Color color = bitmap.GetPixel(x, y); bitmap.Dispose(); return color; } } |
クリックされたら色情報を表示します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
public partial class Form1 : Form { private void Hook_ButtonDown() { int x = Control.MousePosition.X; int y = Control.MousePosition.Y; Color color = GetColor(x, y); pictureBox1.BackColor = color; int a = color.A; int r = color.R; int g = color.G; int b = color.B; labelA.Text = "A = " + a.ToString("X2"); labelR.Text = "R = " + r.ToString("X2"); labelG.Text = "G = " + g.ToString("X2"); labelB.Text = "B = " + b.ToString("X2"); labelColorCode.Text = "#" + a.ToString("X2") + r.ToString("X2") + g.ToString("X2") + b.ToString("X2"); labelPos.Text = $"X = {x} Y = {y}"; } } |