2012-03-10 11 views
12

mam GradientStopCollection:uzyskać kolor w określonym miejscu na gradientowe

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

mogę uzyskać kolor w określonym miejscu? Na przykład: Lokalizacja 0: Czerwony Lokalizacja .5: Żółty Lokalizacja .75: ??

Czy istnieje klasa osób trzecich, która może to zrobić?

+0

Nie sądzę, że jest to zdefiniowane w dowolnym miejscu w WPF. Spodziewam się, że zależy to od implementacji sterownika karty wideo, poziomu powiększenia, głębi kolorów użytkownika itd. Możesz użyć metody Visual.PointToScreen, a następnie Graphics.CopyFromScreen, aby pobrać ten piksel. Następnie użyj Bitmap.GetPixel, aby pobrać szczegóły kolorów. – akhisp

Odpowiedz

17

Uzyskanie koloru w określonym punkcie jest niezbędne do zrozumienia danego gradientu, a nie jest to rola klasy GradientStopCollection. Pojęcie tej klasy nie polega na zrozumieniu gradientu, ale powinno być prostym zbiorem wsparcia dla gradientu.

Ważne jest, aby zrozumieć pojęcie każdej klasy.

Aby uzyskać kolor, należy utworzyć instancję klasy reprezentującej gradient za pomocą gradientu do malowania iw końcu uzyskać ich kolor z obrazu.

, ale dam ci szybsze rozwiązanie. Możesz użyć algorytmu gradientowego do wygenerowania pojedynczego punktu. Jest to realizacja, jak to zrobić stosując liniowy algorytm gradient:

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; 
    } 
} 

Dodaj tę klasę w bieżącym kontekście (kontekstowe przestrzeni nazw)

Aby uzyskać kolor w dowolnym miejscu możesz wstawić coś takiego:

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

Johnny, myślisz, że możesz przyjść do http://stackoverflow.com/questions/16161931/how-to-read-the-color-from-anset-of-a-xaml-lineargradientbrush i zamieścić tę odpowiedź ? Chciałbym, żebyś zdobył punkty. –

+0

To jest dokładnie to, czego szukałem, z jedną wadą, że jeśli przesunięcie jest dokładnie równe gradientowi, zignoruje to całkowicie zatrzymanie gradientu. Stąd moja edycja. – Underdetermined

+0

@Underdetermined: uh, oh, ... i gdzie ta edycja jest? – quetzalcoatl

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

próbowałem metody napisany przez Jonny Piazzi. Ale to nie działało poprawnie.
więc napisać własny jeden poniżej:

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

Mam nadzieję, że pracuje dla Ciebie!

Użyłem tej metody w moim kodzie xaml poniżej, aby wyświetlić określoną liczbę jako położenie mapy ciepła.

<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

Uwielbiam używać break, aby uniknąć niepotrzebnych iteracji. – Wobbles

+0

Możesz uprościć kod, usuwając widoczne iteracje i używając czegoś podobnego do 'GradientStop left = stops.Where (s => s.Offset <= przesunięcie) .Last(); GradientStop right = stops.Where (s => s.Offset> offset) .First(); ' – Wobbles

+0

Dzięki! Naprawdę uprościł mój kod. W tym przypadku wszystkie moje "' {"" i "'} '" zniknęły. Ale domyślam się, że powinieneś użyć 'FirstOrDefault' i' LastOrDefault' z '??' zamiast 'First' i' Last'. – walterlv

Powiązane problemy