2012-03-10 25 views
12

tengo GradientStopCollection:Obtenga un color de ubicación específica en gradiente de

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

¿Puedo obtener el color en un lugar específico? Por ejemplo: Ubicación 0: Rojo Ubicación .5: Amarillo Ubicación .75: ??

Hay una tercera clase que puede hacerlo?

+0

No creo que esto se defina en WPF. Esperaría que dependa de la implementación del controlador de su tarjeta de video, el nivel de zoom, la profundidad de color de los usuarios, etc. Puede usar el método Visual.PointToScreen y luego Graphics.CopyFromScreen para tomar ese píxel. Luego use Bitmap.GetPixel para recuperar los detalles de color. – akhisp

Respuesta

17

Para obtener un color en un punto específico es necesario comprender el gradiente en cuestión, y este no es el rol de la clase GradientStopCollection. El concepto de esta clase no es comprender un gradiente, sino que debe ser una simple colección de soporte para un degradado.

Es importante que comprenda el concepto de cada clase.

Para obtener un color, necesita crear una instancia de una clase que represente un degradado utilizando el degradado para pintar y, finalmente, obtener su color de la pintura.

pero le daré una solución más rápida. Puede usar un algoritmo de gradiente para generar un solo punto. Esta es una implementación de cómo hacer esto utilizando un algoritmo de gradiente lineal:

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

Añadir esta clase en su contexto actual (contexto espacio de nombres)

Para obtener su color en cualquier lugar de insertar algo como esto:

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

Johnny, ¿crees que podrías venir a http://stackoverflow.com/questions/16161931/how-to-read-the-color-from-an-offset-of-a-xaml-lineargradientbrush y publicar esta respuesta ? Me gustaría que obtengas los puntos. –

+0

Esto es exactamente lo que estaba buscando, con un error que si el desplazamiento es exactamente igual a un degradado, ignorará por completo ese gradiente. De ahí mi edición. – Underdetermined

+0

@Underdetermined: uh, oh, ... ¿y dónde está esa edición? – 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

he intentado el método escrito por Jonny Piazzi. Pero no funcionó correctamente.
así que escribir mi propio uno a continuación:

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

espero que funcione para usted!

He utilizado este método en mi código xaml a continuación para mostrar un número específico como posición de mapa de calor.

<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

Me gusta el uso del break para evitar iteraciones innecesarias – Wobbles

+0

Puede simplificar el código eliminando las iteraciones visibles y usando algo como 'GradientStop left = stops.Where (s => s.Offset <= offset). Last(); GradientStop right = stops.Where (s => s.Offset> offset) .Primero(); ' – Wobbles

+0

¡Gracias! Realmente simplificó mi código. En este caso, todos mis "' {'" y "'} 'desaparecieron. Pero supongo que deberías usar 'FirstOrDefault' y' LastOrDefault' con '??' en lugar de 'First' y' Last'. – walterlv

Cuestiones relacionadas