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

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


当前回答

我有同样的问题,但我必须在PHP开发它。我用了@Garek的解决方案,我也用了这个答案: 转换十六进制颜色到RGB值在PHP转换十六进制颜色代码到RGB。

所以我要分享它。

我想在给定的背景颜色下使用这个函数,但不总是从“#”开始。

//So it can be used like this way:
$color = calculateColor('#804040');
echo $color;

//or even this way:
$color = calculateColor('D79C44');
echo '<br/>'.$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;
}

其他回答

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

您可以在任何色相背景上有任何色相文本,并确保它是易读的。我一直都这么做。在Javascript中有一个关于可读的彩色文本的公式- STW* 正如它在那个链接上所说的那样,这个公式是逆伽马调整计算的变化,尽管IMHO更易于管理。 该链接右侧的菜单及其相关页面使用随机生成的颜色作为文本和背景,始终清晰可辨。所以,是的,显然这是可以做到的,没有问题。

基于R版本的@Gacek的答案来获得亮度(你可以很容易地应用你自己的阈值)

# vectorized
luminance = function(col) c(c(.299, .587, .114) %*% col2rgb(col)/255)

用法:

luminance(c('black', 'white', '#236FAB', 'darkred', '#01F11F'))
# [1] 0.0000000 1.0000000 0.3730039 0.1629843 0.5698039

谢谢你写这篇文章。

对于可能感兴趣的人,这里有一个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;