【问题标题】:Programmatically choose high-contrast colors以编程方式选择高对比度的颜色
【发布时间】:2010-09-29 07:09:12
【问题描述】:

这应该是一个简单的问题,但我一直没能找到让它发挥作用的方法。

基本上,我有一个愚蠢的本地主机页面,我在我的网络开发中使用它。当我在我们的开发服务器和我的本地版本的 C# 代码(通过主机文件从 dev url 重定向)之间浏览时,我知道有时会忘记“dev.foo.com”指向的内容 - 本地或服务器。

所以我创建了一个页面,它将作为我的默认网页的默认页面在本地运行,这样我就可以轻松地从服务器识别我的本地主机。

这个页面会随机做很多事情(包括为 D&D 生成角色的起始统计数据),包括设置随机背景颜色。为此,我生成 3 个 0 到 255 之间的随机数,并将它们设置为 CSS 中正文背景颜色的 RGB 值。

鉴于 3 个整数 R、G 和 B,我如何确定 R2、G2 和 B2 以使第二种颜色与第一种颜色具有高对比度?我喜欢让页面有随机的背景颜色(它让我不习惯登陆页面的外观),但我也希望能够阅读文本。

【问题讨论】:

    标签: random colors rgb


    【解决方案1】:

    您需要不同的亮度才能使文本可读,因为色觉本身的分辨率太低。

    因此,作为一种算法,我建议如下:

    • 选择一个随机的背景颜色。

    • 然后决定是浅色还是深色。例如,您可以检查三基色的平均值是否大于或等于 128。

    • 对于浅色使用黑色文本,对于深白色文本。

    更新:这是我在玩 split_evenly 的 Rust crate plotters 示例时制作的示例图像。它显示Palette99中的颜色:

    【讨论】:

    • 这是一个相当简单的解决方案,而且(现在)运行良好。我会尝试一段时间,因为它总是可读的,如果有点简单。
    【解决方案2】:

    “对比度”是一个加载词。如果您只关心能够阅读文本,那么一种简单的方法是在 HSL 等基于亮度的颜色空间中工作,并选择亮度差异很大的前景色和背景色。

    HSL 和 RGB 之间的转换是众所周知的——有关详细信息,请参阅 Wikipedia。

    如果您谈论的是实际的颜色对比度,它几乎没有那么简单(据我所知,有很多感知因素尚未简化为单一颜色空间),但我怀疑你不需要那种复杂程度。

    【讨论】:

    【解决方案3】:

    查看这个 PHP 解决方案:Andreas Gohr 的Calculating Color Contrast with PHP。当然,它可以移植到任何语言。

    他还对他的对比度分析器进行了很好的演示,您可以在其中找到一些可以使用的最低对比度。

    【讨论】:

    • 实际上,只有第 3 个函数处理颜色对比度,第 1 个和第 2 个函数正在计算一些随机指标
    【解决方案4】:

    您可以在Color 类上使用方法GetBrightness()。它返回一个从 0.0(黑色亮度)到 1.0(白色)的浮点值。 一个简单的解决方案是:

    var color1 = new Color.FromArgb(r1, g1, b1);
    var brightness = color1.GetBrightness();
    
    var color2 = brightness > 0.5 ? Color.Black : Color.White;
    

    【讨论】:

      【解决方案5】:

      我在 Palm OS 应用程序中做了类似的事情。这就是我想出的。它不会为您提供“高对比度”颜色,但它会为您提供与文本颜色足够不同的背景颜色,以使其易于阅读:

        // Black background is a special case.  It's fairly likely to occur and 
        // the default color shift we do isn't very noticeable with very dark colors.
        if (backColor.r < 0x20 && backColor.g < 0x20 && backColor.b < 0x20)
        {
            textColor.r = backColor.r + 0x20;
            textColor.g = backColor.g + 0x20;
            textColor.b = backColor.b + 0x20;
        }
        else
        {
            textColor.r = backColor.r + ((backColor.r < 128) ? 0x10 : -0x10);
            textColor.g = backColor.g + ((backColor.g < 128) ? 0x10 : -0x10);
            textColor.b = backColor.b + ((backColor.b < 128) ? 0x10 : -0x10);
        }
      

      您可能不需要将黑色作为特殊情况用于您的目的 - Palm 的颜色处理有点时髦(16 位颜色)。

      【讨论】:

        【解决方案6】:

        这些答案或多或少建议根据颜色是亮还是暗来使用两种或三种颜色中的一种。

        我使用了一些不同的方法,在我的情况下它工作得很好。这是实现。

         int color = your_color;
         contrastColor = Color.rgb(255-(color >> 16)&0xFF, 255-(color >> 8)&0xFF, 255- color&0xFF);
        

        简单而美妙。

        【讨论】:

        • 嗨,Mayank 刚刚发送了一封电子邮件,内容涉及潜在的咨询工作,如果您有兴趣!
        • 我认为这是相同的方法:Color.rgb(255 - Color.red(color), 255 - Color.green(color), 255 - Color.blue(color)
        【解决方案7】:

        如果你翻转所有位,你会得到“相反”的颜色,这将是一个很好的对比。

        我相信它是 C# 中的 ~ 运算符:

        R2 = ~R1;
        G2 = ~G1;
        B2 = ~B1;
        

        【讨论】:

        • 这不适用于颜色直方图“中间”附近的颜色,例如 #808080。
        • 是的……但相反的颜色有一个额外的好处,当它们放在一起时看起来很悦目。
        • 蒂姆,你可以继续把它说得更强烈一些——它根本不起作用。 :-)
        • 您可以为那些不能正常工作的“中间”情况添加一些“if”语句。你也可以有类似“if(light) return Black; else return White;”之类的东西。但这显然会减少输出颜色的数量。
        • 也许我应该指出这是一个 ASP 网站,但您的评论仍然很有帮助。我唯一的问题是中心的那些“边缘”案例,以及随之而来的问题是“在切换到黑白之前离中心有多近?”
        【解决方案8】:

        感谢@starblue

        这是我使用的C# 代码

         public static string GetContrastBlackOrWhiteColorAsHtmlColorCode(Color c)
                {
                    System.Drawing.Color color = System.Drawing.ColorTranslator.FromHtml("transparent");
        
                    try
                    {
                        if (c.R >= 128 && c.G >= 128 && c.B >= 128)
                        {
                            return System.Drawing.ColorTranslator.ToHtml(Color.Black);
                        }
                        else
                        {
                            return System.Drawing.ColorTranslator.ToHtml(Color.White);
                        }
                    }
                    catch (Exception)
                    {
                    }
        
                    return System.Drawing.ColorTranslator.ToHtml(color);
                }
        

        【讨论】:

        • 这并不是 StarBlue 所说的——他建议平均 R、G 和 B 值。您正在设置最小阈值。即使在 #FF7FFF#7FFFFF#FFFF7F,您的代码也会使用白色
        【解决方案9】:

        为了获得最佳对比度,请使用此代码

        function lumdiff($R1,$G1,$B1,$R2,$G2,$B2){
        
            $L1 = 0.2126 * pow($R1/255, 2.2) +
                  0.7152 * pow($G1/255, 2.2) +
                  0.0722 * pow($B1/255, 2.2);
        
            $L2 = 0.2126 * pow($R2/255, 2.2) +
                  0.7152 * pow($G2/255, 2.2) +
                  0.0722 * pow($B2/255, 2.2);
        
            if($L1 > $L2){
                return ($L1+0.05) / ($L2+0.05);
            }else{
                return ($L2+0.05) / ($L1+0.05);
            }
        }
        
        function get_the_contrast($c1, $c2) {
            return (lumdiff(hexdec(substr($c1,0,2)),
                hexdec(substr($c1,2,2)),hexdec(substr($c1,4,2)),
                hexdec(substr($c2,0,2)),hexdec(substr($c2,2,2)),
                hexdec(substr($c2,4,2))));
        }
        

        上面的方法( AVG(red,green,blue) > 128 )不太好。

        【讨论】:

          【解决方案10】:
          private Color GetContrastingColor(Color color)
          {
              int r = color.R > 0 ? 256 - color.R : 255;
              int g = color.G > 0 ? 256 - color.G : 255;
              int b = color.B > 0 ? 256 - color.B : 255;
              return System.Drawing.Color.FromArgb(r, g, b);
          }
          

          【讨论】:

          • 也许对您的解决方案的简短评论会对 OP 有所帮助。
          • 这不适用于值在 128 左右的中档颜色,最好使用this
          猜你喜欢
          • 1970-01-01
          • 2011-10-19
          • 2012-04-01
          • 1970-01-01
          • 2017-12-30
          • 2013-06-12
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多