Click here to Skip to main content
15,880,651 members
Articles / Desktop Programming / MFC
Article

Color Take

Rate me:
Please Sign up or sign in to vote.
4.89/5 (21 votes)
9 Dec 20053 min read 86.8K   1.6K   42   17
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


Written By
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
GeneralCosmetic change Pin
Roger6515-Dec-05 2:16
Roger6515-Dec-05 2:16 
Generalcolour preview boxes Pin
Ashley van Gerven11-Dec-05 23:47
Ashley van Gerven11-Dec-05 23:47 
GeneralRe: colour preview boxes Pin
Roger6512-Dec-05 0:21
Roger6512-Dec-05 0:21 
GeneralRe: colour preview boxes Pin
Ashley van Gerven12-Dec-05 0:26
Ashley van Gerven12-Dec-05 0:26 
GeneralRe: colour preview boxes Pin
Roger6512-Dec-05 1:00
Roger6512-Dec-05 1:00 
GeneralRe: colour preview boxes Pin
Roger6512-Dec-05 4:36
Roger6512-Dec-05 4:36 
GeneralList Box Pin
brianma30-Nov-05 7:39
professionalbrianma30-Nov-05 7:39 
GeneralRe: List Box Pin
Roger6530-Nov-05 12:19
Roger6530-Nov-05 12:19 
GeneralSmall suggestions Pin
Hans Dietrich25-Nov-05 10:08
mentorHans Dietrich25-Nov-05 10:08 
GeneralRe: Small suggestions Pin
Roger6525-Nov-05 23:20
Roger6525-Nov-05 23:20 
GeneralRe: Small suggestions Pin
Hans Dietrich26-Nov-05 10:23
mentorHans Dietrich26-Nov-05 10:23 
GeneralRe: Small suggestions Pin
Roger6526-Nov-05 23:23
Roger6526-Nov-05 23:23 
GeneralPerformance Trivia (data) Pin
Roger652-Apr-05 4:12
Roger652-Apr-05 4:12 
GeneralVery nice !! Pin
WREY30-Mar-05 1:57
WREY30-Mar-05 1:57 
GeneralRe: Very nice !! Pin
Roger651-Apr-05 4:55
Roger651-Apr-05 4:55 
GeneralZoomPlus Pin
Member 155321429-Mar-05 12:00
Member 155321429-Mar-05 12:00 
GeneralRe: ZoomPlus Pin
Anonymous29-Mar-05 15:47
Anonymous29-Mar-05 15:47 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.