Determinar a cor da fonte com base na cor de fundo

Dado um sistema (um site, por exemplo) que permite ao usuário personalizar a cor de fundo para alguma seção, mas não a cor da fonte (para manter o número de opções no mínimo), existe uma maneira de determinar programaticamente se uma “luz” ou ” escuro “cor da fonte é necessária?

Tenho certeza de que há algum algoritmo, mas não sei o suficiente sobre colors, luminosidade, etc para descobrir sozinho.

Eu encontrei um problema semelhante. Eu tive que encontrar um bom método de seleção de cor de fonte contrastante para exibir labels de texto em colorscales / heatmaps. Tinha que ser um método universal e a cor gerada tinha que ser “bonita”, o que significa que a simples geração de cor complementar não era uma boa solução – às vezes gerava colors estranhas e muito intensas que eram difíceis de ver e ler.

Depois de longas horas de testes e tentando resolver esse problema, descobri que a melhor solução é selecionar a fonte branca para colors “escuras” e a fonte preta para colors “shinys”.

Aqui está um exemplo de function que estou usando em 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); } 

Isso foi testado para várias escalas de colors (arco-íris, tons de cinza, calor, gelo e muitas outras) e é o único método “universal” que descobri.

Editar
Mudou a fórmula de contar a para “luminosidade perceptiva” – realmente parece melhor! Já implementei no meu software, parece ótimo.

Edit 2 @WebSeed forneceu um excelente exemplo de funcionamento deste algoritmo: http://codepen.io/WebSeed/full/pvgqEq/

Obrigado @Gacek . Aqui está uma versão para o 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); } 

E uma versão melhorada (mais curta):

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

Apenas no caso de alguém gostar de uma versão mais curta, talvez mais fácil de entender da resposta do 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: Eu removi a inversão do valor de luma (para fazer colors shinys têm um valor mais alto, o que parece mais natural para mim e é também o método de cálculo ‘padrão’).

Eu usei as mesmas constantes que o GaceK daqui, pois elas funcionavam muito bem para mim.

(Você também pode implementar isso como um método de extensão usando a seguinte assinatura:

 public static Color ContrastColor(this Color iColor) 

Você pode chamá-lo via foregroundColor = background.ContrastColor() .)

Minha implementação Swift da resposta 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; }; 

Essa é uma resposta tão útil. Obrigado por isso!

Eu gostaria de compartilhar uma versão do 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 ); } 

Agora, descobrir como usar o algoritmo para criar colors de ajuda automática para links de menu. Os headers de luz ficam mais claros e vice-versa.

Obrigado por este post.

Para quem quer que esteja interessado, aqui está um exemplo dessa function no 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; 

Pitão feio se você não quiser escrevê-lo 🙂

 ''' 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' 

Eu tive o mesmo problema, mas tive que desenvolvê-lo em PHP . Eu usei a solução da @Garek e também usei esta resposta: Converta a cor hexadecimal em valores RGB em PHP para converter o código de cor HEX em RGB.

Então eu estou compartilhando.

Eu queria usar essa function com a cor HEX de fundo, mas nem sempre começando de ‘#’.

 //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 (extensão 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 } 

Se você está manipulando espaços de colors para efeitos visuais, geralmente é mais fácil trabalhar em HSL (matiz, saturação e luminosidade) do que RGB. Movendo colors em RGB para dar efeitos naturalmente agradáveis ​​tende a ser bastante difícil conceitualmente, enquanto convertendo em HSL, manipulando lá, então convertendo novamente fora é mais intuitivo em conceito e invariavelmente dá resultados mais bonitos.

A Wikipedia tem uma boa introdução ao HSL e ao HSV intimamente relacionado. E não há código livre em torno da rede para fazer a conversão (por exemplo, aqui é uma implementação de javascript )

A transformação precisa que você usa é uma questão de gosto, mas pessoalmente eu pensaria que reverter os componentes Matiz e Luminosidade certamente geraria uma boa cor de alto contraste como primeira aproximação, mas você pode facilmente obter efeitos mais sutis.

Você pode ter qualquer texto de matiz em qualquer plano de fundo de matiz e garantir que ele seja legível. Eu faço isso o tempo todo. Há uma fórmula para isso em Javascript em texto legível em colors – STW * Como diz o link, a fórmula é uma variação do cálculo de ajuste de gama inversa, embora IMHO um pouco mais gerenciável. Os menus no lado direito desse link e suas páginas associadas usam colors geradas aleatoriamente para texto e plano de fundo, sempre legíveis. Então sim, claramente isso pode ser feito, sem problemas.

Como extensão 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 } 

Uma variação do Android que captura o alfa também.

(obrigado @ 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); } 

Uma implementação 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 Exemplo:

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

ATUALIZAÇÃO - Descobriu que 0.6 foi um teste melhor para a consulta