完成にしとく


予想図よりはグラフ用紙風表示とかしてなかったり手は抜いた。見た目を凝るのは別のゲームっぽいアプリで一生懸命やることにしよう。一応マウス位置をあらわす黒い四角だけは描いておいた。以下はMainForm.cs。Win32.csとHook.csは先日のやつから変更ない。
念のために操作をおさらい。

  1. CTRL+ALT+矢印でマウスカーソルが1ドットずつ動く。
  2. CTRL+ALT+SHIFT+矢印でマウスカーソルが10ドットずつ動く。
  3. CTRL+ALT+Cでマウス下画素がColorクラスにあわせて16進8桁の文字列としクリップボードに入る。

出力イメージ:Alpha('FF'固定)+Red(16進2桁)+Green(16進2桁)+Blue(16進2桁)


おっと忘れるところだった。ImageUtilsはjunki氏作の画像処理ライブラリである。→のブックマークのMemoNyanDumから入手ができる。大変便利なライブラリなので皆さんもぜひご活用いただきたい。

using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.Windows.Forms;
using System.ComponentModel;
using ImageUtils;
using garu.Util;

namespace garu.ColorPicker
{
    partial class MainForm : Form
    {
        KeyboardHook keyHook = new KeyboardHook();
        MouseHook mouHook = new MouseHook();

        const string MYTITLE = "Color Picker";
        const int ZOOM = 16;
        const int CAP_LEN = 15; // 奇数にすること
        const int FORM_LEN = ZOOM * CAP_LEN;

        string clipText;
        Bitmap screenImage;
        Bitmap formImage;

        public MainForm()
        {
            InitializeComponent();
            FormBorderStyle = FormBorderStyle.FixedToolWindow;
            Icon = new Icon(GetType(), "ColorPicker.ico");
            SetStyle(ControlStyles.Opaque, true);
            formImage = new Bitmap(FORM_LEN, FORM_LEN, PixelFormat.Format24bppRgb);
            ClientSize = formImage.Size;
            screenImage = new Bitmap(CAP_LEN, CAP_LEN, PixelFormat.Format24bppRgb);
            screenCapture();
            keyHook.KeyDown += delegate(object sender, KeyEventArgs e)
            {
                if (e.KeyCode == Keys.Escape)
                    Close();
                if (e.Control && e.Alt)
                {
                    int step = e.Shift ? 10 : 1;
                    Point pt = Cursor.Position;
                    switch (e.KeyCode)
                    {
                        case Keys.Left:
                            pt.X -= step;
                            break;
                        case Keys.Right:
                            pt.X += step;
                            break;
                        case Keys.Up:
                            pt.Y -= step;
                            break;
                        case Keys.Down:
                            pt.Y += step;
                            break;
                        case Keys.C:
                            Clipboard.SetText(clipText);
                            break;
                        default:
                            return;
                    }
                    e.Handled = true;
                    Cursor.Position = pt;
                    screenCapture();
                    Invalidate();
                }
            };
            mouHook.MouseMove += delegate(object sender, MouseEventArgs e)
            {
                if (Win32.WindowFromPoint(e.Location) == Handle)
                {
                    // MainForm上にマウスがある
                }
                else
                {
                    // 別アプリ上にマウスがある
                    screenCapture();
                    Invalidate();
                }
            };
        }

        void screenCapture()
        {
            Graphics screenGraphics = Graphics.FromImage(screenImage);
            screenGraphics.CopyFromScreen(
                Cursor.Position.X - CAP_LEN / 2, Cursor.Position.Y - CAP_LEN / 2,
                0, 0, screenImage.Size, CopyPixelOperation.SourceCopy);
            screenGraphics.Dispose();

            BmpProc24 src = new BmpProc24(screenImage);
            BmpProc24 dst = new BmpProc24(formImage);

            src.SetXY(CAP_LEN / 2, CAP_LEN / 2);
            Text = string.Format("{0} (R={1:X2} G={2:X2} B={3:X2})",
                MYTITLE, src.R, src.G, src.B);
            clipText = string.Format("FF{0:X2}{1:X2}{2:X2}",
                src.R, src.G, src.B);

            for (int y = 0; y < FORM_LEN; y++)
            {
                for (int x = 0; x < FORM_LEN; x++)
                {
                    src.SetXY(x / ZOOM, y / ZOOM);
                    dst.SetXY(x, y);
                    dst.R = src.R;
                    dst.G = src.G;
                    dst.B = src.B;
                }
            }

            const int center = (CAP_LEN / 2) * ZOOM;
            drawBox(dst, Color.Black, center, center, ZOOM, ZOOM);

            ImgUtils.CallDispose(src, dst);
        }

        void drawBox(BmpProc24 dst, Color color, int x, int y, int width, int height)
        {
            for (int i = 0; i < width - 1; i++)
            {
                dst.SetXY(x++, y);
                dst.R = color.R;
                dst.G = color.G;
                dst.B = color.B;
            }
            for (int i = 0; i < height - 1; i++)
            {
                dst.SetXY(x, y++);
                dst.R = color.R;
                dst.G = color.G;
                dst.B = color.B;
            }
            for (int i = 0; i < width - 1; i++)
            {
                dst.SetXY(x--, y);
                dst.R = color.R;
                dst.G = color.G;
                dst.B = color.B;
            }
            for (int i = 0; i < height - 1; i++)
            {
                dst.SetXY(x, y--);
                dst.R = color.R;
                dst.G = color.G;
                dst.B = color.B;
            }
        }

        protected override void OnPaint(PaintEventArgs e)
        {
            e.Graphics.DrawImage(formImage, 0, 0);
        }

        protected override void OnClosing(CancelEventArgs e)
        {
            ImgUtils.CallDispose(keyHook, mouHook, screenImage, formImage);
            base.OnClosing(e);
        }
    }
}