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 */
#define UNDEFINED (HLSMAX*2/3)
void RGBtoHLS(lRGBColor)
DWORD lRGBColor;
{
WORD R,G,B;
BYTE cMax,cMin;
WORD Rdelta,Gdelta,Bdelta;
R = GetRValue(lRGBColor);
G = GetGValue(lRGBColor);
B = GetBValue(lRGBColor);
cMax = max( max(R,G), B);
cMin = min( min(R,G), B);
L = ( ((cMax+cMin)*HLSMAX) + RGBMAX )/(2*RGBMAX);
if (cMax == cMin) {
S = 0;
H = UNDEFINED;
}
else {
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);
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
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)
{
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.
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.