2008-09-18 11 views
40

Dado un color de fuente de cualquier matiz por el sistema o el usuario, me gustaría un algoritmo simple que pueda usar para encontrar variantes más claras o más oscuras del color seleccionado. Similar a los efectos utilizados en Windows Live Messenger para diseñar la interfaz de usuario.¿Cómo puedo determinar la variante de color más oscura o más clara de un color dado?

El idioma es C# con .net 3.5.

Respondiendo al comentario: El formato de color es (Alfa) RGB. Con valores como bytes o flotantes.

Marcado respuesta: Por el contexto de mi uso (algunos efectos de IU simples), la respuesta que estoy marcando como aceptada es en realidad la más simple para este contexto. Sin embargo, también he renunciado a las respuestas más complejas y precisas. Cualquiera que realice operaciones de color más avanzadas y encuentre este hilo en el futuro definitivamente debería verificarlas. Gracias. :)

+0

¿Qué formato es el color? – UnkwnTech

+0

Solo para complementar, actualmente el espacio de colores de vanguardia para conversiones de color e interpolaciones (por ejemplo, para crear un mapa de colores perceptualmente uniforme, etc.) es CIELab. – heltonbiker

Respuesta

27

simplemente multiplique los valores RGB por la cantidad que desea modificar el nivel de. Si uno de los colores ya está en el valor máximo, no se puede hacer más brillante (usando las matemáticas HSV de todos modos)

Esto da exactamente el mismo resultado con mucha menos matemática que cambiar a HSV y luego modificar V. Esto da el mismo resultado que cambiar a HSL y luego modificar L, siempre y cuando no quiera comenzar a perder saturación.

+0

Sí, es posible hacer un color más brillante incluso si no puede hacer que un canal de color individual sea más brillante. Perder la saturación es un efecto secundario inevitable. Consulte http://stackoverflow.com/a/141943/5987 –

+0

Multiplicar los valores de rgb no hace nada si el color es negro – Dylanthepiguy

10

usted puede convertir sus colores en la HSL espacio de color, manipularlo allí y convertir de nuevo a su color en el espacio de elección (lo más probable es RGB)

encendedor colores tienen un mayor valor L, más oscuro a menor.

Aquí es el material relevante y todas las ecuaciones:

http://en.wikipedia.org/wiki/HSL_color_space

Otro método es interpolar simplemente su color con blanco o negro. Esto también desaturará el color un poco, pero es más barato de calcular.

+0

Estos cálculos tienden a ser baratos, pero una gran diferencia es que la codificación requerida es una carga para el programador. – heltonbiker

0

Suponiendo que obtiene el color como RGB, primero conviértalo al espacio de color HSV (matiz, saturación, valor). A continuación, aumente/disminuya el valor para producir un tono más claro/más oscuro del color. Luego vuelve a convertir a RGB.

20

HSV (Matiz/Saturación/Valor) también llamado HSL (Matiz/Saturación/Luminosidad) es solo una representación de color diferente.

Al usar esta representación es más fácil ajustar el brillo. Así que convierte de RGB a HSV, ilumina la 'V', luego vuelve a convertir a RGB.

A continuación se muestra un código C para convertir

void RGBToHSV(unsigned char cr, unsigned char cg, unsigned char cb,double *ph,double *ps,double *pv) 
{ 
double r,g,b; 
double max, min, delta; 

/* convert RGB to [0,1] */ 

r = (double)cr/255.0f; 
g = (double)cg/255.0f; 
b = (double)cb/255.0f; 

max = MAXx(r,(MAXx(g,b))); 
min = MINx(r,(MINx(g,b))); 

pv[0] = max; 

/* Calculate saturation */ 

if (max != 0.0) 
    ps[0] = (max-min)/max; 
else 
    ps[0] = 0.0; 

if (ps[0] == 0.0) 
{ 
    ph[0] = 0.0f; //UNDEFINED; 
    return; 
} 
/* chromatic case: Saturation is not 0, so determine hue */ 
delta = max-min; 

if (r==max) 
{ 
    ph[0] = (g-b)/delta; 
} 
else if (g==max) 
{ 
    ph[0] = 2.0 + (b-r)/delta; 
} 
else if (b==max) 
{ 
    ph[0] = 4.0 + (r-g)/delta; 
} 
ph[0] = ph[0] * 60.0; 
if (ph[0] < 0.0) 
    ph[0] += 360.0; 
} 

void HSVToRGB(double h,double s,double v,unsigned char *pr,unsigned char *pg,unsigned char *pb) 
{ 
int i; 
double f, p, q, t; 
double r,g,b; 

if(s == 0) 
{ 
    // achromatic (grey) 
    r = g = b = v; 
} 
else 
{ 
    h /= 60;   // sector 0 to 5 
    i = (int)floor(h); 
    f = h - i;   // factorial part of h 
    p = v * (1 - s); 
    q = v * (1 - s * f); 
    t = v * (1 - s * (1 - f)); 
    switch(i) 
    { 
    case 0: 
     r = v; 
     g = t; 
     b = p; 
    break; 
    case 1: 
     r = q; 
     g = v; 
     b = p; 
    break; 
    case 2: 
     r = p; 
     g = v; 
     b = t; 
    break; 
    case 3: 
     r = p; 
     g = q; 
     b = v; 
    break; 
    case 4: 
     r = t; 
     g = p; 
     b = v; 
    break; 
    default:  // case 5: 
     r = v; 
     g = p; 
     b = q; 
    break; 
    } 
} 
r*=255; 
g*=255; 
b*=255; 

pr[0]=(unsigned char)r; 
pg[0]=(unsigned char)g; 
pb[0]=(unsigned char)b; 
} 
+6

[HSV y HSL son cosas diferentes] (http://en.wikipedia.org/wiki/HSL_and_HSV). HSV es ** no ** también llamado HSL. –

+0

Pero HSV a veces se llama HSB (brillo). Que todavía es diferente a HSL, como dice @romkyns. –

+0

@KPexEA escribiste "Así que convierte de RGB a HSV, ilumina la 'V' y luego vuelve a convertirla a RGB." . ¿Cómo hago * el brillo de la parte 'V'' Necesito generar' n' tonos del mismo color. Las sombras deben ser cada vez más brillantes. – Geek

0

Si sus colores son en formato RGB (o, presumiblemente, CMYK), se puede utilizar el método bastante crudo de aumentar el valor de cada componente del color. Por ejemplo, en los colores HTML se representan tres números hexadecimales de dos dígitos. # ff0000 le dará un rojo brillante, que luego se puede atenuar aumentando los valores de los componentes G y B en la misma cantidad, como # ff5555 (da un rojo más claro). Presumiblemente para los colores Hue, Saturation y Lightness (HSL), puedes simplemente elevar el componente L, pero no puedo decirlo con certeza; Estoy menos familiarizado con este espacio de color.

Como digo, este método es bastante crudo. De mis recuerdos de Live Messenger, parece que estás tratando de hacer degradados, que se pueden aplicar muy fácilmente en Windows Presentation Foundation (WPF, parte de .NET 3.0). WPF admite muchos tipos diferentes de pincel de degradado, incluidos degradados lineales y radiales.

Puedo recomendar encarecidamente el libro de Adam Nathan Windows Presentation Foundation Unleashed como una introducción buena y completa a WPF.

HTH

+0

# ff5555 no da un rojo más claro, da un rojo desvanecido. Menos saturado Esto produce más luz, pero es más de un rosa que de un rojo más brillante. – clahey

+0

De hecho, uno puede usar un degradado, pero debe proporcionar colores para cada parada de gradiente. – Nidonocu

3

Si está utilizando colores RGB Me transformar este parametros de color para HSL (matiz, saturación, luminosidad), modificar el parámetro ligereza y luego transformar de nuevo a RGB. Busque en Google y encontrará una gran cantidad de muestras de código sobre cómo hacer estas transformaciones de representación de color (RGB a HSL y viceversa).

Esto es lo que me encontré con rapidez: http://bytes.com/forum/thread250450.html

0

Cualquier variación en el color se realiza mejor en HSL/HSV.

Una buena prueba es interpolar entre dos valores equivalentes en el espacio RGB y el espacio HSL. La rampa en el espacio HSL parece una progresión natural. En el espacio RGB, por lo general, parece bastante antinatural. HSL asigna a nuestra percepción del espacio de color visual mucho mejor que RGB.

4

Supongo que está utilizando RGB con valores de bytes (0 a 255), ya que es muy común en todas partes.

Para obtener más brillo, promedie los valores RGB con el RGB de blanco. O bien, para tener cierto control sobre la cantidad de brillo, mezcle en ellos en cierta proporción. Vamos f puede variar de 0,0 a 1,0, entonces:

Rnew = (1-f)*R + f*255 
Gnew = (1-f)*G + f*255 
Bnew = (1-f)*B + f*255 

Para más oscuro, utilice el RGB de negro - que, al ser todos los ceros, hace que la matemática más fácil.

Olvidé detalles como convertir el resultado en bytes, lo que probablemente desee hacer.

0

La idea de convertir a HSV u otro espacio de color parece buena, y puede ser necesaria para un trabajo de color preciso, pero para fines ordinarios el error de trabajar en RGB puede no ser suficiente. Además, puede ser una molestia lidiar con casos límites: RGB es un espacio en forma de cubo, mientras que HSV no lo es. Si trabaja con valores de bytes, puede tener asignaciones de muchos a uno y uno a muchos entre los espacios. Esto puede o no ser un problema dependiendo de la aplicación. YMMV

14

Rich Newman discusses HSL color con respecto a .NET System.Drawing.Color en su blog e incluso provides an HSLColor class que hace todo el trabajo por usted. Convierta su System.Drawing.Color en un HSLColor, agregue/reste valores contra la luminosidad, y conviértalo nuevamente a System.Drawing.Color para usar en su aplicación.

9

He utilizado el ControlPaint.Dark() y .Light() en System.Windows.Forms.

+3

brillante. ¿Por qué no es parte del espacio de nombres "Colores"? – itsho

+0

Agradable. Tenga en cuenta que se espera que el valor 'percOfLightLight' (segundo argumento para el método, y que realmente es su nombre) sea un flotante en el rango de 0 a 1. Se aceptan otros valores, pero el comportamiento no será el que desee. Código de ejemplo para obtener un color más claro: 'Color lighterColor = ControlPaint.Light (originalColor, 1.0f);' – Jinlye

0

Este website indica que puede usar la clase ControlPaint dentro del espacio de nombres BCL C# System.Windows.Forms.

44

En XNA there is the Color.Lerp static method que hace esto como la diferencia entre dos colores.

Lerp es una operación matemática entre dos flotadores que cambia el valor del primero por una relación de la diferencia entre ellos.

Aquí es un método de extensión de hacerlo a un float:

public static float Lerp(this float start, float end, float amount) 
{ 
    float difference = end - start; 
    float adjusted = difference * amount; 
    return start + adjusted; 
} 

Así que una simple operación de lerp entre dos colores utilizando RGB sería:

public static Color Lerp(this Color colour, Color to, float amount) 
{ 
    // start colours as lerp-able floats 
    float sr = colour.R, sg = colour.G, sb = colour.B; 

    // end colours as lerp-able floats 
    float er = to.R, eg = to.G, eb = to.B; 

    // lerp the colours to get the difference 
    byte r = (byte) sr.Lerp(er, amount), 
     g = (byte) sg.Lerp(eg, amount), 
     b = (byte) sb.Lerp(eb, amount); 

    // return the new colour 
    return Color.FromArgb(r, g, b); 
} 

Un ejemplo de aplicación de este habría algo como:

// make red 50% lighter: 
Color.Red.Lerp(Color.White, 0.5f); 

// make red 75% darker: 
Color.Red.Lerp(Color.Black, 0.75f); 

// make white 10% bluer: 
Color.White.Lerp(Color.Blue, 0.1f); 
+0

+1 gran respuesta thx. ¿Te vuelve loco tener que escribir Color en lugar de color en las librerías de .NET? :) –

+9

@ScottSilvi Ya estoy acostumbrado - no es tan malo en C# compilado, pero he pasado años tratando de averiguar qué hay de malo con código HTML/CSS/JS porque he deletreado centro o color correctamente : S – Keith

+0

la sintaxis del ejemplo me confundió pero ahora lo tengo ... solo tengo que reorganizarlo Supongo que – ycomp

Cuestiones relacionadas