//////////////////////////////////////////////////////////////////////
// ColorSpy Copyright 2003 Tom Furuya
//
// Readers of this article may copy the code for use in developing their own applications.
// If the code is used in a commercial application, however, an acknolegement must
// be included in the following form:
// "Segment of the code (c) 2003 Tom Furuya for CodeProject.com".
//////////////////////////////////////////////////////////////////////
// ColorHelper.h: interface for the CColorHelper class.
//
// RGB to HSB conversion code
//
// Copyright restrictions
// ======================
//
// The Gri programming languages, and all manuals and online help-files,
// are (c) 1991-2002 Dan E. Kelley <Dan.Kelley@Dal.CA>.
//
#if !defined(AFX_COLORHELPER_H__FC0D0C25_B591_494D_9C6A_2E3D92E2C903__INCLUDED_)
#define AFX_COLORHELPER_H__FC0D0C25_B591_494D_9C6A_2E3D92E2C903__INCLUDED_
#pragma once
#include "Duo.h"
//
// Color name-to-RGB value mapping
//
// rgbtab.h - Color table from Xpm library of XFree86.
// Original: [ftp://ftp.xfree86.org/pub/XFree86/4.3.0/source/X430src-1.tgz]
//
#include "rgbtab.h" // Modified. You can replace the table as you wish.
// Color Helper class
class CColorHelper
{
public:
static bool s_bStaticInit;
static int s_nMaxPatternLen;
typedef enum {
CF_WEB,
CF_DEC,
CF_HSB,
} ColorFormat;
CColorHelper()
{
_Init();
}
CString ToString(ColorFormat fmt, COLORREF clr)
{
static LPCTSTR FMT_WEB = TEXT("%02X%02X%02X");
static LPCTSTR FMT_DEC = TEXT("R:%d G:%d B:%d");
CString str;
switch (fmt)
{
default:
case CF_WEB:
str.Format(FMT_WEB, GetRValue(clr), GetGValue(clr), GetBValue(clr));
break;
case CF_DEC:
str.Format(FMT_DEC, GetRValue(clr), GetGValue(clr), GetBValue(clr));
break;
case CF_HSB:
str = ToHSB(clr);
break;
}
return str;
}
CString ToString(COLORREF clr)
{
return ToString(CF_WEB, clr);
}
DuoT<bool, COLORREF> GetColor(const CString& s)
{
ATLASSERT(s.GetLength() == 6);
const DuoT<bool, COLORREF> InvalidColor = make_duo(false, 0);
if (s.GetLength() != 6) return InvalidColor;
if (!IsHex(s[0]) || !IsHex(s[1]) || !IsHex(s[2]) ||
!IsHex(s[3]) || !IsHex(s[4]) || !IsHex(s[5]))
return InvalidColor;
CString strR = s.Mid(0, 2);
CString strG = s.Mid(2, 2);
CString strB = s.Mid(4, 2);
TCHAR *stopstring;
unsigned long ul;
BYTE r, g, b;
ul = _tcstoul( (LPCTSTR)strR, &stopstring, 16);
if (*stopstring != 0) return InvalidColor;
r = LOBYTE(LOWORD(ul));
ul = _tcstoul( (LPCTSTR)strG, &stopstring, 16);
if (*stopstring != 0) return InvalidColor;
g = LOBYTE(LOWORD(ul));
if (*stopstring != 0) return InvalidColor;
ul = _tcstoul( (LPCTSTR)strB, &stopstring, 16);
b = LOBYTE(LOWORD(ul));
return make_duo(true, RGB(r, g, b));
}
CString GetColorName(COLORREF clr)
{
rgbRecord* pos = theRGBRecords;
while (pos->name)
{
if (clr == pos->rgb)
return pos->name;
pos++;
}
return _T("");
}
DuoT<bool, COLORREF> GetColorByName(CString name)
{
const DuoT<bool, COLORREF> InvalidColor = make_duo(false, 0);
const int nLen = name.GetLength();
if (nLen >= s_nMaxPatternLen) return InvalidColor;
name.MakeLower();
// theRecords: Color name-to-RGB value mapping table. See rgbtable.h for details
const int nRecords = NELEM(theRGBRecords);
for (int i = 0; i < nRecords; i++)
{
if (nLen != thePatternLen[i] || name[0] != *theRGBRecords[i].name)
continue;
if (name == theRGBRecords[i].name)
return make_duo(true, theRGBRecords[i].rgb);
}
return InvalidColor;
}
static void _Init()
{
if (s_bStaticInit) return;
// performance improvement
for (int i = 0; i < NELEM(theRGBRecords); i++)
{
thePatternLen[i] = lstrlen(theRGBRecords[i].name);
if (thePatternLen[i] >= s_nMaxPatternLen)
s_nMaxPatternLen = thePatternLen[i];
}
// done
s_bStaticInit = true;
}
inline bool IsHex(TCHAR ch)
{
return (ch == _T('0') || ch == _T('1') || ch == _T('2') ||
ch == _T('3') || ch == _T('4') || ch == _T('5') ||
ch == _T('6') || ch == _T('7') || ch == _T('8') ||
ch == _T('9') || ch == _T('A') || ch == _T('B') ||
ch == _T('C') || ch == _T('D') || ch == _T('E') ||
ch == _T('F') || ch == _T('a') || ch == _T('b') ||
ch == _T('c') || ch == _T('d') || ch == _T('e') ||
ch == _T('f'));
}
CString ToHSB(COLORREF clr)
{
static LPCTSTR FMT_HSB = TEXT("H:%d S:%d B:%d");
CString str;
int i = GetRValue(clr);
int i1 = GetGValue(clr);
int i2 = GetBValue(clr);
double h, s, br;
rgb2hsb(i / 255.f, i1 / 255.f, i2 / 255.f, &h, &s, &br);
// Make Hue value close to what P*******p tell us.
CComVariant varIn = h, varResult;
VarRound(&varIn, 0, &varResult);
str.Format(FMT_HSB, int(varResult.dblVal), int(s * 100), int(br * 100));
return str;
}
/*
* (red, green, blue) in range from 0 to 1 is translated to (hue, saturation,
* brightness) in same range.
*
* NOTE: false checking on range of (r,g,b) is done, and strange results may result
* outside this range.
*
* Algorithm: Foley + Van Dam
*/
void
rgb2hsb(double r, double g, double b, double *h, double *s, double *br)
{
double mx, mn;
mx = r;
if (g > mx)
mx = g;
if (b > mx)
mx = b;
mn = r;
if (g < mn)
mn = g;
if (b < mn)
mn = b;
*br = mx;
if (mx)
*s = (mx - mn) / mx;
else
*s = 0.0;
if (*s == 0.0)
{
*h = 0.0; /* doesn't matter, since black anyway */
}
else
{
*h = GetHue(r,g,b);
#if NEVER
double rc, gc, bc;
rc = (mx - r) / (mx - mn);
gc = (mx - g) / (mx - mn);
bc = (mx - b) / (mx - mn);
if (r == mx)
*h = bc - gc;
else if (g == mx)
*h = 2.f + rc - bc;
else if (b == mx)
*h = 4.f + gc - rc;
*h /= 6.f;
if (*h < 0.f)
*h = *h + 1.f;
#endif
}
}
double GetHue(double r, double g, double b)
{
double f = r;
double f1 = g;
double f2 = b;
double f6 = 0.0f;
double f3 = f;
double f4 = f;
if (f1 > f3)
f3 = f1;
if (f2 > f3)
f3 = f2;
if (f1 < f4)
f4 = f1;
if (f2 < f4)
f4 = f2;
double f5 = f3 - f4;
if (f == f3)
{
f6 = (f1 - f2) / f5;
}
else
{
if (f1 == f3)
f6 = 2.f + (f2 - f) / f5;
else if (f2 == f3)
f6 = 4.f + (f - f1) / f5;
}
f6 *= 60.f;
if (f6 < 0.f)
f6 += 360.f;
return f6;
}
};
__declspec(selectany) int CColorHelper::s_nMaxPatternLen = 0;
__declspec(selectany) bool CColorHelper::s_bStaticInit = false;
#endif // !defined(AFX_COLORHELPER_H__FC0D0C25_B591_494D_9C6A_2E3D92E2C903__INCLUDED_)