2012-03-10 61 views
12

我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)); 

我可以在特定位置的颜色? 例如: 位置0:红色 位置.5:黄色 位置.75:??

有第三方类可以这样做吗?

+0

我不认为这是WPF中的任何地方定义。我希望它取决于您的视频卡驱动程序的实现,缩放级别,用户颜色深度等。您可以使用Visual.PointToScreen方法,然后使用Graphics.CopyFromScreen来获取该像素。然后使用Bitmap.GetPixel检索颜色细节。 – akhisp 2012-03-10 21:19:24

回答

17

要在特定点获取颜色是理解问题中的渐变所​​必需的,并且这不是类GradientStopCollection的角色。这个类的概念不是要理解渐变,而应该是对渐变的简单支持。

重要的是你了解每个类的概念。

要获得一种颜色,您需要实例化一个类,该类使用渐变绘制并最终从绘画中获取颜色。

但我会给你一个更快的解决方案。您可以使用梯度算法生成单个点。这是如何做到这一点,使用线性梯度算法的实现:

public static class GradientStopCollectionExtensions 
{ 
    public static Color GetRelativeColor(this GradientStopCollection gsc, double offset) 
    { 
     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; 
    } 
} 

添加这个类在当前的环境(名字空间上下文)

为了让您的颜色在你插入像这样的任何地方:

var color = grsc.GetRelativeColor(.75); 
+1

约翰尼,你认为你可以过来http://stackoverflow.com/questions/16161931/how-to-read-the-color-from-an-offset-of-a-xaml-lineargradientbrush并发布此答案?我希望你能获得积分。 – 2013-04-23 22:49:17

+0

这正是我正在寻找的,有一个缺陷,如果偏移量完全等于渐变停止,它将完全忽略该渐变停止。因此我的编辑。 – Underdetermined 2016-06-03 16:34:48

+0

@未定:呃,哦,...以及编辑的位置是? – quetzalcoatl 2018-02-25 15:38:18

0
foreach (var gs in gsc) 
      { 
       if (gs.Offset == offset) return gs.Color; //new line added 
       if (gs.Offset < offset && gs.Offset > before.Offset) 
       { 
        before = gs; 
       } 

       if (gs.Offset > offset && gs.Offset < after.Offset) 
       { 
        after = gs; 
       } 
      } 
2

我试着通过乔尼皮亚齐写的方法。但它没有正常工作。
所以我下面写我自己的一个:

private static Color GetColorByOffset(GradientStopCollection collection, double offset) 
{ 
    GradientStop[] stops = collection.OrderBy(x => x.Offset).ToArray(); 
    if (offset <= 0) return stops[0].Color; 
    if (offset >= 1) return stops[stops.Length - 1].Color; 
    GradientStop left = stops[0], right = null; 
    foreach (GradientStop stop in stops) 
    { 
     if (stop.Offset >= offset) 
     { 
      right = stop; 
      break; 
     } 
     left = stop; 
    } 
    Debug.Assert(right != null); 
    offset = Math.Round((offset - left.Offset)/(right.Offset - left.Offset), 2); 
    byte a = (byte) ((right.Color.A - left.Color.A)*offset + left.Color.A); 
    byte r = (byte) ((right.Color.R - left.Color.R)*offset + left.Color.R); 
    byte g = (byte) ((right.Color.G - left.Color.G)*offset + left.Color.G); 
    byte b = (byte) ((right.Color.B - left.Color.B)*offset + left.Color.B); 
    return Color.FromArgb(a, r, g, b); 
} 

我希望它为你的作品!

我在下面的xaml代码中使用了这个方法来显示指定的数字作为热图位置。

<LinearGradientBrush x:Key="CountBrush" StartPoint="0 0" EndPoint="1 0"> 
    <GradientStop Offset="0.00" Color="ForestGreen"/> 
    <GradientStop Offset="0.50" Color="Yellow"/> 
    <GradientStop Offset="1.00" Color="OrangeRed"/> 
</LinearGradientBrush> 
<local:Int32ToColorConverter x:Key="CountToColorConverter" Min="0" Max="200" LinearBrush="{StaticResource CountBrush}"/> 
+0

我喜欢使用break来避免不必要的迭代 – Wobbles 2017-01-03 11:42:02

+0

您可以通过删除可见迭代并使用诸如'GradientStop left = stops.Where(s => s.Offset <= offset).Last(); GradientStop right = stops.Where(s => s。Offset> offset).First();' – Wobbles 2017-01-14 20:34:09

+0

谢谢!它真的简化了我的代码。在这种情况下,我所有的''''''''''''''都不见了。但我想你应该用'FirstOrDefault'和'LastOrDefault'来代替'First'和'Last'。 – walterlv 2017-01-19 07:47:57