首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> VC >> VC++

螢幕取色器實作:三行 API 獲取任意像素 RGB 值

     編輯:VC++

前言

想知道螢幕上某個好看顏色的 RGB 值嗎?Windows GDI 提供極簡單的三步驟:取得螢幕 DC → 讀取游標位置像素 → 分解 RGB 分量。本文提供極精簡的 MFC 實作,可直接整合至專案或獨立執行。

核心代碼 (僅 15 行)

void CScreenColorPicker::PickColor(COLORREF& rgbOut)
{
    // 1. 取得全螢幕裝置內容
    HDC hScreenDC = ::GetDC(NULL);
    if (!hScreenDC) return;

    // 2. 取得游標位置並讀取像素
    CPoint pt;
    ::GetCursorPos(&pt);
    COLORREF color = ::GetPixel(hScreenDC, pt.x, pt.y);

    // 3. 釋放 DC 並分解 RGB
    ::ReleaseDC(NULL, hScreenDC);

    rgbOut = color;  // 呼叫端可用 GetRValue/GetGValue/GetBValue 取得分量
}

完整對話方塊類別範例

class CScreenColorPickerDlg : public CDialog
{
    // 控制項:三個靜態文字顯示 R/G/B、一個顏色預覽矩形
    CStatic m_stR, m_stG, m_stB, m_stPreview;
    CButton m_btnStartStop;

    BOOL m_bPicking = FALSE;
    UINT m_nTimerID = 1;

    afx_msg void OnTimer(UINT nIDEvent);
    afx_msg void OnBnClickedStartStop();
    afx_msg HBRUSH OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor);

    DECLARE_MESSAGE_MAP()
};

BEGIN_MESSAGE_MAP(CScreenColorPickerDlg, CDialog)
    ON_WM_TIMER()
    ON_BN_CLICKED(IDC_BTN_START_STOP, OnBnClickedStartStop)
    ON_WM_CTLCOLOR()
END_MESSAGE_MAP()

void CScreenColorPickerDlg::OnTimer(UINT nIDEvent)
{
    if (nIDEvent == m_nTimerID && m_bPicking)
    {
        COLORREF color;
        PickColor(color);

        // 更新介面
        m_stR.SetWindowText(CString(_T("R: ")) + std::to_wstring(GetRValue(color)).c_str());
        m_stG.SetWindowText(CString(_T("G: ")) + std::to_wstring(GetGValue(color)).c_str());
        m_stB.SetWindowText(CString(_T("B: ")) + std::to_wstring(GetBValue(color)).c_str());

        m_stPreview.Invalidate();  // 觸發 OnCtlColor 重繪預覽
    }
    CDialog::OnTimer(nIDEvent);
}

void CScreenColorPickerDlg::OnBnClickedStartStop()
{
    m_bPicking = !m_bPicking;
    if (m_bPicking)
    {
        SetTimer(m_nTimerID, 100, NULL);  // 100ms 輪詢
        m_btnStartStop.SetWindowText(_T("停止取色"));
    }
    else
    {
        KillTimer(m_nTimerID);
        m_btnStartStop.SetWindowText(_T("開始取色"));
    }
}

HBRUSH CScreenColorPickerDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{
    if (pWnd->GetDlgCtrlID() == IDC_ST_PREVIEW)
    {
        pDC->SetBkMode(TRANSPARENT);
        static CBrush brush;
        brush.DeleteObject();
        brush.CreateSolidBrush(m_lastColor);  // 需保存上次取得的色彩
        return brush;
    }
    return CDialog::OnCtlColor(pDC, pWnd, nCtlColor);
}

關鍵 API 對照表

API用途備註
GetDC(NULL)取得螢幕 DC對應 ReleaseDC(NULL, hDC) 釋放
GetCursorPos取得游標螢幕座標以螢幕左上角為原點
GetPixel讀取指定座標像素色彩回傳 COLORREF (0x00BBGGRR)
GetRValue/G/BValue巨集分解 RGB 分量定義於 windowsx.h

進階擴充

  • 放大鏡預覽: 在 OnPaint 以 StretchBlt 將游標周圍 20×20 區域放大 5 倍繪製於對話方塊。
  • 色碼複製: 加入「複製 #RRGGBB」按鈕,格式化 CString::Format(_T("#%02X%02X%02X"), R, G, B) 寫入剪貼簿。
  • 多採樣平均: 取 3×3 鄰域像素平均,減少雜訊。
  • 系統熱鍵: 註冊 RegisterHotKey (如 Ctrl+Alt+P) 全域啟動/停止,無需切換視窗焦點。

常見問題

  1. GetPixel 回傳 CLR_INVALID (0xFFFFFFFF): 座標超出螢幕範圍或 DC 失效,需檢查 pt.x < GetSystemMetrics(SM_CXSCREEN) 等。
  2. DirectX/全螢幕遊戲無法取色: 繞過 GDI 直接寫入顯存,需改用 Desktop Duplication API (Windows 8+) 或鉤子截圖。
  3. 高 DPI 縮放: 專案設定 DPI Awareness = Per Monitor V2,確保座標與像素 1:1 對應。

結語

三行核心 API 即可實作專業級螢幕取色器。理解 GetDC(NULL)、GetCursorPos、GetPixel 協作關係,不僅能快速開發取色工具,更是學習 GDI 底層繪圖管線的絕佳切入點。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved