WPF Color interpolation

后端 未结 5 1198
离开以前
离开以前 2021-01-15 14:43

I am trying to paint a WPF control\'s background based on a palette where each color has been assigned with values (e.g. Red = 0, DarkGreen = 10, Green = 20,LightGreen =30)

相关标签:
5条回答
  • 2021-01-15 14:55

    Using the LinearGradientBrush sounds like it would have a bit of an overhead. No knowledge though. A color interpolation function isn't that hard to write though.

    I'm assuming your palettes have values that are divisible by 10 for simplicity.

    public static Color GetColor(int value)
    {
        int startIndex = (value/10)*10;
        int endIndex = startIndex + 10;
    
        Color startColor = Palette[startIndex];
        Color endColor = Palette[endIndex];
    
        float weight = (value - startIndex)/(float)(endIndex - startIndex);
    
        return Color.FromArgb(
            (int)Math.Round(startColor.R * (1 - weight) + endColor.R * weight),
            (int)Math.Round(startColor.G * (1 - weight) + endColor.G * weight),
            (int)Math.Round(startColor.B * (1 - weight) + endColor.B * weight));
    
    }
    

    If the defined colors are not divisible by 10 the logic to find the start and end colors will be a bit more complex.

    0 讨论(0)
  • 2021-01-15 14:55

    I think you'll be better of using a value converter, just take one of the interpolation functions suggested in the other answers and put in in a value converter, use this converter to bind the background property to the value and you're done.

    0 讨论(0)
  • 2021-01-15 15:08

    Where did you come up with the Values 10/20/30 for your DarkGreen/Green/Lightgreen colors.

    You'll need some sort of correlation table between your assigned palette values & the real numeric representations of the colors... e.g.

    Color             Pal-Code     RGB            HSL
    Red               0            255,0,0        0,240,120
    Dark Green        10           0,128,0        80,240,60
    Green             20           0,255,0        80,240,120
    Light Green       30           128,255,128    80,240,180
    

    From that correlation table, you could take any user "palette code", find the closed matching pair of palette codes from the table above and do a best-match range find on it. e.g. if some entered 25 (let's use HSL for convenience) then the formula would be...

    Green             20           0,255,0        80,240,120
    Light Green       30           128,255,128    80,240,180
    

    25 is halfway between both codes so

    Palette Code     Hue        Sat      Luminence
    20               80         240      120
    30               80         240      180
    -------------------------------------------------
    25               80         240      150 
    

    If they had selected 6, you'd need to find .6 of the range of colors between each value.

    Red               0            255,0,0        0,240,120
    Dark Green        10           0,128,0        80,240,60
    
    Palette Code     Hue        Sat      Luminence
    0                0          240      120
    10               80         240      60
    -------------------------------------------------
    6                48         240      84
    
    0->80      = +80 * 60%   = +48    So 0+48   = 48
    240->240   =   0 * 60%   = 0      So 240+0  = 240
    120->60    = -60 * 60%   = -36    So 120-36 = 84
    
    0 讨论(0)
  • 2021-01-15 15:17

    I'm not sure if this was the case back then but in .NET 4.0 getting a color from a LinearGradientBrush can be done.

    private Color GetColor(double ratio)
    {
        if (ratio < 0) ratio = 0;
        else if (ratio > 1) ratio = 1;
    
        //Find gradient stops that surround the input value
        GradientStop gs0 = ColorScale.GradientStops.Where(n => n.Offset <= ratio).OrderBy(n => n.Offset).Last();
        GradientStop gs1 = ColorScale.GradientStops.Where(n => n.Offset >= ratio).OrderBy(n => n.Offset).First();
    
        float y = 0f;
        if (gs0.Offset != gs1.Offset)
        {
            y = (float)((ratio - gs0.Offset) / (gs1.Offset - gs0.Offset));
        }
    
        //Interpolate color channels
        Color cx = new Color();
        if (ColorScale.ColorInterpolationMode == ColorInterpolationMode.ScRgbLinearInterpolation)
        {
            float aVal = (gs1.Color.ScA - gs0.Color.ScA) * y + gs0.Color.ScA;
            float rVal = (gs1.Color.ScR - gs0.Color.ScR) * y + gs0.Color.ScR;
            float gVal = (gs1.Color.ScG - gs0.Color.ScG) * y + gs0.Color.ScG;
            float bVal = (gs1.Color.ScB - gs0.Color.ScB) * y + gs0.Color.ScB;
            cx = Color.FromScRgb(aVal, rVal, gVal, bVal);
        }
        else
        {
            byte aVal = (byte)((gs1.Color.A - gs0.Color.A) * y + gs0.Color.A);
            byte rVal = (byte)((gs1.Color.R - gs0.Color.R) * y + gs0.Color.R);
            byte gVal = (byte)((gs1.Color.G - gs0.Color.G) * y + gs0.Color.G);
            byte bVal = (byte)((gs1.Color.B - gs0.Color.B) * y + gs0.Color.B);
            cx = Color.FromArgb(aVal, rVal, gVal, bVal);
        }
        return cx;
    }
    

    This would work with a brush configured as follows (for example):

    var brush = new LinearGradientBrush();
    brush.StartPoint = new Point(0, 0);
    brush.EndPoint = new Point(1, 0);
    
    //Set brush colors
    brush.GradientStops.Add(new GradientStop() { Color = Color.FromRgb(102, 40, 0), Offset = 0 });
    brush.GradientStops.Add(new GradientStop() { Color = Color.FromRgb(254, 167, 80), Offset = 0.25 });
    brush.GradientStops.Add(new GradientStop() { Color = Color.FromRgb(0, 153, 51), Offset = 0.5 });
    brush.GradientStops.Add(new GradientStop() { Color = Color.FromRgb(232, 165, 255), Offset = 0.75 });
    brush.GradientStops.Add(new GradientStop() { Color = Color.FromRgb(66, 0, 89), Offset = 1 });
    

    Source: http://dotupdate.wordpress.com/2008/01/28/find-the-color-of-a-point-in-a-lineargradientbrush/

    0 讨论(0)
  • 2021-01-15 15:21

    Thanks for all the replies guys. It seems there is no way to get the "value" of a GradientBrush at a specified point. I hope this is corrected at some later version of the framework. So I guess the only option for now is to implement an interpolation algorithm as Mikko suggested.

    0 讨论(0)
提交回复
热议问题