Determine el color de fuente en función del color de fondo

Dado un sistema (un sitio web, por ejemplo) que permite al usuario personalizar el color de fondo para una sección pero no el color de la fuente (para mantener el número de opciones al mínimo), ¿hay alguna forma de determinar programáticamente si una “luz” o ” “oscuro”, ¿es necesario el color de la fuente?

Estoy seguro de que hay algún algoritmo, pero no sé lo suficiente sobre los colores, la luminosidad, etc. para resolverlo solo.

Me encontré con un problema similar. Tenía que encontrar un buen método para seleccionar el color de fuente contrastivo para mostrar tags de texto en escala de colores / mapas de calor. Tenía que ser un método universal y el color generado tenía que ser “atractivo”, lo que significa que la simple generación de colores complementarios no era una buena solución; a veces generaba colores extraños, muy intensos, difíciles de ver y leer.

Después de largas horas de pruebas e intentando resolver este problema, descubrí que la mejor solución es seleccionar una fuente blanca para los colores “oscuros” y una fuente negra para los colores “shinys”.

Aquí hay un ejemplo de función que estoy usando en C #:

Color ContrastColor(Color color) { int d = 0; // Counting the perceptive luminance - human eye favors green color... double luminance = ( 0.299 * color.R + 0.587 * color.G + 0.114 * color.B)/255; if (luminance > 0.5) d = 0; // bright colors - black font else d = 255; // dark colors - white font return Color.FromArgb(d, d, d); } 

Esto fue probado para muchas escalas de colores (arcoíris, escala de grises, calor, hielo y muchos otros) y es el único método “universal” que descubrí.

Editar
Cambió la fórmula de conteo de a “luminancia perceptiva” – ¡realmente se ve mejor! Ya lo implementé en mi software, se ve genial.

Editar 2 @WebSeed proporcionó un gran ejemplo de trabajo de este algoritmo: http://codepen.io/WebSeed/full/pvgqEq/

Gracias @Gacek . Aquí hay una versión para Android:

 @ColorInt public static int getContrastColor(@ColorInt int color) { // Counting the perceptive luminance - human eye favors green color... double a = 1 - (0.299 * Color.red(color) + 0.587 * Color.green(color) + 0.114 * Color.blue(color)) / 255; int d; if (a < 0.5) { d = 0; // bright colors - black font } else { d = 255; // dark colors - white font } return Color.rgb(d, d, d); } 

Y una versión mejorada (más corta):

 @ColorInt public static int getContrastColor(@ColorInt int color) { // Counting the perceptive luminance - human eye favors green color... double a = 1 - (0.299 * Color.red(color) + 0.587 * Color.green(color) + 0.114 * Color.blue(color)) / 255; return a < 0.5 ? Color.BLACK : Color.WHITE; } 

En caso de que a alguien le guste una versión más corta, tal vez más fácil de entender de la respuesta de GaceK :

 public Color ContrastColor(Color iColor) { // Calculate the perceptive luminance (aka luma) - human eye favors green color... double luma = ((0.299 * iColor.R) + (0.587 * iColor.G) + (0.114 * iColor.B)) / 255; // Return black for bright colors, white for dark colors return luma > 0.5 ? Color.Black : Color.White; } 

Nota: eliminé la inversión del valor de luma (para que los colores shinys tengan un valor más alto, lo que me parece más natural y también es el método de cálculo “predeterminado”).

Usé las mismas constantes que GaceK desde aquí ya que me funcionaron muy bien.

(También puede implementar esto como un Método de extensión usando la siguiente firma:

 public static Color ContrastColor(this Color iColor) 

Puede llamarlo a través de foregroundColor = background.ContrastColor() .

Mi aplicación Swift de la respuesta de Gacek:

 func contrastColor(color: UIColor) -> UIColor { var d = CGFloat(0) var r = CGFloat(0) var g = CGFloat(0) var b = CGFloat(0) var a = CGFloat(0) color.getRed(&r, green: &g, blue: &b, alpha: &a) // Counting the perceptive luminance - human eye favors green color... let luminance = 1 - ((0.299 * r) + (0.587 * g) + (0.114 * b)) if luminance < 0.5 { d = CGFloat(0) // bright colors - black font } else { d = CGFloat(1) // dark colors - white font } return UIColor( red: d, green: d, blue: d, alpha: a) } 

Javascript [ES2015]

 const hexToLuma = (colour) => { const hex = colour.replace(/#/, ''); const r = parseInt(hex.substr(0, 2), 16); const g = parseInt(hex.substr(2, 2), 16); const b = parseInt(hex.substr(4, 2), 16); return [ 0.299 * r, 0.587 * g, 0.114 * b ].reduce((a, b) => a + b) / 255; }; 

Esta es una respuesta tan útil. ¡Gracias por eso!

Me gustaría compartir una versión SCSS:

 @function is-color-light( $color ) { // Get the components of the specified color $red: red( $color ); $green: green( $color ); $blue: blue( $color ); // Compute the perceptive luminance, keeping // in mind that the human eye favors green. $l: 1 - ( 0.299 * $red + 0.587 * $green + 0.114 * $blue ) / 255; @return ( $l < 0.5 ); } 

Ahora descubriendo cómo usar el algoritmo para crear automáticamente los colores de página para los enlaces de menú. Los encabezados de luz obtienen un vuelo más oscuro y viceversa.

Gracias por esta publicación

Para quien pueda estar interesado, aquí hay un ejemplo de esa función en Delphi:

 function GetContrastColor(ABGColor: TColor): TColor; var ADouble: Double; R, G, B: Byte; begin if ABGColor < = 0 then begin Result := clWhite; Exit; // *** EXIT RIGHT HERE *** end; if ABGColor = clWhite then begin Result := clBlack; Exit; // *** EXIT RIGHT HERE *** end; // Get RGB from Color R := GetRValue(ABGColor); G := GetGValue(ABGColor); B := GetBValue(ABGColor); // Counting the perceptive luminance - human eye favors green color... ADouble := 1 - (0.299 * R + 0.587 * G + 0.114 * B) / 255; if (ADouble < 0.5) then Result := clBlack; // bright colors - black font else Result := clWhite; // dark colors - white font end; 

Ugly Python si no tienes ganas de escribirlo 🙂

 ''' Input a string without hash sign of RGB hex digits to compute complementary contrasting color such as for fonts ''' def contrasting_text_color(hex_str): (r, g, b) = (hex_str[:2], hex_str[2:4], hex_str[4:]) return '000' if 1 - (int(r, 16) * 0.299 + int(g, 16) * 0.587 + int(b, 16) * 0.114) / 255 < 0.5 else 'fff' 

Tuve el mismo problema, pero tuve que desarrollarlo en PHP . Usé la solución de @ Garek y también usé esta respuesta: Convertir el color hexadecimal a valores RGB en PHP para convertir el código de color HEX a RGB.

Así que lo estoy compartiendo.

Quería usar esta función con el color HEX de fondo dado, pero no siempre comenzando desde ‘#’.

 //So it can be used like this way: $color = calculateColor('#804040'); echo $color; //or even this way: $color = calculateColor('D79C44'); echo '
'.$color; function calculateColor($bgColor){ //ensure that the color code will not have # in the beginning $bgColor = str_replace('#','',$bgColor); //now just add it $hex = '#'.$bgColor; list($r, $g, $b) = sscanf($hex, "#%02x%02x%02x"); $color = 1 - ( 0.299 * $r + 0.587 * $g + 0.114 * $b)/255; if ($color < 0.5) $color = '#000000'; // bright colors - black font else $color = '#ffffff'; // dark colors - white font return $color; }

iOS Swift 3.0 (extensión UIColor):

 func isLight() -> Bool { if let components = self.cgColor.components, let firstComponentValue = components[0], let secondComponentValue = components[1], let thirdComponentValue = components[2] { let firstComponent = (firstComponentValue * 299) let secondComponent = (secondComponentValue * 587) let thirdComponent = (thirdComponentValue * 114) let brightness = (firstComponent + secondComponent + thirdComponent) / 1000 if brightness < 0.5 { return false }else{ return true } } print("Unable to grab components and determine brightness") return nil } 

Si está manipulando espacios de color para efectos visuales, generalmente es más fácil trabajar en HSL (Matiz, Saturación y Luminosidad) que RGB. Mover colores en RGB para dar efectos naturalmente agradables tiende a ser conceptualmente difícil, mientras que convertirlos en HSL, manipularlos allí, luego convertirlos de nuevo es más intuitivo en concepto e invariablemente da mejores resultados.

Wikipedia tiene una buena introducción a HSL y al HSV estrechamente relacionado. Y hay un código libre en la red para hacer la conversión (por ejemplo, aquí hay una implementación de JavaScript )

Qué transformación precisa utilizas es una cuestión de gusto, pero personalmente habría pensado que invertir los componentes Hue y Lightness generaría un buen color de alto contraste como primera aproximación, pero puedes elegir efectos más sutiles.

Puede tener cualquier texto de matiz en cualquier fondo de matiz y asegurarse de que sea legible. Lo hago todo el tiempo. Hay una fórmula para esto en Javascript en texto legible en color – STW * Como dice en ese enlace, la fórmula es una variación en el cálculo de ajuste de gamma inversa, aunque un poco más manejable en mi humilde opinión. Los menús en el lado derecho de ese enlace y sus páginas asociadas usan colores generados aleatoriamente para texto y fondo, siempre legibles. Entonces sí, claramente se puede hacer, no hay problema.

Como extensión de Kotlin / Android:

 fun Int.getContrastColor(): Int { // Counting the perceptive luminance - human eye favors green color... val a = 1 - (0.299 * Color.red(this) + 0.587 * Color.green(this) + 0.114 * Color.blue(this)) / 255 return if (a < 0.5) Color.BLACK else Color.WHITE } 

Una variación de Android que captura el alfa también.

(gracias @ thomas-vos)

 /** * Returns a colour best suited to contrast with the input colour. * * @param colour * @return */ @ColorInt public static int contrastingColour(@ColorInt int colour) { // XXX https://stackoverflow.com/questions/1855884/determine-font-color-based-on-background-color // Counting the perceptive luminance - human eye favors green color... double a = 1 - (0.299 * Color.red(colour) + 0.587 * Color.green(colour) + 0.114 * Color.blue(colour)) / 255; int alpha = Color.alpha(colour); int d = 0; // bright colours - black font; if (a >= 0.5) { d = 255; // dark colours - white font } return Color.argb(alpha, d, d, d); } 

Una implementación para objective-c

 + (UIColor*) getContrastColor:(UIColor*) color { CGFloat red, green, blue, alpha; [color getRed:&red green:&green blue:&blue alpha:&alpha]; double a = ( 0.299 * red + 0.587 * green + 0.114 * blue); return (a > 0.5) ? [[UIColor alloc]initWithRed:0 green:0 blue:0 alpha:1] : [[UIColor alloc]initWithRed:255 green:255 blue:255 alpha:1]; } 

Swift 4 Ejemplo:

 extension UIColor { var isLight: Bool { let components = cgColor.components let firstComponent = ((components?[0]) ?? 0) * 299 let secondComponent = ((components?[1]) ?? 0) * 587 let thirdComponent = ((components?[2]) ?? 0) * 114 let brightness = (firstComponent + secondComponent + thirdComponent) / 1000 return !(brightness < 0.6) } } 

ACTUALIZACIÓN : se encontró que 0.6 era un banco de pruebas mejor para la consulta