ColorFinder'�Retrieve the Color of Any Pixel on the Desktop

Environment: VC6 SP4

Introduction

When developing Web pages or graphics, we frequently need a tool that will give us the RGB value of the color of a particular region in some other application's window. An example could be that you need to know the background color of a JPG image so that you can use the same color for the background of the Web page on which you will display the image. ColorFinder comes in handy exactly for this. You can use this tool to pick the color from any pixel on the Desktop.

How to Use the Tool

To get the color value, left-click on the dropper icon and, while keeping the left mouse button pressed down, move it over the Desktop. As the mouse moves, ColorFinder shows the color under the mouse pointer and at the same time it displays the pointer coordinates and the value of the color in decimal, hex, and HTML color formats. When the mouse pointer is over the color you want to select, release the mouse button. Then, using the buttons labeled ">" on the right of any of the text boxes displaying the color value, copy that value to the Clipboard.

By default, the tool is always on top of all the application. This allows you to see the color under the mouse pointer as you move the pointer over the Desktop. You can disable this behavior by unchecking the "Always on top" menu option in the application's system menu.

Using the Code

The source files CButtonSK.h, CButtonSK.cpp, CUrl.h, and Curl.cpp are not directly relevant for this application. CButtonSK is used for skinning buttons and is used for the copy buttons (labeled with '>'). Curl is used in the About box to display URLs that behave identically to the URLs inside a browser.

The class associated with the main dialog is CColorFinderDlg and it is defined and implemented in the ColorFinderDlg.h and ColorFinderDlg.cpp files.

In the constructor for this class, the icon and cursor for the dropper are loaded and the m_bTracking variable is set to false. The current color m_colCurrent is set to black.

CColorFinderDlg::CColorFinderDlg(CWnd* pParent /*=NULL*/)
: CDialog(CColorFinderDlg::IDD, pParent)
{
    ...
    m_bTracking    = false;
    m_hCursor      = AfxGetApp()->LoadCursor(IDC_DROPPER);
    m_hDropperIcon = AfxGetApp()->LoadIcon(IDI_DROPPER);
    m_colCurrent   = RGB(0,0,0);
}

To get the color, three Windows messages—WM_MOUSEMOVE, WM_LBUTTONDOWN, and WM_LBUTTONUP—have been used.

When the message handler for WM_LBUTTONDOWN is called, the handler verifies that the location of the mouse button down is inside the rectangle for the static control that displays the dropper icon. It then sets the mouse tracking flag m_bTracking and captures the mouse so that all subsequent mouse move messages are sent to the window for CColorFinderDlg. The handler also changes the mouse cursor to that of the dropper and hides the dropper icon on the dialog. This gives an impression that the dropper is picked up from the dialog's window.

void CColorFinderDlg::OnLButtonDown(UINT nFlags, CPoint point)
{
    CRect rect;
    m_statDropper.GetWindowRect(&rect);
    ClientToScreen(&point);
    if (PtInRect(&rect, point))
    {
        SetCapture();
        m_bTracking = true;
        ::SetCursor(m_hCursor);
        m_statDropper.SetIcon(NULL);
    }
    ...
}

The handler for the WM_MOUSEMOVE first verifies that the mouse is being tracked, i.e., the mouse left button is currently down. It does that by using the m_bTracking variable set in OnLButtonDown. The current mouse pointer location is obtained using the Win32 API GetCursorPos. To get the color under the mouse pointer, first a handle to the Desktop device context is obtained using the API GetDCEx . This handle is then converted to a CDC class pointer by using CDC::FromHandle. Then, the color is retrieved by using the CDC method GetPixel.

void CColorFinderDlg::OnMouseMove(UINT nFlags, CPoint point)
{
    if (m_bTracking)
        UpdateColor();

    CDialog::OnMouseMove(nFlags, point);
}

void CColorFinderDlg::UpdateColor()
{
    ...
    //  Get the mouse pointer position and display it
    GetCursorPos(&pt);
    str.Format ("%d, %d", pt.x, pt.y);
    m_editCurPos.SetWindowText((LPCTSTR)str);

    //  Get the device context of the desktop and from it get the
    //  color of the pixel at the current mouse pointer position
    CDC *pDesktopDC = CDC::FromHandle ( ::GetDCEx(NULL, NULL, 0));
    m_colCurrent = pDesktopDC->GetPixel(pt);

    //  Break the color into the RGB components
    BYTE rVal = GetRValue(m_colCurrent);
    BYTE gVal = GetGValue(m_colCurrent);
    BYTE bVal = GetBValue(m_colCurrent);

    //  Display the pixel color in different formats
    str.Format("%02X, %02X, %02X", rVal, gVal, bVal);
    m_editColHex.SetWindowText((LPCTSTR)str);

    str.Format("%d, %d, %d", rVal, gVal, bVal);
    m_editColDec.SetWindowText((LPCTSTR)str);

    str.Format("#%02X%02X%02X", rVal, gVal, bVal);
    m_editColHTML.SetWindowText((LPCTSTR)str);

    //  Show the color in the static control
    CDC *pSDC = m_statCol.GetDC();
    CRect sRect;
    m_statCol.GetClientRect(&sRect);
    pSDC->FillSolidRect(&sRect, m_colCurrent);

    ...
}

In the handler for the WM_LBUTTONUP, the mouse capture is released and the m_bTracking flag is cleared. The dropper icon on the dialog is also restored.

void CColorFinderDlg::OnLButtonUp(UINT nFlags, CPoint point)
{
    if (m_bTracking)
    {
        ReleaseCapture();
        m_bTracking = false;
        m_statDropper.SetIcon(m_hDropperIcon);
    }
    ...
}

Points of Interest

The color displayed in the m_statCol is not updated with the WM_PAINT message.

The tool gives the actual RGB value of the pixel on the Desktop. If the color depth on your Desktop is less than 24-bit, all 24-bit colors will be displayed after approximating to the nearest supported color. ColorFinder will display the approximated color and NOT the actual color.

Downloads

Download demo executable - 51 Kb
Download source - 63 Kb


About the Author

Abhinaba Basu

Abhinaba loves coding for the sheer fun of it. He started programming in 1995 with BASIC and then moved through Cobol, Pascal, Prolog, C, C++, VisualBasic and VC++. He received a Bachelor of Technology degree from University of Calcutta in 2001. Abhinaba is originally from the City of Joy, Kolkata in India, but now codes and lives in Noida close to Delhi. His hobby is coding which also happens to be his job. Besides coding he loves traveling.

Comments

  • WM_CAPTURECHANGED

    Posted by Legacy on 12/09/2003 12:00am

    Originally posted by: Kiran

    Hi,

    This is a nice and useful tool. Good job.

    I noticed one problem though. Windows posts the mouse events to the window which has captured the mouse. Windows will stop posting mouse events to the captured window only as long as that thread is the active thread. If the active thread changes for some reason, windows will no longer send mouse events to this window. This could happen because of user switching to another application by activating it.

    So, if you drag the dropper tool to some application and then Alt-Tab to another app, you will see the problem.

    You should be handling WM_CAPTURECHANGED also, in that case, right ?

    Reply
Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • IBM Worklight is a mobile application development platform that lets you extend your business to mobile devices. It is designed to provide an open, comprehensive platform to build, run and manage HTML5, hybrid and native mobile apps.

  • New IT trends to support worker mobility — such as VDI and BYOD — are quickly gaining interest and adoption. But just as with any new trend, there are concerns and pitfalls to avoid.  Download this paper to learn the most important considerations to keep in mind for your VDI project.

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds