C#取色器
闲来无事,就写了一个取色器。原理其实很简单,只需要两步,
- 获取鼠标光标的位置,
- 获取当前鼠标光标的位置的RGB颜色值。
获取鼠标光标的位置:
System.Drawing.Point p = MousePosition;
获取指定坐标的RGB颜色值,这里我们需要用到1个WIN32的API函数:GetPixel。
GetPixel函数的作用是检索坐标点的像素的RGB颜色值,函数原型为COLORREF GetPixel(HDC hdc, int nXPos, int nYPos)
由于这个是系统提供的API函数,所以在C#中我们无法直接使用,我们需要把它"翻译"一下,以便让C#调用:
/// <summary> /// 该函数检索指定坐标点的像素的RGB颜色值。 /// </summary> /// <param name="hDC">设备环境句柄。</param> /// <param name="nXPos">指定要检查的像素点的逻辑X轴坐标。</param> /// <param name="nYPos">指定要检查的像素点的逻辑Y轴坐标。</param> /// <returns>返回值是该象像点的RGB值。如果指定的像素点在当前剪辑区之外;那么返回值是CLR_INVALID。</returns> [DllImport("gdi32")] public static extern uint GetPixel(IntPtr hDC, int nXPos, int nYPos);
该函数的X,Y坐标我们已经获取到了,但是设备环境句柄hDC如何获取呢,这里我们又要用到一个WIN32的API函数:GetDC。
GetDC函数的作用是检索显示设备上下文环境的句柄,函数原型为HDC GetDC(HWND hWnd)
"翻译"如下:
/// <summary> /// 该函数检索一指定窗口的客户区域或整个屏幕的显示设备上下文环境的句柄, /// 以后可以在GDI函数中使用该句柄来在设备上下文环境中绘图。 /// </summary> /// <param name="hWnd">设备上下文环境被检索的窗口的句柄,如果该值为NULL,GetDC则检索整个屏幕的设备上下文环境。</param> /// <returns>如果成功,返回指定窗口客户区的设备上下文环境;如果失败,返回值为Null。</returns> [DllImport("user32")] public static extern IntPtr GetDC(IntPtr hWnd);
由于是非托管代码,所以获取到的环境句柄,我们需要手动释放掉。这里又要用到一个API函数:ReleaseDC
ReleaseDC函数的作用是该函数释放设备上下文环境,函数原型为int ReleaseDC(HWND hWnd, HDC hdc)
"翻译"如下:
/// <summary> /// 该函数释放设备上下文环境(DC)供其他应用程序使用。函数的效果与设备上下文环境类型有关。 /// 它只释放公用的和设备上下文环境,对于类或私有的则无效。 /// </summary> /// <param name="hWnd">指向要释放的设备上下文环境所在的窗口的句柄。</param> /// <param name="hDC">指向要释放的设备上下文环境的句柄。</param> /// <returns>如果释放成功,则返回值为1;如果没有释放成功,则返回值为0。</returns> [DllImport("user32")] public static extern int ReleaseDC(IntPtr hWnd, IntPtr hDC);
接下来开始写代码了。
页面布局如下:
整体的代码也是很简单的。
using System; using System.Drawing; using System.Windows.Forms; using JackyHelper; namespace GetColor { public partial class MainForm : Form { /// <summary> /// 显示设备上下文环境的句柄。 /// </summary> private IntPtr _hdc = IntPtr.Zero; /// <summary> /// 指向窗口的句柄。 /// </summary> private readonly IntPtr _hWnd = IntPtr.Zero; public MainForm() { InitializeComponent(); } private void timer1_Tick(object sender, EventArgs e) { System.Drawing.Point p = MousePosition; tsslCursorPos.Text = string.Format("X:{0},Y:{1}", p.X, p.Y); uint color = Win32Helper.GetPixel(_hdc, p.X, p.Y); byte r = Win32Helper.GetRValue(color); byte g = Win32Helper.GetGValue(color); byte b = Win32Helper.GetBValue(color); txtR.Text = Convert.ToString(r); txtG.Text = Convert.ToString(g); txtB.Text = Convert.ToString(b); picColor.BackColor = Color.FromArgb(r, g, b); txtHexColor.Text = "#" + r.ToString("X").PadLeft(2, '0') + g.ToString("X").PadLeft(2, '0') + b.ToString("X").PadLeft(2, '0'); } /// <summary> /// 取色按钮按下 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void btnGetColor_MouseDown(object sender, MouseEventArgs e) { _hdc = Win32Helper.GetDC(_hWnd); Cursor = Cursors.Cross; timer1.Enabled = true; } /// <summary> /// 取色按钮释放 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void btnGetColor_MouseUp(object sender, MouseEventArgs e) { Win32Helper.ReleaseDC(_hWnd, _hdc); Cursor = Cursors.Default; timer1.Enabled = false; Text = "取色器 By Jacky QQ:773091523"; } } }
/// <summary> /// 2014-12-5 21:43:51 /// 获取一个RGB颜色值中的红色强度值。 /// </summary> /// <param name="rgb">指定的RGB颜色值。</param> /// <returns></returns> public static byte GetRValue(uint rgb) { return (byte)rgb; } /// <summary> /// 2014-12-5 21:51:24 /// 获取一个RGB颜色值中的绿色强度值。 /// </summary> /// <param name="rgb">指定的RGB颜色值。</param> /// <returns></returns> public static byte GetGValue(uint rgb) { return (byte)(((ushort)(rgb)) >> 8); } /// <summary> /// 2014-12-5 21:52:37 /// 获取一个RGB颜色值中的蓝色强度值。 /// </summary> /// <param name="rgb">指定的RGB颜色值。</param> /// <returns></returns> public static byte GetBValue(uint rgb) { return (byte)(rgb >> 16); }
不足之处,还望各位大神指正,不胜感激。