如何根据字体颜色选择背景颜色以达到适当的对比度。

18

我对颜色组合不是很了解,所以我想出了这个算法,根据试错的方法选择基于字体颜色的背景颜色:

public class BackgroundFromForegroundColorConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if (!(value is Color))
            return value;
        Color color = (Color)value;
        if (color.R + color.G + color.B > 550)
            return new SolidColorBrush(Colors.Gray);
        else if (color.R + color.G + color.B > 400)
            return new SolidColorBrush(Colors.LightGray);
        else
            return new SolidColorBrush(Colors.White);
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}
我在谷歌上搜索了一下,但没有找到关于如何通过不同的方式计算背景颜色以达到良好对比效果的正式信息。
因此我的问题是: 是否有更"正式"的方法来选择一个良好的背景颜色以获得良好的对比度? 或者,如果希望文本无论其字体颜色如何都尽可能易读,您会如何选择背景颜色?
快速更新
更多的背景: 我只是试图显示一些文本的预览(例如 "The quick brown fox jumps over the lazy dog"),其中用户选择字体颜色、字体重量、字体等。然而,我对于能够做什么感兴趣,无论它是超级简单,还是更复杂。
最终编辑
我决定采用H.B.提出的方法: 它似乎可以很好地处理我尝试的所有颜色,而我的先前算法中前景与背景的对比度不总是正确的。我很想知道是否有公式可以给出给定前景色的"最佳"背景色,但对于我所需的黑/白结果非常好。这是我的当前代码形式:
public class BackgroundFromForegroundColorConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if (!(value is Color))
            return value;
        Color color = (Color)value;
        double Y = 0.2126 * color.ScR + 0.7152 * color.ScG + 0.0722 * color.ScB;
        return Y > 0.4 ? Brushes.Black : Brushes.White;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotSupportedException();
    }
}

顺便提一下,单向转换器中的 ConvertBack 应该抛出 NotSupportedException 异常,因为它将没有实现。 - H.B.
4个回答

22

有一些计算颜色亮度的方法,基于这些方法,你可以选择黑色或白色背景来提高可读性。例如,参见luma

Y = 0.2126 R + 0.7152 G + 0.0722 B

我认为如果使用规范化的输入值(0.0 - 1.0),阈值将为0.5,但我已经有一段时间没有使用过了...

编辑:示例转换实现草图:

public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
    var c = (Color)value;
    var l = 0.2126 * c.ScR + 0.7152 * c.ScG + 0.0722 * c.ScB;

    return l < 0.5 ? Brushes.White : Brushes.Black;
}

阈值实际上可能会有一定的依赖于显示器和个人偏好,我本人更喜欢较低的阈值,这样黑色背景的占比就更大了。


选择黑色或白色似乎可以起作用;现在使用您发布的亮度公式,Y将在0到255之间变化;您有任何关于我应该在哪里划定底线的想法吗? - user610650
我认为我理解了你对0.5的意思:0.5*255=127.5;如果大于则使用黑色背景,否则使用白色。通过一系列随机颜色的测试,它似乎非常有效! - user610650
1
这是一种看待它的方式(你也可以将所有通道除以255.0,或者结果);它确实有效,这就是我之前使用它的原因(两年前)。 - H.B.
您可能还想测试一些阈值以确定哪个最好,我建议使用较低的一个(例如0.25),因为计算机显示器上的颜色往往会比较亮。 - H.B.

3

对于任何给定颜色 c,最对比(不同)的颜色是通过以下方式获得:

new Color(c.R > .5 ? 0 : 1, c.G > .5 ? 0 : 1, c.B > .5 ? 0 : 1)

或者如果您需要0-255范围

new Color(c.R > 127 ? 0 : 255, c.G > 127 ? 0 : 255, c.B > 127 ? 0 : 255)

在给定的背景下,文本的可见性总是最好的,但不一定总是美观。如果您不想被疯狂的颜色所干扰,您可以使用由接受的答案建议的黑色/白色。


3

我认为这不仅是一个“正式”的问题,更多的是设计问题。因此,这取决于你自己的决定。你能不能展示一些接近你想要实现的例子?我最近也在解决类似的问题(创建在线画廊,根据画廊中照片的颜色动态更改其背景),我觉得我正在很好地解决它,我的建议是,无论你选择什么作为背景,都在背景中创建一层黑色或白色,取决于前景色(相反的亮度),这样你就在某种程度上“限制”了背景,例如,背景可以设置为黑色,而你的文本也是黑色的,但是有一个白色的图层在背景上方,使文本可读。图层的不透明度留给你,尝试并找到最佳值。你可以在值转换器中实现整个过程,而这个背景+“图层”组合只是一个颜色值。


1
在我工作的一个项目中,我们决定使用一种公式将颜色按红绿蓝值分离,并从255中减去红绿蓝以得到近乎完美的对比色。
然而... 灰色是那些不适用这个公式的颜色之一。您可以简单地检查颜色是否为灰色,然后再进行减法。 在颜色光谱的两端还有一些其他颜色,您可能需要引导它们以获得可读的对比颜色。

我认为那样做不太好看,例如红色在青色上,或者绿色在洋红色上看起来不是很舒服,就我个人而言。但其他情况下增加对比度仍然不错,除非颜色接近灰色当然除外。 - Can Poyrazoğlu
@can poyrazoğlu - 作者询问了一种好的方法来找到光谱另一端的对比色,这个方法确实可以给出完全相反的颜色。使用这种方法,红色的对比色实际上非常好。绿色-黄色;我忘记确切的颜色是什么了。 - Security Hound

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接