Search code examples
c#.netxamllineargradientbrush

Get color in specific location on gradient


I have the following GradientStopCollection:

GradientStopCollection grsc = new GradientStopCollection(3);
grsc.Add(new GradientStop(Colors.Red, 0));
grsc.Add(new GradientStop(Colors.Yellow, .5));
grsc.Add(new GradientStop(Colors.Green, 1));

Can I get the color at a specific "location"? For example:

  • Location 0: Red
  • Location .5: Yellow
  • Location .75: Yellow<~>Green

Is there an API in WPF / some third party library that could do that?


Solution

  • To get a color at a specific point is necessary to understand the gradient in question, and this is not the role of class GradientStopCollection. The concept of this class is not to understand a gradient, but should be a simple collection of support to a gradient.

    Is important that you understand the concept of each class.

    To get a color, you need to instantiate a class that represents a gradient using the gradient to paint and finally get their color from the painting.

    but I'll give you a quicker solution. You can use a gradient algorithm to generate a single point. This is an implementation of how to do this using a linear gradient algorithm:

    public static class GradientStopCollectionExtensions
    {
        public static Color GetRelativeColor(this GradientStopCollection gsc, double offset)
        {
            var point = gsc.SingleOrDefault(f => f.Offset == offset);
            if (point != null) return point.Color;
    
            GradientStop before = gsc.Where(w => w.Offset == gsc.Min(m => m.Offset)).First();
            GradientStop after = gsc.Where(w => w.Offset == gsc.Max(m => m.Offset)).First();
    
            foreach (var gs in gsc)
            {
                if (gs.Offset < offset && gs.Offset > before.Offset)
                {
                    before = gs;
                }
                if (gs.Offset > offset && gs.Offset < after.Offset)
                {
                    after = gs;
                }
            }
    
            var color = new Color();
    
            color.ScA = (float)((offset - before.Offset) * (after.Color.ScA - before.Color.ScA) / (after.Offset - before.Offset) + before.Color.ScA);
            color.ScR = (float)((offset - before.Offset) * (after.Color.ScR - before.Color.ScR) / (after.Offset - before.Offset) + before.Color.ScR);
            color.ScG = (float)((offset - before.Offset) * (after.Color.ScG - before.Color.ScG) / (after.Offset - before.Offset) + before.Color.ScG);
            color.ScB = (float)((offset - before.Offset) * (after.Color.ScB - before.Color.ScB) / (after.Offset - before.Offset) + before.Color.ScB);
    
            return color;
        }
    }
    

    PS: This algorithm assumes there are no stops with the same offset. If there are multiple stops with the same offset a InvalidOperationException will be thrown.

    Add this class in your current context (namespace context)

    To get your color in any place you insert something like this:

    var color = grsc.GetRelativeColor(.75);