Convert RGB method? - c#

How can I do this?
int blue = Color.Blue.ToArgb();
int yellow = Color.Yellow.ToArgb();
blue = (blue + yellow) / 2;
Color Blue = ConvertFromRGB(blue);

I think what you're looking for is this:
var blueColor = Color.FromArgb((blue + yellow) / 2);
However, I don't think it will give you the result you actually want.
You must be quite careful about mixing colours in this way. The int value representing a colour in ARGB form is fairly arbitrary as far as the coder is concerned. It's probably best to mix RGB components individually, like:
var color1 = Color.Blue;
var color2 = Color.Yellow;
var blueColor = Color.FromArgb((color1.R + color2.R) / 2,
(color1.G + color2.G) / 2, (color1.B + color2.B) / 2);
This interpolates (taking the centre point) between two colours, and should give you something that looks much more like the blend of the two colours.
(Note that I assume you're referring to the System.Drawing.Color type here.)

I think this is what you might be looking for:
int blue = Color.Blue.ToArgb();
int yellow = Color.Yellow.ToArgb();
blue = (blue + yellow)/2;
Color Blue = Color.FromArgb(blue);

Just average the colors component-wise, if that is what you are trying to do:
Color average = ConvertFromRGB((Color.Blue.R + Color.Yellow.R) / 2), (Color.Blue.G + Color.Yellow.G) / 2), (Color.Blue.B + Color.Yellow.B) / 2));

It would be useful to know what you're expecting from the second assign to 'blue' - you certainly won't be getting a shade of blue (more like red).
The problem is that the Color class keeps its ARGB values as Int32 because each of the 4 bytes represents one of the Alpha, Red, Blue and Green values.
Asking to add together two colours in their Int32 form is going to cause unexpected values, as one byte 'overflows' into the next (what happens when you add 255 and 1?)
Color.Blue, for example, is -16776961. That's because it has 4 bytes that look like this:
0: 255
1: 0
2: 0
3: 255
Or:
11111111 00000000 00000000 11111111
You'll find it much clearer to break the ARGB components down into individual bytes, System.Drawing.Color allows you to do this via its instance properties:
blue.A
blue.R
blue.G
blue.B
You can safely manipulate these, but remember that they're an instance of Byte, so you can't assign a value out of the range 0-255. To create a colour from the component bytes, use:
Color.FromArgb(a, r, g, b);
Where a, r, g, b are bytes.
Somewhat confusingly, Color.FromArgb accepts int parameters, rather than bytes. I'm afraid I've no idea why, someone better than me will have to answer that, but casting a byte to an int with produce an int with a value between 0 and 255, so it's safe to use this. Color also has a private CheckByte class that it passes each argument into so you'll get an ArgumentException rather than an unexpected color (that you'll likely get with your non-component approach).

Related

Determine which color (red, blue, green or other) would be visible for a given RGB value combination?

So basically, I need a method in which I can pass values of red, green and blue and the method should return whether that combination of RGB values result in a visibly Red-ish color Green-ish color or Blue-ish color. And if the combination doesn't result in any of those three colors it should return false.
I tried to do this by using conditional statements, tried a few variations, but nothing is accurate.
For example I tried:
if (B > 100 && B > G / 2 && B > R / 2)
{
blueCount++;
}
else if (G > 100 && G > G / 2 && G > B / 2)
{
greenCount++;
}
else if (R > 100 && R > G / 2 && R > B / 2)
{
redCount++;
}
// R , G , B contains 0-255 values
If you define "being color-ish" as:
the color value is above 100
the color value is at least twice as the 2 other values
your current code states "at least half of the 2 other values" but this can't work because if you have "R:199 G:101 B:102", you could say that it is green-ish because G is above 100 and more than half 199 and half 102 (when it's obviously red-ish)
then your code looks almost good (just replace / with *).
I would just use an enum for the result:
enum Ish
{
Other, // 0 so this would be false if you convert it to bool
Red, // 1
Green, // 2
Blue // 3
}
if (R>100 && R>G*2 && R>B*2)
return Ish.Red;
if (G>100 && G>R*2 && G>B*2) // you had G>G/2 here /!\
return Ish.Green;
if (B>100 && B>G*2 && B>R*2)
return Ish.Blue;
return Ish.Other;
I used 2 for twice, but I think you can use other values as long as it is >1 (you can't say blue is dominant if B <= R for example)
This would be the redish values possible for R=100 (left image with factor 2, right image with factor 1):
And this for R=200 (left image with factor 2, right image with factor 1):
Therefore you could probably use a factor between 1 and 2
For R=200 you can see the red-ish colors depending on the factor below:
I suggest using different color space: HSV or HSL instead of RGB.
Now, to declare the color being greenish you have to check
If color has H (Hue) within some range (Green tinge dominates over other colors)
If color has S (Saturation) above some threshold in order not to be too colorless (grayish)
If color has V or L (Value or Luminocity) above some threshold in order not to be too dark (blackish)
https://vignette.wikia.nocookie.net/psychology/images/e/e0/HSV_cylinder.png/revision/latest?cb=20071105130143
Don't try to hard to encounter a perfectly accurate answer for this. After all, there is no such thing as a perfect defined line between red-ish and not red-ish.
The way I would approach this is: first, check that color is not too grey/black. This can be done using the sum of the three components (keep in mind that full black is 0;0;0 on RGB, greys are usually something like 55;55;55). For example, you could consider as too dark any color whose components sum up less than 300. Play a little bit with any RGB picker tool to find the threshold you like the most.
EDIT: from comment below I see sum of three components won't work, for example the 255;0;0 would be consider as too grey. So you have to use maximum value of the three components. For example, 20;0;0 would still be quite dark, but 100;0;0 not so much. Thanks to #rafalon for pointing this out.
Then, you would need to check that this color is close to a "pure" color, that is, red, green or blue. In order to do that, you would need to compare the most prominent component with the other two. You have to compare this highest component with the other two, individually. This is because a color like 255;0;255 is not redish at all, while a 255;128;128 could be considered as such. So combination of the two less prominents components won't do the trick.
You could consider a color to be red-ish if both Green and Blue have a value lower than some percentage of red. Take for example this percentage to be 50%. Then, you need to check that green is less than 0.5 * red AND blue is less than 0.5 * red. Again, you should play a bit with RGB colors to find a percentage that you think it suits.
TL;DR: for a color with components r, g and b, this color will be a "pure" color if:
Max(r, g, b) > tooDarkValue
r > somePercentage * Max(r, g, b) AND g > somePercentage * Max(r, g, b) AND b > somePercentage * Max(r, g, b)
Note that second condition will always be true for Max(r, g, b), (any number is greater than a percentage of itself), so no need to evaluate which component is highest and then have 3 different conditions

OpenGL Gl.glColor3f How to color with one parametr?

I have some question about visualization in OpenGL. I have points in 3D space, each point also have one extraValue, which represent diffrent values, eg temperature, pressure and so on. User chooses one of this and other method sets extraValue to each point.
First problem is, that this values have diffrent ranges, eg:
temperature: <80; 2000>
preassure: <-500; 400>
gamma: <0,5; 1,8>
...
Now I want to visualize it to look for reliable, for example the temperature: 80 C is cold, so blue color, 2000 is hot so red. Similarry for others, preassure, gamma and so on.
The second problem is that Gl.glColor3f accepts 3 parameters: red, green, blue. I have only ONE parameter to each ponit.
Range of RGB is <0;1>, my values have diffrent ranges.
Does anybody have an idea, or some algorithm that could help mi with this ?
Firstly, remap your value into a range of 0-1, like so:
double t = ( value - min ) / ( max - min ); // i.e. min could be 80 and max 2000
// it might be a good idea to limit t to 0-1 here, in case
// your original value could be outside the valid range
Then, do a linear interpolation between the colors, like so (pseudocode):
Color a = Blue, b = Red
double inv = 1.0 - t
Color result = Color( inv * a.R + t * b.R,
inv * a.G + t * b.G,
inv * a.B + t * b.B )
That should get you started!

How do I implement this "color difference" algorithm?

As a follow up to this question: (How can I draw legible text on a bitmap (Winforms)?), I'm drawing legible but small text on top of a bitmap by calculating the "average" color beneath the text, and choosing an appropriately contrasting color for the text.
I've stolen Till's code from https://stackoverflow.com/a/6185448/3784949 for calculating "average" bmp color. Now I'm looking at the "color difference" algorithm suggested by http://www.w3.org/TR/AERT#color-contrast.
This suggests that I need to make my color brightness at least 125 "units" greater, and my color difference at least 500 units greater, where brightness and difference are calculated like this:
Color brightness is determined by the following formula:
((Red value X 299) + (Green value X 587) + (Blue value X 114)) / 1000
Color difference is determined by the following formula:
(maximum (Red value 1, Red value 2) - minimum (Red value 1, Red value 2)) + (maximum (Green value 1, Green value 2) - minimum (Green value 1, Green value 2)) + (maximum (Blue value 1, Blue value 2) - minimum (Blue value 1, Blue value 2))
How do I implement this? I can set my color by ARGB (I believe, it's a label foreground color); but how do I calculate how much to change each individual value to achieve the difference being required here? I'm not familiar with the math required to break the "difference" units down into their component parts.
As an example, my "average" for one bitmap is: Color [A=255, R=152, G=138, B=129]. How do I "add" enough to each part to achieve the two differences?
EDIT: To be specific, my confusion lies here:
it looks like I need to add to three separate values (R,G,B) to achieve two different goals (new RGB adds up to original plus 125, new RGB adds up to original plus 500
it looks like I may need to "weight" my added brighness values to add more to G than R than B.
I have no idea how to address #1. And I'm not positive I'm correct about #2.
EDIT: Proposed solution
I'm currently experimenting with this:
private Color GetContrastingFontColor(Color AverageColorOfBitmap,
List<Color> FavoriteColors)
{
IEnumerable<Color> AcceptableColors =
(IEnumerable<Color>)FavoriteColors.Where(clr =>
(GetColorDifferenceAboveTarget(AverageColorOfBitmap, clr, (float)200) > 0)
&& (GetBrightnessAboveTarget(AverageColorOfBitmap, clr, (float).125) > 0))
.OrderBy(clr => GetColorDifferenceAboveTarget(
AverageColorOfBitmap, clr, (float)200));
return AcceptableColors.DefaultIfEmpty(Color.Aqua).First();
}
It's a good framework, but I need to work on selecting the "best" candidate from the list. Right now it's just returning "the qualifying color with the greatest color difference that meets the brightness criteria". However, this allows me to modify the float values (W3's "500 color difference required" is complete crap, zero KnownColors qualify) and experiment.
Support code:
private float GetBrightnessAboveTarget(Color AverageColorOfBitmap,
Color proposed, float desiredDifference)
{
float result = proposed.GetBrightness() - AverageColorOfBitmap.GetBrightness();
return result - desiredDifference;
}
private float GetColorDifferenceAboveTarget(Color avg, Color proposed,
float desiredDifference)
{
float r1 = Convert.ToSingle(MaxByte(Color.Red, avg, proposed));
float r2 = Convert.ToSingle(MinByte(Color.Red, avg, proposed));
float r3 = Convert.ToSingle(MaxByte(Color.Green, avg, proposed));
float r4 = Convert.ToSingle(MinByte(Color.Green, avg, proposed));
float r5 = Convert.ToSingle(MaxByte(Color.Blue, avg, proposed));
float r6 = Convert.ToSingle(MinByte(Color.Blue, avg, proposed));
float result = (r1 - r2) + (r3 - r4) + (r5 - r6);
return result - desiredDifference;
}
private byte MaxByte(Color rgb, Color x, Color y)
{
if (rgb == Color.Red) return (x.R >= y.R) ? x.R : y.R;
if (rgb == Color.Green) return (x.G >= y.G) ? x.G : y.G;
if (rgb == Color.Blue) return (x.B >= y.B) ? x.B : y.B;
return byte.MinValue;
}
private byte MinByte(Color rgb, Color x, Color y)
{
if (rgb == Color.Red) return (x.R <= y.R) ? x.R : y.R;
if (rgb == Color.Green) return (x.G <= y.G) ? x.G : y.G;
if (rgb == Color.Blue) return (x.B <= y.B) ? x.B : y.B;
return byte.MinValue;
}
This is more an answer to the original question. I call it a homemeade outline.
Using transparency plus the maximum and minimum brightness you can get (white&black) it creates good contrast, at least it looks pretty good on my screen.
It is a mixture of shadowing and transparency. I have subtracted a little from the red component to get the aqua you thought about..
It is creating first a darker version of the background by printing the text 1 pixel up left and the 1 pixel down right. Finally it prints a bright version on top of that. Note that it is not really using black and white because with its semi-transparent pixels the hue really it that of each background pixel.
For an actual printout you will have to experiment, especially with the font but also with the two transparencies!
Also you should maybe switch between white on a black shadow and black on a white highlight, depending on the brightness of the spot you print on. But with this homemeade outline it really will work on both dark and bright backgrounds, it'll just look a little less elegant on a bright background.
using (Graphics G = Graphics.FromImage(pictureBox1.Image) )
{
Font F = new Font("Arial", 8);
SolidBrush brush0 = new SolidBrush(Color.FromArgb(150, 0, 0, 0))
SolidBrush brush1 = new SolidBrush(Color.FromArgb(200, 255, 255, 222))
G.DrawString(textBox1.Text, F, brush0 , new Point(x-1, y-1));
G.DrawString(textBox1.Text, F, brush0 , new Point(x+1, y+1));
G.DrawString(textBox1.Text, F, brush1, new Point(x, y));
}
Edit: This is called from a button click but really should be in the paint event.
There the Graphics object and its using block G would be replaced by simply the e.Graphics event parameter..
I noticed that you are using a 'transparent' label to display the data to avoid the details of Graphics.DrawString and the Paint event.
Well that can be done and the result looks rather similar:
string theText ="123 - The quick brown fox..";
Label L1, L2, L3;
pictureBox1.Controls.Add(new trLabel());
L1 = (trLabel)pictureBox1.Controls[pictureBox1.Controls.Count - 1];
L1.Text = theText;
L1.ForeColor = Color.FromArgb(150, 0, 0, 0);
L1.Location = new Point(231, 31); // <- position in the image, change!
L1.Controls.Add(new trLabel());
L2 = (trLabel)L1.Controls[pictureBox1.Controls.Count - 1];
L2.Text = theText;
L2.ForeColor = Color.FromArgb(150, 0, 0, 0);
L2.Location = new Point(2, 2); // do not change relative postion in the 1st label!
L2.Controls.Add(new trLabel());
L3 = (trLabel)L2.Controls[pictureBox1.Controls.Count - 1];
L3.Text = theText;
L3.ForeColor = Color.FromArgb(200, 255, 255, 234);
L3.Location = new Point(-1,-1); // do not change relative postion in the 2nd label!
However you will note that due to the impossiblity of having really transparent controls in Winforms we need a little extra effort. You probably use a label subclass like this:
public partial class trLabel : Label
{
public trLabel()
{
SetStyle(ControlStyles.SupportsTransparentBackColor | ControlStyles.UserPaint, true);
BackColor = Color.Transparent;
Visible = true;
AutoSize = true;
}
}
This seems to work. But in reality it only seems that way, because upon creation each label gets a copy of its current background from its parent. Which never gets updated. Which is why I have to add the 2nd & 3rd label not to the picturebox I display the image in, but to the 1st and 2nd
'transparent' label respectively.
There simply is not real transparency between Winforms controls unless you draw things yourself.
So the DrawString solution is not really complicated. And it gives you the bonus of allowing you to twist several properties of the Graphics object like Smoothingmode, TextContrast or InterpolationMode
Short suggestion: Just use black or white.
The algorithms are giving you a passing criteria, but not an algorithm for determining what colors meet that criteria. So, you will have to create such an algorithm. A naive algorithm would be to loop through every possible color, and calculate the color difference, then see if the difference is greater than 125, and if so you have a good color to use. Better, you could search for the color with the maximum difference.
But that's foolish - if I gave you the color R=152, G=138, B=129 - what do YOU think is a very good color to contrast that with? Just by gut, I'm gonna guess 0,0,0. I picked a color with the farthest possible R value, G value, and B value. If you gave me the color 50,200,75 I'd pick R=255, G=0, B=255. Same logic. So my algorithm is if R<128 choose R = 255, else choose R = 0. Same thing for G, and B.
Now that algorithm only picks RGB values that are 0 or 255. But if you don't like that, now you need a mathematical definition for what is "pretty" and I'll leave you to figure that out on your own. :-)

How do I invert a colour?

I know that this won't directly invert a colour, it will just 'oppose' it. I was wondering if anyone knew a simple way (a few lines of code) to invert a colour from any given colour?
At the moment I have this (which isn't exactly the definition of an invert, because if I pass it a grey / gray colour it will return something extremely similar e.g. 127, 127, 127):
const int RGBMAX = 255;
Color InvertMeAColour(Color ColourToInvert)
{
return Color.FromArgb(RGBMAX - ColourToInvert.R,
RGBMAX - ColourToInvert.G, RGBMAX - ColourToInvert.B);
}
It depends on what do you mean by "inverting" a color
Your code provides a "negative" color.
Are you looking for transform red in cyan, green in purple, blue in yellow (and so on) ? If so, you need to convert your RGB color in HSV mode (you will find here to make the transformation).
Then you just need to invert the Hue value (change Hue by 360-Hue) and convert back to RGB mode.
EDIT: as Alex Semeniuk has mentioned, changing Hue by (Hue + 180) % 360 is a better solution (it does not invert the Hue, but find the opposite color on the color circle)
You can use :
MyColor=Color.FromArgb(MyColor.ToArgb()^0xffffff);
It will invert MyColor.
Try this:
uint InvertColor(uint rgbaColor)
{
return 0xFFFFFF00u ^ rgbaColor; // Assumes alpha is in the rightmost byte, change as needed
}
If you want to change every color, try a rotational function (shifting or adding) rather than a flipping function (inverting). In other words, consider the range of 0 to 255 for each single color (red, green, and blue) to be wrapped, connected at the tips like a circle of values. Then shift each color around the cirle by adding some value and doing mod 256. For example, if your starting value for red is 255, and you add 1, you get 0. If you shift all three colors by 128, you get dramatically different values for every original color in the picture, even the grays. Gray 127, 127, 127 becomes white 255, 255, 255. Gray 128, 128, 128 becomes black 0, 0, 0. There's a photographic effect like that called Solarization, discovered by accident by Man Ray in the 1930's.
You can also do rotational operations on each color (red, green, blue) by a different amount to really mess up a picture.
You can also do rotational operations on hue, shifting the hue of every original color by some amount on the hue circle, which alters all the colors without altering the brightness, so the shadows still look like shadows, making people look like Simpsons or Smurphs for example.
The code for a shift by 128 could look like:
public static Color Invert(this Color c) => Color.FromArgb(c.R.Invert(), c.G.Invert(), c.B.Invert());
public static byte Invert(this byte b) {
unchecked {
return (byte)(b + 128);
}
}
Invert the bits of each component separately:
Color InvertMeAColour(Color ColourToInvert)
{
return Color.FromArgb((byte)~ColourToInvert.R, (byte)~ColourToInvert.G, (byte)~ColourToInvert.B);
}
EDIT: The ~ operator does not work with bytes automatically, cast is needed.
What you already have is an RGB-Invert. There are other ways to classify colors and hence other definitions for the Inverse of a Color.
But it sounds like maybe you want a contrasting Color, and there isn't a simple Inversion that is going to work for all colors including RGB(127, 127, 127).
What you need is 1) a conversion to HSV (see ThibThibs answer) and invert the Hue, but also 2) check if the Hue isn't to close to the middle and if so go to either fully bright or fully dark.
The most simple and lazy way I made it to work with having not only triple 12x, but mixed values, is this:
Color invertedColor= Color.FromArgb(fromColor.ToArgb() ^ 0xffffff);
if (invertedColor.R > 110 && invertedColor.R < 150 &&
invertedColor.G > 110 && invertedColor.G < 150 &&
invertedColor.B > 110 && invertedColor.B < 150)
{
int avg = (invertedColor.R + invertedColor.G + invertedColor.B) / 3;
avg = avg > 128 ? 200 : 60;
invertedColor= Color.FromArgb(avg, avg, avg);
}
Now, invertedColor has a different color that the original, even if we have a 128, 128, 128 or close to it color value.
I've created this simple function for VB.NET:
Public Shared Function Invert(ByVal Culoare As Color) As Color
Return Color.FromArgb(Culoare.ToArgb() Xor &HFFFFFF)
End Function
And this one for C#:
public static Color Invert(Color Culoare)
{
return Color.FromArgb(Culoare.ToArgb() ^ 0xFFFFFF);
}

How do I determine darker or lighter color variant of a given color?

Given a source color of any hue by the system or user, I'd like a simple algorithm I can use to work out a lighter or darker variants of the selected color. Similar to effects used on Windows Live Messenger for styling the user interface.
Language is C# with .net 3.5.
Responding to comment: Color format is (Alpha)RGB. With values as bytes or floats.
Marking answer: For the context of my use (a few simple UI effects), the answer I'm marking as accepted is actually the most simple for this context. However, I've given up votes to the more complex and accurate answers too. Anyone doing more advanced color operations and finding this thread in future should definitely check those out. Thanks SO. :)
In XNA there is the Color.Lerp static method that does this as the difference between two colours.
Lerp is a mathematical operation between two floats that changes the value of the first by a ratio of the difference between them.
Here's an extension method to do it to a float:
public static float Lerp( this float start, float end, float amount)
{
float difference = end - start;
float adjusted = difference * amount;
return start + adjusted;
}
So then a simple lerp operation between two colours using RGB would be:
public static Color Lerp(this Color colour, Color to, float amount)
{
// start colours as lerp-able floats
float sr = colour.R, sg = colour.G, sb = colour.B;
// end colours as lerp-able floats
float er = to.R, eg = to.G, eb = to.B;
// lerp the colours to get the difference
byte r = (byte) sr.Lerp(er, amount),
g = (byte) sg.Lerp(eg, amount),
b = (byte) sb.Lerp(eb, amount);
// return the new colour
return Color.FromArgb(r, g, b);
}
An example of applying this would be something like:
// make red 50% lighter:
Color.Red.Lerp( Color.White, 0.5f );
// make red 75% darker:
Color.Red.Lerp( Color.Black, 0.75f );
// make white 10% bluer:
Color.White.Lerp( Color.Blue, 0.1f );
Simply multiply the RGB values by the amount you want to modify the level by. If one of the colors is already at the max value, then you can't make it any brighter (using HSV math anyway.)
This gives the exact same result with a lot less math as switching to HSV and then modifying V. This gives the same result as switching to HSL and then modifying L, as long as you don't want to start losing saturation.
HSV ( Hue / Saturation / Value ) also called HSL ( Hue / Saturation / Lightness ) is just a different color representation.
Using this representation is it easier to adjust the brightness. So convert from RGB to HSV, brighten the 'V', then convert back to RGB.
Below is some C code to convert
void RGBToHSV(unsigned char cr, unsigned char cg, unsigned char cb,double *ph,double *ps,double *pv)
{
double r,g,b;
double max, min, delta;
/* convert RGB to [0,1] */
r = (double)cr/255.0f;
g = (double)cg/255.0f;
b = (double)cb/255.0f;
max = MAXx(r,(MAXx(g,b)));
min = MINx(r,(MINx(g,b)));
pv[0] = max;
/* Calculate saturation */
if (max != 0.0)
ps[0] = (max-min)/max;
else
ps[0] = 0.0;
if (ps[0] == 0.0)
{
ph[0] = 0.0f; //UNDEFINED;
return;
}
/* chromatic case: Saturation is not 0, so determine hue */
delta = max-min;
if (r==max)
{
ph[0] = (g-b)/delta;
}
else if (g==max)
{
ph[0] = 2.0 + (b-r)/delta;
}
else if (b==max)
{
ph[0] = 4.0 + (r-g)/delta;
}
ph[0] = ph[0] * 60.0;
if (ph[0] < 0.0)
ph[0] += 360.0;
}
void HSVToRGB(double h,double s,double v,unsigned char *pr,unsigned char *pg,unsigned char *pb)
{
int i;
double f, p, q, t;
double r,g,b;
if( s == 0 )
{
// achromatic (grey)
r = g = b = v;
}
else
{
h /= 60; // sector 0 to 5
i = (int)floor( h );
f = h - i; // factorial part of h
p = v * ( 1 - s );
q = v * ( 1 - s * f );
t = v * ( 1 - s * ( 1 - f ) );
switch( i )
{
case 0:
r = v;
g = t;
b = p;
break;
case 1:
r = q;
g = v;
b = p;
break;
case 2:
r = p;
g = v;
b = t;
break;
case 3:
r = p;
g = q;
b = v;
break;
case 4:
r = t;
g = p;
b = v;
break;
default: // case 5:
r = v;
g = p;
b = q;
break;
}
}
r*=255;
g*=255;
b*=255;
pr[0]=(unsigned char)r;
pg[0]=(unsigned char)g;
pb[0]=(unsigned char)b;
}
Rich Newman discusses HSL color with respect to .NET System.Drawing.Color on his blog and even provides an HSLColor class that does all the work for you. Convert your System.Drawing.Color to an HSLColor, add/subtract values against the Luminosity, and convert back to System.Drawing.Color for use in your app.
You can convert your color into the HSL color-space, manipulate it there and convert back to your color-space of choice (most likely that's RGB)
Lighter colors have a higher L-value, darker a lower.
Here's the relevant stuff and all the equations:
http://en.wikipedia.org/wiki/HSL_color_space
Another method is to simply interpolate your color with white or black. This will also desaturate the color a bit but it's cheaper to calculate.
I have used the ControlPaint.Dark() and .Light() in System.Windows.Forms.
I'm guessing you're using RGB with byte values (0 to 255) as that's very common everywhere.
For brighter, average the RGB values with the RGB of white. Or, to have some control over how much brightening, mix in them in some proportion. Let f vary from 0.0 to 1.0, then:
Rnew = (1-f)*R + f*255
Gnew = (1-f)*G + f*255
Bnew = (1-f)*B + f*255
For darker, use the RGB of black - which, being all zeros, makes the math easier.
I leave out details such as converting the result back into bytes, which probably you'd want to do.
If you are using RGB colors I would transform this color paramaters to HSL (hue, saturation, lightness), modify the lightness parameter and then transform back to RGB. Google around and you'll find a lot of code samples on how to do these color representation transformations (RGB to HSL and viceversa).
This is what I quickly found:
http://bytes.com/forum/thread250450.html
Assuming you get the color as RGB, first convert it to HSV (hue, saturation, value) color space. Then increase/decrease the value to produce lighter/darker shade of the color. Then convert back to RGB.
If your colours are in RGB format (or, presumably CMYK), you can use the fairly crude method of increasing the value of each component of the colour. E.g., in HTML colours are represented as three two-digit hex numbers. #ff0000 will give you a bright red, which can then be faded by increasing the values of the G and B componenets by the same amount, such as #ff5555 (gives a lighter red). Presumably for Hue, Saturation and Lightness (HSL) colours, you can just raise the L component, but I can't say for certain; I'm less familiar with this colour space.
As I say, though, this method is quite crude. From my memories of Live Messenger, it sounds like you're trying to do gradients, which can be applied really quite easily in Windows Presentation Foundation (WPF, part of .NET 3.0). WPF supports many different types of gradient brush, including linear and radial gradients.
I can highly recommend Adam Nathan's book Windows Presentation Foundation Unleashed as a good and thorough introduction to WPF.
HTH
Any variations in color are better done in HSL/HSV.
A good test is to interpolate between two equivalent values in RGB space and HSL space. The ramp in HSL space looks like a natural progression. In RGB space it typically looks quite unnatural. HSL maps to our visual color space perception much better than RGB.
The idea of converting to HSV or some other color space seems good, and may be necessary for precise color work, but for ordinary purposes the error of working in RGB may not be enough to matter. Also, it can be a pain to deal with boundary cases: RGB is a cube-shaped space, while HSV is not. If working with byte values, you can have many-to-one and one-to-many mappings between the spaces. This may or may not be a problem depending on the application. YMMV
This website notes that you can use the ControlPaint class within the BCL C# System.Windows.Forms namespace.

Categories