给定一个系统(例如一个网站),允许用户自定义某些部分的背景色,但不允许自定义字体颜色(以保持选项的数量最小化),是否有一种方法可以通过编程来确定“浅色”或“深色”字体颜色是必要的?

我相信有一些算法,但我对颜色、光度等了解不够,无法自己找出答案。


当前回答

基于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)

然后,您可以轻松地将其称为via foregroundColor = backgroundColor.ContrastColor()。

其他回答

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

Swift 4示例:

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

}

更新-发现0.6是一个更好的查询测试平台

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

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

}

现在弄清楚如何使用算法来自动创建菜单链接的悬停颜色。浅标题的悬停颜色较深,反之亦然。

基于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)

然后,您可以轻松地将其称为via foregroundColor = backgroundColor.ContrastColor()。

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