Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Color Take

0.00/5 (No votes)
9 Dec 2005 1  
An article on getting the colors of pixels from the desktop.

Sample Image

Introduction

This program gets the color of pixels from the desktop, displays them in a window, and has a 4 - 1 magnifier. They can be later copied to the clipboard.

Background

This version is user friendly. The selected colors fill the five boxes. The associated button copies its color to the copy window in the format selected by the Select Format option. The buttons are initially disabled else the background color of the dialog window would be copied. Press Copy to sent this value to the clipboard.

I know, you will think this has been done before, even on this web site, but this is why I present this article: I subscribe to Lockergnome - a Windows Fanatics newsletter. Last week, they had a program for download, TakeColor. I wanted to see if I could pseudo reverse engineer it. Turned out to be somewhat challenging: TakeColor - flaxie.com.

Using the code

The elements:

  1. A menu.
  2. A window to display the color of the pixel.
  3. A zoom window (4 - 1 magnifier).
  4. Display HEX, HTML, or RGB.
  5. Mouse coordinates.
  6. List of selected colors.
  7. Five boxes to show the last five selected colors.
  8. Copy to clipboard.

Explanation

  1. The Menu, no biggy, used the resource editor. The first challenge was that the ON_UPDATE_COMMAND_UI does not work for non-system menus. This function toggles menu items. we can call it with ToggleMenuItem(0, 1). I hand coded the menu items and sub items, this call sets a check mark on the Options menu, Stay on Top.
    void CColorTakeDlg::ToggleMenuItem(int nMenu, int nPos)
    {
        // Onupdate command UI doesn't work in a non-system menu
    
        CMenu *pMenu = GetMenu();
        CMenu *pSubMenu = pMenu->GetSubMenu(nMenu);
        UINT nID = pSubMenu->GetMenuItemID(nPos);
        UINT nState = pSubMenu->GetMenuState(nID, MF_BYCOMMAND);
        ASSERT(nState != 0xFFFFFFFF);
    
        if(nState & MF_CHECKED)
            pSubMenu->CheckMenuItem(nID, MF_UNCHECKED | MF_BYCOMMAND);
        else
            pSubMenu->CheckMenuItem(nID, MF_CHECKED | MF_BYCOMMAND);
    }
  2. Display current color.
        CDC *pSDC = m_current.GetDC();
        CRect sRect;
        m_current.GetClientRect(&sRect);
        pSDC->FillSolidRect(&sRect, m_colCurrent);
        ReleaseDC(pSDC);
  3. Zoom window.
        if (bEnableZoom)
        {
            CDC *pDC = m_zoom.GetDC();
            CRect m_rect;
            m_zoom.GetClientRect(&m_rect);
            InflateRect(&m_rect, -1, 0);
            pDC->SetStretchBltMode(COLORONCOLOR);
            // stretch the 20 x 20 to the 81 x 81 window,
    
            // close to 4 to 1 magnifier
    
            pDC->StretchBlt(m_rect.left, m_rect.top, 
                    m_rect.Width(), m_rect.Height(), pDesktopDC,
                    pt.x - m_nOffset, pt.y - m_nOffset, 
                    m_nWidth, m_nWidth, SRCCOPY);
    
            pen.DeleteObject();
            pen.CreatePen(PS_SOLID, 1, RGB(255, 0, 0));
            CPen *pOldPen = pDC->SelectObject(&pen);
            CPoint point;
            // draw a red line at the mid point of the x and y axis
    
            point.x = m_rect.Width()/2;
            point.y = m_rect.top;
            pDC->MoveTo(point);
            point.y = m_rect.bottom;
            pDC->LineTo(point);
            point.x = m_rect.left;
            point.y = m_rect.Height()/2;
            pDC->MoveTo(point);
            point.x = m_rect.right;
            pDC->LineTo(point);
            pDC->SelectObject(pOldPen);
            ReleaseDC(pDC);
        }
  4. Display HEX, HTML, or RGB.
        switch (m_nSelect)
        {
            case 0:
                str.Format("%02X, %02X, %02X", rVal, gVal, bVal);    // Hex
    
                m_color.SetWindowText((LPCTSTR)str);
                break;
    
            case 1:
                str.Format("#%02X%02X%02X", rVal, gVal, bVal);        // HTML
    
                m_color.SetWindowText((LPCTSTR)str);
                break;
    
            case 2:
                str.Format("%d, %d, %d", rVal, gVal, bVal);            // RGB
    
                m_color.SetWindowText((LPCTSTR)str);
                break;
        }
  5. Mouse coordinates: this was quite a challenge, I used SetCapture() to get the cursor from the desktop. In the previous version, that was an error.
    void CColorTakeDlg::OnTimer(UINT nIDEvent) 
    {
        // TODO: Add your message handler code here and/or call default
    
    
        HWND m_hwnd = ::GetDesktopWindow();
        CString str;
        POINT pt;
        pt.x = pt.y = 0;
    
        //  =======================================================================
    
        //  Get the mouse pointer position and display it
    
        //  =======================================================================
    
        GetCursorPos(&pt);
        str.Format("X: %d, Y: %d", pt.x, pt.y);
        m_mouse.SetWindowText((LPCTSTR)str);
        ...
        ...
  6. List of selected colors.
        CString str;
        m_color.GetWindowText(str);
        m_list1.InsertString(0, str);
        UpdateData(FALSE);
  7. Five boxes to show the last five selected colors.
    // Store the current selected color in the left most
    
    // of 5 boxes, shifting old ones right.
    
    void CColorTakeDlg::CopyColor()
    {
        m_nColor[4] = m_nColor[3];
        m_nColor[3] = m_nColor[2];
        m_nColor[2] = m_nColor[1];
        m_nColor[1] = m_nColor[0];
        m_nColor[0] = m_colCurrent;
    
        DrawColorBoxes();
    }
  8. Copy to clipboard.
    void CColorTakeDlg::OnCopy() 
    {
        // TODO: Add your control notification handler code here
    
        m_edit1.SetSel(0, -1);
        // Copy selected color to the clipboard
    
        m_edit1.Copy();
    }

Points of Interest

This program uses the CHotKeyCtrl class to copy the selected color to the list and the first box. The function void GetHotKey( WORD &wVirtualKeyCode, WORD &wModifiers ) const; is used to get the hot key from the control. wVirtualKeyCode is the keyboard key (A - Z) pressed and wModifiers are the control keys (Shift, Ctrl, Alt, and the Windows key). The modifier flags defined in CommCtrl.h can be a combination of the following values:

#define HOTKEYF_SHIFT           0x01
#define HOTKEYF_CONTROL         0x02
#define HOTKEYF_ALT             0x04
#define HOTKEYF_EXT             0x08

Then the hot key has to be registered using:

BOOL RegisterHotKey(
  HWND hWnd,         // handle to window

  int id,            // hot key identifier

  UINT fsModifiers,  // key-modifier options

  UINT vk            // virtual-key code

);

The values for fsModifiers are defined in WinUser.h.

#define MOD_ALT         0x0001
#define MOD_CONTROL     0x0002
#define MOD_SHIFT       0x0004
#define MOD_WIN         0x0008

As you can see, the values are not the same, so I have:

void CColorTakeDlg::OnNewHotkey() 
{
    // TODO: Add your control notification handler code here

    UnregisterHotKey(m_hWnd, HOTKEYID);
    m_hotkey1.GetHotKey(wVirtualKeyCode, wModifiers);
    switch(wModifiers)
    {
    case HOTKEYF_SHIFT:
        fsModifiers = MOD_SHIFT;
        break;
    case HOTKEYF_CONTROL:
        fsModifiers = MOD_CONTROL;
        break;
    case HOTKEYF_ALT:
        fsModifiers = MOD_ALT;
        break;
    case HOTKEYF_EXT:
        fsModifiers = MOD_WIN;
        break;
    }
    RegisterHotKey(m_hWnd, HOTKEYID, fsModifiers, wVirtualKeyCode);
}

These are only four combinations, I didn't want to allow all 16, so I used SetRules().

    m_hotkey1.SetHotKey(0x43, HOTKEYF_ALT);
    m_hotkey1.SetRules(HKCOMB_CA | HKCOMB_SA | HKCOMB_SC | 
                       HKCOMB_SCA | HKCOMB_NONE, HOTKEYF_ALT);
    RegisterHotKey(m_hWnd, HOTKEYID, MOD_ALT, 0x43);
    wVirtualKeyCode = 0x43;
    wModifiers = HOTKEYF_ALT;
    fsModifiers = MOD_ALT;

You want it zany, then position the cursor in the magnifier window. When you get close to the cross-hairs which are 1 pixel wide, you will see in the window they are 4 pixels wide. If you get closer, then 16 pixels wide. About the time they get 64 pixels wide, the window will turn red.

Warning

If you use this program on older versions of Windows, Win95/Win98, and the zoom window fails to function, then you have a problem. The GDI resource causes StretchBlt(...) to return FALSE: see the MSDN Knowledge base article.

History

  • 19 March 2005 - Version 1.0.
  • 25 March 2005 - Version 1.1 - New thread method.
  • 31 March 2005 - Version 1.2 - Fixed error, added marker for Selected.
  • 22 November 2005 - Version 1.3 - New method for zoom.
  • 04 December 2005 - Version 1.4 - The final version, user friendly.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here