閑來無事,就寫了一個取色器。原理其實很簡單,只需要兩步,
- 獲取鼠標光標的位置,
- 獲取當前鼠標光標的位置的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); }
不足之處,還望各位大神指正,不勝感激。