Added functions for direct conversion between HSL and HSV. (hsl_to_hsv is still incomplete, and works over rgb atm)

Added some special cases to the HSV and HSl to RGB conversions, as a "fix" for bug #28.
Random hacking on text_extents in a vain attempt at making its calculations more exact.

Originally committed to SVN as r232.
This commit is contained in:
Niels Martin Hansen 2006-03-17 01:59:41 +00:00
parent 180f323676
commit e6c2f3c083
4 changed files with 221 additions and 34 deletions

View File

@ -302,7 +302,9 @@ namespace AutomationHelper {
if (!thedc) return 0; if (!thedc) return 0;
SetMapMode(thedc, MM_TEXT); SetMapMode(thedc, MM_TEXT);
fontsize = -MulDiv((int)(fontsize+0.5), GetDeviceCaps(thedc, LOGPIXELSY), 72); HDC dczero = GetDC(0);
fontsize = -MulDiv((int)(fontsize+0.5), GetDeviceCaps(dczero, LOGPIXELSY), 72);
ReleaseDC(0, dczero);
LOGFONT lf; LOGFONT lf;
ZeroMemory(&lf, sizeof(lf)); ZeroMemory(&lf, sizeof(lf));
@ -323,16 +325,17 @@ namespace AutomationHelper {
SelectObject(thedc, thefont); SelectObject(thedc, thefont);
SIZE sz; SIZE sz;
size_t thetextlen = intext.length();
const wchar_t *thetext = intext.wc_str();
if (spacing) { if (spacing) {
resx = 0; resx = 0;
for (unsigned int i = 0; i < intext.length(); i++) { for (unsigned int i = 0; i < thetextlen; i++) {
wchar_t c = intext[i]; GetTextExtentPoint32(thedc, &thetext[i], 1, &sz);
GetTextExtentPoint32(thedc, &c, 1, &sz);
resx += sz.cx + spacing; resx += sz.cx + spacing;
resy = sz.cy; resy = sz.cy;
} }
} else { } else {
GetTextExtentPoint32(thedc, intext.wc_str(), intext.Length(), &sz); GetTextExtentPoint32(thedc, thetext, thetextlen, &sz);
resx = sz.cx; resx = sz.cx;
resy = sz.cy; resy = sz.cy;
} }

View File

@ -59,56 +59,151 @@ void hsl_to_rgb(int H, int S, int L, unsigned char *R, unsigned char *G, unsigne
return; return;
} }
if (L == 128 && S == 255) {
switch (H) {
case 0:
case 255: // actually this is wrong, since this is more like 359 degrees... but it's what you'd expect (sadly :)
*R = 255;
*G = 0;
*B = 0;
return;
case 43:
*R = 255;
*G = 255;
*B = 0;
return;
case 85:
*R = 0;
*G = 255;
*B = 0;
return;
case 128:
*R = 0;
*G = 255;
*B = 255;
return;
case 171:
*R = 0;
*G = 0;
*B = 255;
return;
case 213:
*R = 255;
*G = 0;
*B = 255;
return;
}
}
/*const int scale = 64;
int r, g, b; int r, g, b;
H *= scale;
S *= scale;
L *= scale;
int temp2; int temp2;
if (L < 128) { if (L < 128*scale) {
temp2 = L * (256 + S) / 256; temp2 = L * (256*scale + S) / (256*scale);
} else { } else {
temp2 = L + S - L * S / 256; temp2 = L + S - L * S / (256*scale);
} }
int temp1 = 2*L - temp2; int temp1 = 2*L - temp2;
int temp3[3]; int temp3[3];
temp3[0] = H + 256/3; temp3[0] = H + (256*scale)/3;
if (temp3[0] < 0) temp3[0] += 256; if (temp3[0] < 0) temp3[0] += (256*scale);
if (temp3[0] > 256) temp3[0] -= 256; if (temp3[0] > (256*scale)) temp3[0] -= (256*scale);
temp3[1] = H; temp3[1] = H;
temp3[2] = H - 256/3; temp3[2] = H - (256*scale)/3;
if (temp3[2] < 0) temp3[2] += 256; if (temp3[2] < 0) temp3[2] += (256*scale);
if (temp3[2] > 256) temp3[2] -= 256; if (temp3[2] > (256*scale)) temp3[2] -= (256*scale);
if (6 * temp3[0] < 255) if (6 * temp3[0] < (256*scale))
r = temp1 + (temp2 - temp1) * 6 * temp3[0] / 256; r = temp1 + (temp2 - temp1) * 6 * temp3[0] / (256*scale);
else if (2 * temp3[0] < 255) else if (2 * temp3[0] < (256*scale))
r = temp2; r = temp2;
else if (3 * temp3[0] < 511) else if (3 * temp3[0] < (2*256*scale))
r = temp1 + (temp2 - temp1) * ((512/3) - temp3[0]) * 6 / 256; r = temp1 + (temp2 - temp1) * ((512*scale/3) - temp3[0]) * 6 / (256*scale);
else else
r = temp1; r = temp1;
if (6 * temp3[1] < 255) if (6 * temp3[1] < (256*scale))
g = temp1 + (temp2 - temp1) * 6 * temp3[1] / 256; g = temp1 + (temp2 - temp1) * 6 * temp3[1] / (256*scale);
else if (2 * temp3[1] < 255) else if (2 * temp3[1] < (256*scale))
g = temp2; g = temp2;
else if (3 * temp3[1] < 511) else if (3 * temp3[1] < (2*256*scale))
g = temp1 + (temp2 - temp1) * ((512/3) - temp3[1]) * 6 / 256; g = temp1 + (temp2 - temp1) * ((512*scale/3) - temp3[1]) * 6 / (256*scale);
else else
g = temp1; g = temp1;
if (6 * temp3[2] < 255) if (6 * temp3[2] < (256*scale))
b = temp1 + (temp2 - temp1) * 6 * temp3[2] / 256; b = temp1 + (temp2 - temp1) * 6 * temp3[2] / (256*scale);
else if (2 * temp3[2] < 255) else if (2 * temp3[2] < (256*scale))
b = temp2; b = temp2;
else if (3 * temp3[2] < 511) else if (3 * temp3[2] < (2*256*scale))
b = temp1 + (temp2 - temp1) * ((512/3) - temp3[2]) * 6 / 256; b = temp1 + (temp2 - temp1) * ((512*scale/3) - temp3[2]) * 6 / (256*scale);
else else
b = temp1; b = temp1;
*R = clip_colorval(r); *R = clip_colorval(r/scale);
*G = clip_colorval(g); *G = clip_colorval(g/scale);
*B = clip_colorval(b); *B = clip_colorval(b/scale);*/
float h, s, l, r, g, b;
h = H / 255.f;
s = S / 255.f;
l = L / 255.f;
float temp2;
if (l < .5) {
temp2 = l * (1. + s);
} else {
temp2 = l + s - l*s;
}
float temp1 = 2.f * l - temp2;
// assume h is in range [0;1]
float temp3[3];
temp3[0] = h + 1.f/3.f;
if (temp3[0] > 1.f) temp3[0] -= 1.f;
temp3[1] = h;
temp3[2] = h - 1.f/3.f;
if (temp3[2] < 0.f) temp3[2] += 1.f;
if (6.f * temp3[0] < 1.f)
r = temp1 + (temp2 - temp1) * 6.f * temp3[0];
else if (2.f * temp3[0] < 1.f)
r = temp2;
else if (3.f * temp3[0] < 2.f)
r = temp1 + (temp2 - temp1) * ((2.f/3.f) - temp3[0]) * 6.f;
else
r = temp1;
if (6.f * temp3[1] < 1.f)
g = temp1 + (temp2 - temp1) * 6.f * temp3[1];
else if (2.f * temp3[1] < 1.f)
g = temp2;
else if (3.f * temp3[1] < 2.f)
g = temp1 + (temp2 - temp1) * ((2.f/3.f) - temp3[1]) * 6.f;
else
g = temp1;
if (6.f * temp3[2] < 1.f)
b = temp1 + (temp2 - temp1) * 6.f * temp3[2];
else if (2.f * temp3[2] < 1.f)
b = temp2;
else if (3.f * temp3[2] < 2.f)
b = temp1 + (temp2 - temp1) * ((2.f/3.f) - temp3[2]) * 6.f;
else
b = temp1;
*R = clip_colorval((int)(r*255));
*G = clip_colorval((int)(g*255));
*B = clip_colorval((int)(b*255));
} }
@ -118,6 +213,43 @@ void hsv_to_rgb(int H, int S, int V, unsigned char *R, unsigned char *G, unsigne
{ {
*R = *G = *B = 0; *R = *G = *B = 0;
// some special cases... oh yeah baby!
if (S == 255) {
switch (H) {
case 0:
case 255: // actually this is wrong, since this is more like 359 degrees... but it's what you'd expect (sadly :)
*R = V;
*G = 0;
*B = 0;
return;
case 43:
*R = V;
*G = V;
*B = 0;
return;
case 85:
*R = 0;
*G = V;
*B = 0;
return;
case 128:
*R = 0;
*G = V;
*B = V;
return;
case 171:
*R = 0;
*G = 0;
*B = V;
return;
case 213:
*R = V;
*G = 0;
*B = V;
return;
}
}
// Cap values // Cap values
unsigned int h = H * 360; unsigned int h = H * 360;
unsigned int s = clip_colorval(S)*256; unsigned int s = clip_colorval(S)*256;
@ -318,6 +450,54 @@ void rgb_to_hsv(int R, int G, int B, unsigned char *H, unsigned char *S, unsigne
} }
void hsv_to_hsl(int iH, int iS, int iV, unsigned char *oH, unsigned char *oS, unsigned char *oL)
{
int p = iV * (255 - iS);
*oH = iH;
*oL = clip_colorval((p + iV*255)/255/2);
if (*oL == 0) {
*oS = iS; // oS is actually undefined, so any value should work ;)
} else if (*oL <= 128) {
*oS = clip_colorval((iV*255 - p) / (2 * *oL));
} else {
*oS = clip_colorval((iV*255 - p) / (511 - 2 * *oL));
}
}
void hsl_to_hsv(int iH, int iS, int iL, unsigned char *oH, unsigned char *oS, unsigned char *oV)
{
// temporary solution...
hsl_to_rgb(iH, iS, iL, oH, oS, oV);
rgb_to_hsv(*oH, *oS, *oV, oH, oS, oV);
// can this really be so hard? it seems way harder to deduce a formula for this than for the other direction
/* *oH = iH;
if (iS == 0) {
*oS = 0;
*oV = iL;
return;
}
int temp2;
if (iL < 128) {
temp2 = iL * (255 + iS);
} else {
temp2 = iL*255 + iS*255 - iL*iS;
}
int temp1 = 2 * iL*255 - temp2;
int temp3[3];
temp3[0] = iH + 255/3;
if (temp3[0] > 255) temp3[0] -= 255;
temp3[1] = iH;
temp3[2] = iH - 255/3;
if (temp3[2] < 0) temp3[2] += 255;*/
}
wxString color_to_html(wxColour color) wxString color_to_html(wxColour color)
{ {

View File

@ -67,6 +67,10 @@ void rgb_to_hsl(int R, int G, int B, unsigned char *H, unsigned char *S, unsigne
// Convert an RGB color to HSV; all values are expected to be in range 0..255 // Convert an RGB color to HSV; all values are expected to be in range 0..255
void rgb_to_hsv(int R, int G, int B, unsigned char *H, unsigned char *S, unsigned char *V); void rgb_to_hsv(int R, int G, int B, unsigned char *H, unsigned char *S, unsigned char *V);
void hsv_to_hsl(int iH, int iS, int iV, unsigned char *oH, unsigned char *oS, unsigned char *oL);
void hsl_to_hsv(int iH, int iS, int iL, unsigned char *oH, unsigned char *oS, unsigned char *oV);
// Convert a wxColour to a HTML hex string // Convert a wxColour to a HTML hex string
wxString color_to_html(wxColour color); wxString color_to_html(wxColour color);

View File

@ -689,7 +689,7 @@ void DialogColorPicker::UpdateFromHSL()
l = hsl_input[2]->GetValue(); l = hsl_input[2]->GetValue();
hsl_to_rgb(h, s, l, &r, &g, &b); hsl_to_rgb(h, s, l, &r, &g, &b);
//rgb_to_yuv(r, g, b, &y, &u, &v); //rgb_to_yuv(r, g, b, &y, &u, &v);
rgb_to_hsv(r, g, b, &h2, &s2, &v2); hsl_to_hsv(h, s, l, &h2, &s2, &v2);
rgb_input[0]->SetValue(r); rgb_input[0]->SetValue(r);
rgb_input[1]->SetValue(g); rgb_input[1]->SetValue(g);
rgb_input[2]->SetValue(b); rgb_input[2]->SetValue(b);
@ -720,7 +720,7 @@ void DialogColorPicker::UpdateFromHSV()
v2 = hsv_input[2]->GetValue(); v2 = hsv_input[2]->GetValue();
hsv_to_rgb(h2, s2, v2, &r, &g, &b); hsv_to_rgb(h2, s2, v2, &r, &g, &b);
//rgb_to_yuv(r, g, b, &y, &u, &v); //rgb_to_yuv(r, g, b, &y, &u, &v);
rgb_to_hsl(r, g, b, &h, &s, &l); hsv_to_hsl(h2, s2, v2, &h, &s, &l);
rgb_input[0]->SetValue(r); rgb_input[0]->SetValue(r);
rgb_input[1]->SetValue(g); rgb_input[1]->SetValue(g);
rgb_input[2]->SetValue(b); rgb_input[2]->SetValue(b);