2012-03-10 91 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