Click here to Skip to main content
15,891,513 members
Articles / Desktop Programming / MFC
Article

Icon Colors

Rate me:
Please Sign up or sign in to vote.
2.45/5 (12 votes)
12 Apr 20051 min read 44.1K   604   13   1
An article on what you can do with color.

Sample Image

Introduction

While browsing the MSDN Library DVD (Oct. 2001), I found the above image in "Creating Windows XP Icons", and wrote this demonstration to show what can be done with colors.

Background

First, I would like to apologize to people with low resolution screens, the dialog is 800 pixels wide. I wanted to display the colors as a rainbow; sorting by their RGB value doesn't do the trick, so I used HLS instead. The dialog allows either sort.

Using the code

The library shows a function:

VOID ColorRGBToHLS(
    COLORREF clrRGB,
    WORD *pwHue,
    WORD *pwLuminance,
    WORD *pwSaturation
);

defined in Shlwapi.h but I couldn't find it where they said it was. I did find it in MSDN Online Help on article ID: 29240, to convert RGB to HLS.

#define  HLSMAX   RANGE /* H,L, and S vary over 0-HLSMAX */
#define  RGBMAX   255   /* R,G, and B vary over 0-RGBMAX */
                         /* HLSMAX BEST IF DIVISIBLE BY 6 */
                         /* RGBMAX, HLSMAX must each fit in a byte. */

 /* Hue is undefined if Saturation is 0 (grey-scale) */
 /* This value determines where the Hue scrollbar is */
 /* initially set for achromatic colors */
 #define UNDEFINED (HLSMAX*2/3)

 void  RGBtoHLS(lRGBColor)

 DWORD lRGBColor;
 {
    WORD R,G,B;          /* input RGB values */
    BYTE cMax,cMin;      /* max and min RGB values */
 WORD  Rdelta,Gdelta,Bdelta; /* intermediate value: % of spread from max

 */
    /* get R, G, and B out of DWORD */
    R = GetRValue(lRGBColor);
    G = GetGValue(lRGBColor);
    B = GetBValue(lRGBColor);

    /* calculate lightness */
    cMax = max( max(R,G), B);
    cMin = min( min(R,G), B);
    L = ( ((cMax+cMin)*HLSMAX) + RGBMAX )/(2*RGBMAX);

    if (cMax == cMin) {           /* r=g=b --> achromatic case */
       S = 0;                     /* saturation */
       H = UNDEFINED;             /* hue */
    }
    else {                        /* chromatic case */
       /* saturation */
       if (L <= (HLSMAX/2))
          S = ( ((cMax-cMin)*HLSMAX) + ((cMax+cMin)/2) ) / (cMax+cMin);
       else
          S = ( ((cMax-cMin)*HLSMAX) + ((2*RGBMAX-cMax-cMin)/2) )
             / (2*RGBMAX-cMax-cMin);

       /* hue */
    Rdelta = ( ((cMax-R)*(HLSMAX/6)) + ((cMax-cMin)/2) ) / (cMax-cMin);
    Gdelta = ( ((cMax-G)*(HLSMAX/6)) + ((cMax-cMin)/2) ) / (cMax-cMin);
    Bdelta = ( ((cMax-B)*(HLSMAX/6)) + ((cMax-cMin)/2) ) / (cMax-cMin);

       if (R == cMax)
          H = Bdelta - Gdelta;
       else if (G == cMax)
          H = (HLSMAX/3) + Rdelta - Bdelta;
       else /* B == cMax */
          H = ((2*HLSMAX)/3) + Gdelta - Rdelta;

       if (H < 0)
          H += HLSMAX;
       if (H > HLSMAX)
          H -= HLSMAX;
    }
 }

As you can see, this code is the old UNIX C (1978) vintage, but it is easy to bring it up to date. See IconColorsDlg.cpp for details.

Here is the sort routine code:

void CIconColorsDlg::SortColors()
{
    COLORREF clTemp;
    DWORD dwColor1, dwColor2;
    for (int j = 0; j < 32; j++)
    {
        for (int i = 0; i < 31; i++)
        {
            if (!bRGB)
            {
                RGBtoHLS(m_nColor[i + 1]);
                dwColor1 = wHue;
                dwColor1 = dwColor1 << 8;
                dwColor1 += wLum;
                dwColor1 = dwColor1 << 8;
                dwColor1 += wSat;
                dwColor1 = dwColor1 & 0x00FFFFFF;
                
                RGBtoHLS(m_nColor[i]);
                dwColor2 = wHue;
                dwColor2 = dwColor2 << 8;
                dwColor2 += wLum;
                dwColor2 = dwColor2 << 8;
                dwColor2 += wSat;
                dwColor2 = dwColor2 & 0x00FFFFFF;
            
                if (dwColor1 < dwColor2)
                {
                    clTemp = m_nColor[i];
                    m_nColor[i] = m_nColor[i + 1];
                    m_nColor[i + 1] = clTemp;
                }
            }
            else if (m_nColor[i + 1] < m_nColor[i])
            {
                clTemp = m_nColor[i];
                m_nColor[i] = m_nColor[i + 1];
                m_nColor[i + 1] = clTemp;
            }
        }
    }
}

Then to see the details of each color, I use a left-shift-end-around function:

void CIconColorsDlg::OnTimer(UINT nIDEvent) 
{
    // TODO: Add your message handler code here and/or call default
    COLORREF clTemp;
    clTemp = m_nColor[0];
    for(int i = 1; i < 32; i++)
    {
        m_nColor[i-1] = m_nColor[i];
    }
    m_nColor[31] = clTemp;

    DrawColors();

    CDialog::OnTimer(nIDEvent);
}

Points of Interest

The RGB macro uses COLORREF variable to save the value in. It is saved as 0x00bbggrr where bb is the blue byte, gg is the green byte, and rr is the red byte. Sorting this does group the colors, but not how I wanted. The pink color RGB(255, 204, 255) you will notice is out of place because as the variables in RGBtoHLS() is seen, wHue = 65520 (-16), Bdelta = 0, and Gdelta = 16. Maybe I'll fix this sometime.

History

April 11, 2005 - Version 1.0.

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

 
GeneralThanks mate Pin
Kharfax31-Aug-06 5:44
Kharfax31-Aug-06 5:44 

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.