Reputation: 67898
I'm trying to fade a color, let's say Yellow
to White
over a period of time. I've got the timer worked out, and I'm applying the new color just fine as well, but the fade isn't smooth (e.g. it fades into some weird colors before it gets to White
, some of which are darker than their predecessor on the "fade chain" let's call it). I'm confident that's because the math is wrong, but I just can't seem to find a good example of the math for me to modify what I'm doing.
I even pulled the basics of the ColorCeiling
code from this question: Fade a color to white (increasing brightness)
Right now I take a color, and call an extension method Increase
:
dataGridViewResults.Rows[0].DefaultCellStyle.BackColor.Increase(50);
public static Color Increase(this Color color, byte offset)
{
return Color.FromArgb(
color.A.ColorCeiling(offset),
color.R.ColorCeiling(offset),
color.G.ColorCeiling(offset),
color.B.ColorCeiling(offset));
}
and as you can see, each color is then modified by an offset with a ceiling in mind to keep exceptions from being thrown. That extension method, ColorCeiling
looks like this:
public static int ColorCeiling(this byte val, byte modifier, byte ceiling = 255)
{
return (val + modifier > ceiling) ? ceiling : val + modifier;
}
Now, I'm confident that ColorCeiling
is the problem, but I honestly just can't find the math. I honestly feel like just incrementing the ARGB is almost certainly the wrong approach, it seems like you'd say I want you to be 50% lighter, but I just don't know what that means as far as code.
Upvotes: 5
Views: 6132
Reputation: 1353
Here is some code I use to fade from one color to another in the RGB color space. It works quite well for my purposes. You might have to adapt it to return the colors in steps. Currently for each i
you will have a curClr
that is i/discreteUnits
percent between baseClr
and fadeTo
.
int discreteUnits = 10;
Color fadeTo = Color.Green;
Color baseClr = Color.Red;
float correctionFactor = 0.0f;
float corFactorStep = 1.0f / discreteUnits;
for(int i = 0; i < discreteUnits; i++)
{
correctionFactor += corFactorStep;
float red = (fadeTo.R - baseClr.R) * correctionFactor + baseClr.R;
float green = (fadeTo.G - baseClr.G) * correctionFactor + baseClr.G;
float blue = (fadeTo.B - baseClr.B) * correctionFactor + baseClr.B;
Color curClr = Color.FromArgb(baseClr.A, (int)red, (int)green, (int)blue);
}
Credit to this site for giving me a starting place: http://www.pvladov.com/2012/09/make-color-lighter-or-darker.html
Upvotes: 0
Reputation: 14282
Percentage implies multiplication, not addition. In my really simple JavaScript Color class, I do this sort of thing by defining two colors and blending the RGB dimensions.
From my Color class:
this.getBlendedColor = function(color, percent) {
// limit percent between 0 and 1.
// this percent is the amount of 'color' rgb components to use
var p = percent > 0 ? percent : 0;
p = p < 1 ? p : 1;
// amount of 'this' rgb components to use
var tp = 1 - p;
// blend the colors
var r = Math.round(tp * this.r + p * color.r);
var g = Math.round(tp * this.g + p * color.g);
var b = Math.round(tp * this.b + p * color.b);
// return new color object
return new Color(r, g, b);
} // getBlendedColor ()
So, if you had some Color c, and you wanted to get it 50% whiter, you'd do this:
var newColor = c.getBlendedColor(new Color('#ffffff'), 0.50);
If you're using the alpha channel, it can be explicitly included without causing any trouble -- both colors in you example are probably at 100% opacity.
An example gradient using simple RGB Color blending math: http://jsfiddle.net/2MymY/1/
Upvotes: 1
Reputation: 28563
A gradient is what you're looking for. YOu'll have to seperate them and recombine them like so..
int rMax = Color.Yellow.R;
int rMin = Color.White.R;
int bMax = Color.Yellow.B;
int bMin = Color.White.B;
int gMax = Color.Yellow.G;
int gMin = Color.White.G;
var colorList = new List<Color>();
for(int i=0; i<size; i++)
{
var rAverage = rMin + (int)((rMax - rMin) * i / size);
var bAverage = bMin + (int)((bMax - bMin) * i / size);
var gAverage = gMin + (int)((gMax - gMin) * i / size);
colorList.Add(Color.FromArgb(rAverage, gAverage, bAverage));
}
Upvotes: 2
Reputation: 660024
Here's an idea that might work.
Don't do the math in Red-Green-Blue space. Instead treat your colour as having three components:
There are algorithms for converting from RGB to HSV; look them up. This is a good place to start:
http://en.wikipedia.org/wiki/HSL_and_HSV
Now when you are fading from one color to the other, take steps along the HSV axes, not along the RGB axes.
Upvotes: 8