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

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


当前回答

我本想对@MichaelChirico的回答发表评论,但我没有足够的声誉。这里有一个在R中返回颜色的例子:

get_text_colour <- function(
    background_colour,
    light_text_colour = 'white',
    dark_text_colour = 'black',
    threshold = 0.5
) {

    background_luminance <- c( 
        c( .299, .587, .114 ) %*% col2rgb( background_colour ) / 255
    )

    return(
        ifelse(
            background_luminance < threshold,
            light_text_colour,
            dark_text_colour
        )
    )
}
> get_text_colour( background_colour = 'blue' )
[1] "white"

> get_text_colour( background_colour = c( 'blue', 'yellow', 'pink' ) )
[1] "white" "black" "black"

> get_text_colour( background_colour = c('black', 'white', '#236FAB', 'darkred', '#01F11F') )
[1] "white" "black" "white" "white" "black"

其他回答

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

一个Android版本,捕捉alpha以及。

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

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

我本想对@MichaelChirico的回答发表评论,但我没有足够的声誉。这里有一个在R中返回颜色的例子:

get_text_colour <- function(
    background_colour,
    light_text_colour = 'white',
    dark_text_colour = 'black',
    threshold = 0.5
) {

    background_luminance <- c( 
        c( .299, .587, .114 ) %*% col2rgb( background_colour ) / 255
    )

    return(
        ifelse(
            background_luminance < threshold,
            light_text_colour,
            dark_text_colour
        )
    )
}
> get_text_colour( background_colour = 'blue' )
[1] "white"

> get_text_colour( background_colour = c( 'blue', 'yellow', 'pink' ) )
[1] "white" "black" "black"

> get_text_colour( background_colour = c('black', 'white', '#236FAB', 'darkred', '#01F11F') )
[1] "white" "black" "white" "white" "black"