给定背景颜色,如何获得使其在该背景颜色上可读的前景色?

Posted

技术标签:

【中文标题】给定背景颜色,如何获得使其在该背景颜色上可读的前景色?【英文标题】:Given a background color, how to get a foreground color that makes it readable on that background color? 【发布时间】:2011-03-08 04:08:54 【问题描述】:

给定背景色,如何获得使其在该背景色上可读的前景色?

我的意思是在程序中自动计算前景色。

或者简化问题,如果前景色从白/黑中选择,在程序中如何选择?

【问题讨论】:

重复:***.com/questions/946544/… 相关但也重复:***.com/questions/2241447/…***.com/questions/3942878/… 【参考方案1】:

根据上面的答案,我想出了一个 C# 实现,您可能希望根据您的要求调整 alpha 的逻辑。

public static class ColorExtension

    public static Color GetReadableColor(this Color color) => color.GetLuminance() > 140 || color.A != 255 ? Color.Black : Color.White;
    public static double GetLuminance(this Color color) => (0.2126 * color.R) + (0.7151 * color.G) + (0.0721 * color.B);

【讨论】:

【参考方案2】:

PyQt5 版本 Michael Zuschlag 的回答:

import sys
from PyQt5.QtGui import QColor
class MostReadableColor():
    def getLuminance(self, color):
    """ get color luminance.
    
    Convert color RGB values to gamma adjusted normalized rgb values
    then combine them using sRGB constants (rounded to 4 places).
    """
        r, g, b, a = QColor(color).getRgb()
        l = ((r/255)**2.2)*0.2126 + ((g/255)**2.2)*0.7151 + \
            ((b/255)**2.2)*0.0721
        return(l)

    def getContrastRation(self, color1, color2):
        l1 = self.getLuminance(color1)
        l2 = self.getLuminance(color2)
        cr = (l1 + .05)/(l2+.05) if l1 > l2 else (l2+.05)/(l1 + .05)
        return(cr)
     
    def getMostReadable(self, color):
        cr = []
        for c in QColor.colorNames():
            if c == 'transparent':
                continue
            cr.append([self.getContrastRation(color, c), c])
        sorted_cr = sorted(cr, reverse=True)  
        return(sorted_cr[0][1])    
    
def main():
    if len(sys.argv) != 2:
        print("usage: MostReadableColor color_name (ex: 'red')")
    else:   
        mrc = MostReadableColor()
        best_contrast_color = mrc.getMostReadable(sys.argv[1])
        print(f"best_contrast_color")
    
if __name__ == "__main__":
    main()

【讨论】:

【参考方案3】:

Pascal / Delphi 版本:

var
  red,green,blue : Integer;
  luminance : double;

// convert hexa-decimal values to RGB
red := (_BackgroundColor) and $FF;
green := (_BackgroundColor shr 8) and $FF;
blue := (_BackgroundColor shr 16) and $FF;

luminance := (0.2126 * red) + (0.7152 * green) + (0.0722 * blue);

if luminance < 140 then
  Result := TColors.White
else
  Result := TColors.Black;

【讨论】:

【参考方案4】:

如果这仍然对某人有用,这是基于上述答案的 Dart 实现

Color getInverseBW(Color color) 
    double luminance = (0.2126 * color.red + 0.7152 * color.green + 0.0722 * color.blue);
    return (luminance < 140) ? Color(0xffffffff) : Color(0xff000000);

【讨论】:

【参考方案5】:

这是我在 Java 和 javascript 中都做过的一个。它松散地基于this javascript 中的一个。我从here 中获取了亮度公式。我眼中的阈值甜蜜点约为 140。

Java 版本:

public class Color 

    private float CalculateLuminance(ArrayList<Integer> rgb)
        return (float) (0.2126*rgb.get(0) + 0.7152*rgb.get(1) + 0.0722*rgb.get(2));
    

    private ArrayList<Integer> HexToRBG(String colorStr) 
        ArrayList<Integer> rbg = new ArrayList<Integer>();
        rbg.add(Integer.valueOf( colorStr.substring( 1, 3 ), 16 ));
        rbg.add(Integer.valueOf( colorStr.substring( 3, 5 ), 16 ));
        rbg.add(Integer.valueOf( colorStr.substring( 5, 7 ), 16 ));
        return rbg;
    
    public String getInverseBW(String hex_color) 
        float luminance = this.CalculateLuminance(this.HexToRBG(hex_color));
        String inverse = (luminance < 140) ? "#fff" : "#000";
        return inverse;
    


Javascript 版本:

在 javascript 中,前端的东西也是一样的。 RGB转换取自here:

hex_to_rgb: function(hex) 
        var result = /^#?([a-f\d]2)([a-f\d]2)([a-f\d]2)$/i.exec(hex);
        return result ?  
                r: parseInt(result[1], 16),
                g: parseInt(result[2], 16),
                b: parseInt(result[3], 16) 
         : null;
,
hex_inverse_bw: function(hex) 
        rgb = this.hex_to_rgb(hex);
        luminance = (0.2126*rgb["r"] + 0.7152*rgb["g"] + 0.0722*rgb["b"]);
        return (luminance < 140) ? "#ffffff": "#000000";

【讨论】:

谢谢,正是我需要的。其他问题中的另一种解决方案和这个问题的公认答案,在计算光度之前对 rgb 进行归一化对我不起作用,但这是完美的。 感谢您提供即用型代码!欣赏!【参考方案6】:

这里有一些实际的 (ruby) 代码可以真正完成提升:

rgbval = "8A23C0".hex
r = rgbval >> 16
g = (rgbval & 65280) >> 8
b = rgbval & 255
brightness = r*0.299 + g*0.587 + b*0.114
return (brightness > 160) ? "#000" : "#fff"

【讨论】:

【参考方案7】:

最安全的选择是遵守万维网联盟 (W3C) 的 Web 内容可访问性指南 2.0,该指南指定了亮度 contrast ratio of 4.5:1 for regular text (12 pt or smaller), and 3.0:1 for large text。对比度定义为:

[Y(b) + 0.05] / [Y(d) + 0.05]

其中 Y(b) 是较亮颜色的亮度(亮度),Y(d) 是较暗颜色的亮度。

您首先将每种颜色的 RGB 值转换为经过伽马调整的归一化 rgb 值,从而计算亮度 Y:

r = (R/255)^2.2 b = (B/255)^2.2 g = (G/255)^2.2

然后使用 sRGB 常量组合它们(四舍五入):

Y = 0.2126*r + 0.7151*g + 0.0721*b

这使白色的 Y 为 1,黑色的 Y 为 0,因此可能的最大对比度为 (1.05/ 0.05) = 21(在舍入误差内)。

或者let JuicyStudio do the math给你。

此计算假设在相对昏暗的房间(或用户可以根据需要调暗的房间)中的标准性能监视器。这足以满足家庭或办公室使用,但我不知道它是否适合移动应用程序或其他户外使用的设备。

【讨论】:

【参考方案8】:

您可以计算反色,但您会冒着在颜色空间的“中间”降低对比度的风险。

【讨论】:

【参考方案9】: 计算亮度(参见HSL) 如果亮度低于 50%,请使用白色。否则,请使用黑色。

使用颜色作为前景色很困难,因为您必须考虑对比度和色盲。

【讨论】:

我看了一些rgb_to_hsl的sn-p代码,亮度是用MAX(r, g, b)/255计算的,好像还不够选择。 太棒了。 d3.rgb().hsl 很简单

以上是关于给定背景颜色,如何获得使其在该背景颜色上可读的前景色?的主要内容,如果未能解决你的问题,请参考以下文章

Qt5:如何改变表格中一行的背景颜色,使其在排序时自动移动?

文本颜色计算以获得最大的可读性 PHP/JS/CSS

计算不同于背景和前景的颜色

使文本在任意背景图像上可读

EditText背景基线颜色变化基于其在android中的焦点

如何删除 UIImage 背景颜色并使其透明?