根据背景颜色确定字体颜色

给定一个系统(例如一个网站),让用户自定义一些部分的背景颜色,但不是字体颜色(保持选项的数量最less),有没有一种方法来编程确定是否“光”或“黑暗“的字体颜色是必要的?

我确定有一些algorithm,但是我对颜色,光度等知之甚less,无法自行解决。

我遇到过类似的问题。 我不得不find一个很好的方法来select对比字体颜色来显示colorscales / heatmaps上的文本标签。 它必须是通用的方法,生成的颜色必须是“好看”,这意味着简单的生成互补色不是很好的解决scheme – 有时会产生难以观察和阅读的奇怪,非常强烈的颜色。

经过长时间的testing,并试图解决这个问题,我发现最好的解决办法是select“黑”颜色的白色字体,黑色字体为“明亮”的颜色。

这里是我在C#中使用的函数的一个例子:

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

这是testing了许多不同的颜色(彩虹,灰度,热,冰和许多其他),是唯一的“通用”的方法,我发现了。

编辑
a计算的公式改成了“感知亮度” – 它真的看起来更好! 已经在我的软件中实现了,看起来不错。

编辑2 @WebSeed提供了这个algorithm的一个很好的工作示例: http ://codepen.io/WebSeed/full/pvgqEq/

这是一个有用的答案。 谢谢!

我想分享一个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 ); } 

现在计算出如何使用该algorithm为菜单链接自动创buildhover颜色。 灯头变暗,而反之亦然。

谢谢@Gacek 。 这里有一个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); } 

而一个改进的(更短的)版本:

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

感谢这个职位。

对于任何可能感兴趣的人,下面是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; 

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

以防万一有人想要更短,也许更容易理解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; } 

注意:我删除了亮度值的反转(以使明亮的颜色具有更高的值,这对我来说似乎更自然,也是“默认”计算方法。

我从这里使用了与GaceK相同的常量,因为它们对我很好。

(您也可以使用以下签名将其实现为扩展方法 :

 public static Color ContrastColor(this Color iColor) 

然后可以通过foregroundColor = background.ContrastColor()调用它。)

丑陋的Python,如果你不想写它:)

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

iOS Swift 3.0(UIColor扩展):

 func isLight() -> Bool { let components = self.cgColor.components let firstComponent = ((components?[0])! * 299) let secondComponent = ((components?[1])! * 587) let thirdComponent = ((components?[2])! * 114) let brightness = (firstComponent + secondComponent + thirdComponent) / 1000 if brightness < 0.5 { return false } else { return true } } 

我的Swift实现了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) } 

如果您操纵色彩空间以获得视觉效果,那么使用HSL(色相,饱和度和亮度)通常比RGB更容易。 在RGB中移动颜色给自然赏心悦目的效果往往在概念上是相当困难的,而转换成HSL,在那里操作,然后再转换回来在概念上更直观,总是给出更好的结果。

维基百科有一个很好的介绍 HSL和密切相关的HSV。 而且网上有免费的代码来做转换(例如这里是一个JavaScript实现 )

你使用的是什么样的精确转换就是品味的问题,但是我个人认为,颠倒色调和明亮度组件肯定会产生一个很好的高对比度颜色作为第一个近似值,但是你可以很容易地find更微妙的效果。

你可以在任何色调背景上有任何色调文本,并确保它清晰可辨。 我一直这样做。 有一个在Javascript 颜色可读文本中的公式- STW *正如它在这个链接上所说的,公式是反伽马调整计算的一个变体,尽pipe更容易pipe理的恕我直言。 该链接右侧的菜单及其关联页面使用随机生成的文本和背景颜色,始终可读。 所以是的,显然可以做到,没有问题。

作为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 }