Use HSV instead of RGB in WPF

旧街凉风 提交于 2019-12-13 15:46:18

问题


I'm using the Color.FromArgb to for determining the brush color. Using this for examplePen p= new Pen(new SolidColorBrush(Color.FromArgb(95, 255, 0, 0)), 6); the problem with this is that I want to use 4 colors of the brushes (red, orange, yellow and green). And I have a condition where depending on the value in this condition the color is chosen with a certain transparency. The problem with this is the transition between the two different colors, for example from green to yellow or from orange to red, the color changes suddenly and I don't want this. I want to transition to be smooth between different colors so for example from orange to red I want it to take the different degrees of oranges till it becomes reddish till it becomes red. The below is a snapshot of my code trying to clarify what I did, so if anyone could please advise, and please let me know if any more clarification needed. So as shown below depending of the value of X the color is determined with a certain intensity, but the problem is in if the last value of X was 10 which means Green and the current is 11 which means the color is Yellow, this makes the view not smooth because the color changed from Green to Yellow without any degrees of smoothness. And I thought that may be using HSV can solve this problem. So if anyone could please advise.

for(X=0; X<=40; X++)
//this is green phase
if (X == 0)
    P = new Pen(new SolidColorBrush(Color.FromArgb(75, 0, 255, 0)), 6);
else if (X == 1)
    P = new Pen(new SolidColorBrush(Color.FromArgb(77, 0, 255, 0)), 6);
else if (X == 2)
    P = new Pen(new SolidColorBrush(Color.FromArgb(79, 0, 255, 0)), 6);
else if (X == 3)
    P = new Pen(new SolidColorBrush(Color.FromArgb(81, 0, 255, 0)), 6);
else if (X == 4)
    P = new Pen(new SolidColorBrush(Color.FromArgb(83, 0, 255, 0)), 6);
else if (X == 5)
    P = new Pen(new SolidColorBrush(Color.FromArgb(85, 0, 255, 0)), 6);
else if (X == 6)
    P = new Pen(new SolidColorBrush(Color.FromArgb(87, 0, 255, 0)), 6);
else if (X == 7)
    P = new Pen(new SolidColorBrush(Color.FromArgb(89, 0, 255, 0)), 6);
else if (X == 8)
    P = new Pen(new SolidColorBrush(Color.FromArgb(91, 0, 255, 0)), 6);
else if (X == 9)
    P = new Pen(new SolidColorBrush(Color.FromArgb(93, 0, 255, 0)), 6);
else if (X == 10)
    P = new Pen(new SolidColorBrush(Color.FromArgb(95, 0, 255, 0)), 6);

    // this is yellow phase
else if (X == 11)
    P = new Pen(new SolidColorBrush(Color.FromArgb(75, 255, 255, 0)), 6);
else if (X == 12)
    P = new Pen(new SolidColorBrush(Color.FromArgb(77, 255, 255, 0)), 6);
else if (X == 13)
    P = new Pen(new SolidColorBrush(Color.FromArgb(79, 255, 255, 0)), 6);
else if (X == 14)
    P = new Pen(new SolidColorBrush(Color.FromArgb(81, 255, 255, 0)), 6);
else if (X == 15)
    P = new Pen(new SolidColorBrush(Color.FromArgb(83, 255, 255, 0)), 6);
else if (X == 16)
    P = new Pen(new SolidColorBrush(Color.FromArgb(85, 255, 255, 0)), 6);
else if (X == 17)
    P = new Pen(new SolidColorBrush(Color.FromArgb(87, 255, 255, 0)), 6);
else if (X == 18)
    P = new Pen(new SolidColorBrush(Color.FromArgb(89, 255, 255, 0)), 6);
else if (X == 19)
    P = new Pen(new SolidColorBrush(Color.FromArgb(91, 255, 255, 0)), 6);
else if (X == 20)
    P = new Pen(new SolidColorBrush(Color.FromArgb(93, 255, 255, 0)), 6);

    // this is orange phase
else if (X == 21)
    P = new Pen(new SolidColorBrush(Color.FromArgb(75, 255, 127, 0)), 6);
else if (X == 22)
    P = new Pen(new SolidColorBrush(Color.FromArgb(77, 255, 127, 0)), 6);
else if (X == 23)
    P = new Pen(new SolidColorBrush(Color.FromArgb(79, 255, 127, 0)), 6);
else if (X == 24)
    P = new Pen(new SolidColorBrush(Color.FromArgb(81, 255, 127, 0)), 6);
else if (X == 25)
    P = new Pen(new SolidColorBrush(Color.FromArgb(83, 255, 127, 0)), 6);
else if (X == 26)
    P = new Pen(new SolidColorBrush(Color.FromArgb(85, 255, 127, 0)), 6);
else if (X == 27)
    P = new Pen(new SolidColorBrush(Color.FromArgb(87, 255, 127, 0)), 6);
else if (X == 28)
    P = new Pen(new SolidColorBrush(Color.FromArgb(89, 255, 127, 0)), 6);
else if (X == 29)
    P = new Pen(new SolidColorBrush(Color.FromArgb(91, 255, 127, 0)), 6);
else if (X == 30)
    P = new Pen(new SolidColorBrush(Color.FromArgb(93, 255, 127, 0)), 6);

    //this is red phase
else if (X == 31)
    P = new Pen(new SolidColorBrush(Color.FromArgb(75, 255, 0, 0)), 6);
else if (X == 32)
    P = new Pen(new SolidColorBrush(Color.FromArgb(77, 255, 0, 0)), 6);
else if (X == 33)
    P = new Pen(new SolidColorBrush(Color.FromArgb(79, 255, 0, 0)), 6);
else if (X == 34)
    P = new Pen(new SolidColorBrush(Color.FromArgb(81, 255, 0, 0)), 6);
else if (X == 35)
    P = new Pen(new SolidColorBrush(Color.FromArgb(83, 255, 0, 0)), 6);
else if (X == 36)
    P = new Pen(new SolidColorBrush(Color.FromArgb(85, 255, 0, 0)), 6);
else if (X == 37)
    P = new Pen(new SolidColorBrush(Color.FromArgb(87, 255, 0, 0)), 6);
else if (X == 38)
    P = new Pen(new SolidColorBrush(Color.FromArgb(89, 255, 0, 0)), 6);
else if (X == 39)
    P = new Pen(new SolidColorBrush(Color.FromArgb(91, 255, 0, 0)), 6);
else if (X == 40)
    P = new Pen(new SolidColorBrush(Color.FromArgb(93, 255, 0, 0)), 6);

回答1:


Maybe you should take a look into this answer. It helps you to use the methods GetHue(), GetSaturation() and GetBrightness() from the color class and create a new color from these parameters.

By using this you can simply get out the hue of your start and end color and depending on your step size get as much intermediate colors as needed.

Wouldn't it be great to have a method:

int numberOfIntermediateColors = 8;
IEnumerable<Colors> colorPalette = Color.Red.Range(Color.Green, numberOfIntermediateColors);

And here it is:

public static IEnumerable<Color> Range(this Color firstColor, Color lastColor, int count)
{
    float stepHueClockwise = GetStepping(firstColor.GetHue(), lastColor.GetHue(), count, Direction.Clockwise);
    float stepHueCounterClockwise = GetStepping(firstColor.GetHue(), lastColor.GetHue(), count, Direction.CounterClockwise);

    if (Math.Abs(stepHueClockwise) >= Math.Abs(stepHueCounterClockwise))
        return Range(firstColor, lastColor, count, Direction.Clockwise);
    else
        return Range(firstColor, lastColor, count, Direction.CounterClockwise);
}

public static IEnumerable<Color> Range(this Color firstColor, Color lastColor, int count, Direction hueDirection)
{
    var color = firstColor;

    if (count <= 0)
        yield break;

    if (count == 1)
        yield return firstColor;

    float startingHue = color.GetHue();
    float stepHue = GetStepping(firstColor.GetHue(), lastColor.GetHue(), count - 1, hueDirection);
    var stepSaturation = (lastColor.GetSaturation() - firstColor.GetSaturation()) / (count - 1);
    var stepBrightness = (lastColor.GetBrightness() - firstColor.GetBrightness()) / (count - 1);
    var stepAlpha = (lastColor.A - firstColor.A) / (count - 1.0);

    for (int i = 1; i < count; i++)
    {
        yield return color;

        var hueValue = startingHue + stepHue * i;

        if (hueValue > 360)
            hueValue -= 360;

        if (hueValue < 0)
            hueValue = 360 + hueValue;

        color = FromAhsb(
                    Clamp((int)(color.A + stepAlpha), 0, 255),
                         hueValue,
                         Clamp(color.GetSaturation() + stepSaturation, 0, 1),
                         Clamp(color.GetBrightness() + stepBrightness, 0, 1));
    }

    yield return lastColor;
}

    public enum Direction
    {
        Clockwise = 0,
        CounterClockwise = 1
    }

private static float GetStepping(float start, float end, int count, Direction direction)
{
    var hueDiff = end - start;

    switch (direction)
    {
        case Direction.CounterClockwise:
            if (hueDiff >= 0)
                hueDiff = (360 - hueDiff) * -1;
            break;

        default:
            if (hueDiff <= 0)
                hueDiff = 360 + hueDiff;
            break;
    }

    return hueDiff / count;
}

private static int Clamp(int value, int min, int max)
{
    if (value < min)
        return min;

    if (value > max)
        return max;

    return value;
}

private static float Clamp(float value, float min, float max)
{
    if (value < min)
        return min;

    if (value > max)
        return max;

    return value;
}

To get your list of pens without any transparency you can take this simple approach:

var startColor = Color.Green;
var endColor = Color.Red;
var penWidth = 6;

var rainbow = startColor.Range(endColor, 40, bla.Direction.CounterClockwise);
var pens = rainbow.Select(color => new Pen(color, penWidth))
                  .ToList();

// Somewhere else...
int x = RetrieveDesiredCondition();
var neededPen = pens[x];

As far as i can see in your example you like to let the transparency iterate from 75 - 95 for each block of ten colors and a total of four blocks. In that case maybe this algorithm may help:

var startColor = Color.Green;
var endColor = Color.Red;
var penWidth = 6;
var lowerTransparency = 75;
var higherTransparency = 95;
var stepsPerSection = 10;
var sections = 4;
var stepsNeeded = stepsPerSection * sections;

var transparencyRange = higherTransparency - lowerTransparency;
var stepSize = transparencyRange / stepsPerSection;
var rainbow = startColor.Range(endColor, stepsNeeded, Direction.CounterClockwise);
var rainbowWithTransparency = rainbow.Select((color, index) =>
{
    var step = (index % stepsPerSection) * stepSize;
    var neededTransparency = lowerTransparency + step;
    return Color.FromArgb(neededTransparency, color);
});

var pens = rainbowWithTransparency.Select(color => new Pen(color, penWidth))
                                  .ToList();

// Somewhere else...
int x = RetrieveDesiredCondition();
var neededPen = pens[x];


来源:https://stackoverflow.com/questions/18821696/use-hsv-instead-of-rgb-in-wpf

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!