如何检查十六进制颜色是否为“太黑”?


111

我正在尝试评估颜色选择器选择的颜色的暗度,以查看它是否“过黑”,如果是,请将其设置为白色。我以为可以使用十六进制值的第一个字符来完成此操作。它正在工作,但是它也在切换某些合法的“浅色”颜色。

我有这样做的代码:

        if (lightcolor.substring(0,3) == "#00"|| lightcolor.substring(0,3) == "#010"){
            lightcolor="#FFFFFF";
            color=lightcolor;
        }

十六进制数学中必须有一种更有效的方法来知道一种颜色已经超出了一定的黑暗度?就像如果lightcolor +“某些十六进制值” <=“某些十六进制值”,那么将其设置为白色。

我添加了tinyColor,可能对此有用,但是我不确定。


1
您是否尝试过启动拾色器并检查值?我注意到当R,G和B都在70以下时,它会变黑。这可能不是正确的方法,但这是一种。
里克·柯伊伯斯

1
因为您已经在使用tinyColor,所以将颜色转换为HSL,然后看一下L分量。1 =白色,0 =黑色
Andreas

4
@Andreas HSL的亮度没有考虑到人类的感知。L值0.5对不同的色调会有不同的感知亮度。
Alnitak

1
@Alnitak你是对的,但对TO的描述并非如此。因此,任何低于3/8的值都可能足以达到他的目的。
安德里亚斯(Andreas)2012年

1
@Andreas取决于-如果您在我的回答中查看ITU的亮度值,您会发现蓝色仅被感知为绿色的1/10。
Alnitak

Answers:


226

您必须分别提取三个RGB分量,然后使用标准公式将生成的RGB值转换为它们的感知亮度。

假设有六个字符的颜色:

var c = c.substring(1);      // strip #
var rgb = parseInt(c, 16);   // convert rrggbb to decimal
var r = (rgb >> 16) & 0xff;  // extract red
var g = (rgb >>  8) & 0xff;  // extract green
var b = (rgb >>  0) & 0xff;  // extract blue

var luma = 0.2126 * r + 0.7152 * g + 0.0722 * b; // per ITU-R BT.709

if (luma < 40) {
    // pick a different colour
}

编辑

自2014年5月tinycolorgetBrightness(),尽管使用CCIR601加权因子而不是上述ITU-R加权因子,但现在具有功能。

编辑

最终的亮度值范围是0..255,其中0是最暗的,而255是最亮的。大于128的值被视为tinycolor。(从@ pau.moreno和@Alnitak的评论中无耻地复制)


11
一段时间以来,还没有在javascript中看到过一些不错的操作。很酷的东西。en.wikipedia.org/wiki/Rec._709#Luma_coefficients
jbabey

2
代码不错,但是经过测试后,我建议var luma =(r + g + b)/ 3; if(luma <128){//会更有用。}
特里·林

2
@TerryLin为什么?给出的系数是标准的 ITU值允许的事实,绿色的感觉比红(然后蓝色)更明亮。
Alnitak

1
结果luma值范围为0..255,其中0最暗,最亮255(三个系数之和为1)。
pau.moreno,2015年

1
@gabssnake仅自2014年5月起,isDark()阈值硬编码为128
Alnitak

21

TinyColor库(你已经提到它)提供了用于检查和操纵的色彩,其中几个功能:

  • getBrightness

    根据Web内容可访问性指南(1.0版)定义,返回从0到255的颜色的感知亮度。

    tinycolor("#fff").getBrightness(); // 255
  • isLight

    返回一个布尔值,指示颜色的感知亮度是否为浅色。

    tinycolor("#fff").isLight(); // true
    tinycolor("#000").isLight(); // false
  • isDark

    返回一个布尔值,指示颜色的感知亮度是否为暗。

    tinycolor("#fff").isDark(); // false
    tinycolor("#000").isDark(); // true
  • getLuminance

    根据Web内容可访问性指南(2.0版)的定义,从0-1返回颜色的感知亮度。

    tinycolor("#fff").getLuminance(); // 1

15

我找到了这个WooCommerce Wordpress PHP函数(wc_hex_is_light),然后转换为JavaScript。工作良好!

function wc_hex_is_light(color) {
    const hex = color.replace('#', '');
    const c_r = parseInt(hex.substr(0, 2), 16);
    const c_g = parseInt(hex.substr(2, 2), 16);
    const c_b = parseInt(hex.substr(4, 2), 16);
    const brightness = ((c_r * 299) + (c_g * 587) + (c_b * 114)) / 1000;
    return brightness > 155;
}

1
太酷了,谢谢!我用几种颜色进行了测试,所有颜色的检测都是正确的:)
David Dal Busco

colorIsDarkOrLight(color){var hex = color.replace(“#”,“”); var c_r,c_g,c_b,亮度=“”; 如果(hex.length == 3){c_r = parseInt(hex.substr(0,2),16); c_g = parseInt(hex.substr(1,2),16); c_b = parseInt(hex.substr(2,2),16); 亮度=(c_r * 299 + c_g * 587 + c_b * 114)/ 1000; } else {c_r = parseInt(hex.substr(0,2),16); c_g = parseInt(hex.substr(2,2),16); c_b = parseInt(hex.substr(4,2),16); }返回亮度> 155; },
Pedro Henrique

与十六进制的3个字符和6个字符一起使用
Pedro Henrique

6

您可以计算亮度

因此,亮度是表面会显得有多亮的指示。

因此,最好选择文本是白色还是黑色。

var getRGB = function(b){
    var a;
    if(b&&b.constructor==Array&&b.length==3)return b;
    if(a=/rgb\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*\)/.exec(b))return[parseInt(a[1]),parseInt(a[2]),parseInt(a[3])];
    if(a=/rgb\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*\)/.exec(b))return[parseFloat(a[1])*2.55,parseFloat(a[2])*2.55,parseFloat(a[3])*2.55];
    if(a=/#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/.exec(b))return[parseInt(a[1],16),parseInt(a[2],16),parseInt(a[3],
16)];
    if(a=/#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/.exec(b))return[parseInt(a[1]+a[1],16),parseInt(a[2]+a[2],16),parseInt(a[3]+a[3],16)];
    return (typeof (colors) != "undefined")?colors[jQuery.trim(b).toLowerCase()]:null
};

var luminance_get = function(color) {
    var rgb = getRGB(color);
    if (!rgb) return null;
        return 0.2126 * rgb[0] + 0.7152 * rgb[1] + 0.0722 * rgb[2];
}

上面的方法允许您以不同的格式传递颜色,但是算法基本上只在中luminance_get

使用它时,如果亮度大于180,则将颜色设置为黑色,否则将其设置为白色。


5

亮度和亮度之间存在重要区别。归根结底,亮度是对能量在某个区域中传播的度量,它完全忽略了我们的感知系统如何感知该能量。另一方面,亮度是衡量我们如何感知能量并考虑亮度和我们的感知系统之间关系的一种量度。(作为一个混淆点,有一个称为相对亮度的术语,它似乎与亮度术语同义。它使我兴奋不已)。

准确地说,您正在寻找其他人建议的“亮度”或“值”或“相对亮度”。您可以通过几种不同的方式(例如人类!)来计算此值。http://en.wikipedia.org/wiki/HSL_and_HSV#Lightness

  1. 取R,G和B的最大值。
  2. 取R,G和B中最大值和最小值的平均值。
  3. 取三者的平均值。
  4. 使用其他一些建议的加权平均值。

AFAIK只有Wikipedia页面上描述的亮度计算是基于感知的模型。
Alnitak

2
指出物理光能与感知亮度之间的区别是很好的,但是我认为您的事情错综复杂。您链接到的Wikipedia文章的这一节有第四个要点,指出“在感知上更相关的替代方法是使用亮度Y'作为亮度尺寸”(强调我的意思),然后继续给出Alnitak的公式和罗宾的答案。换句话说,您遗漏并推荐使用的方法最适合人类的感知。
约翰Y

@JohnY是的,这就是我要说的-他只剩下一个实际上与他的回答其余部分匹配的人。
Alnitak

是的,事实证明我是这里唯一的困惑者。我对此表示同意:)我只是想说明要点,即能量和感知之间存在差异。我将相应地更新我的答案。
大卫·阮

4

十六进制工作,例如#fefefe

function isTooDark(hexcolor){
    var r = parseInt(hexcolor.substr(1,2),16);
    var g = parseInt(hexcolor.substr(3,2),16);
    var b = parseInt(hexcolor.substr(4,2),16);
    var yiq = ((r*299)+(g*587)+(b*114))/1000;
    // Return new color if to dark, else return the original
    return (yiq < 40) ? '#2980b9' : hexcolor;
}

您可以将其更改为退货truefalse更改

return (yiq < 40) ? '#2980b9' : hexcolor;

return (yiq < 40);

@Vivek是因为您需要使用完整的十六进制值(#000000和
#ffffff

2

一种可能的解决方案是将颜色从RGB转换为HSB。HSB代表色相,饱和度和亮度(也称为HSV,其中V代表值)。然后,您只需检查一个参数:亮度。


1

我知道这次对话已经有几年历史了,但仍然很有意义。我想补充一点,我的团队在Java(SWT)中也遇到了同样的问题,并且发现这更加准确:

private Color getFontColor(RGB bgColor) {
    Color COLOR_BLACK = new Color(Display.getDefault(), 0, 0, 0);
    Color COLOR_WHITE = new Color(Display.getDefault(), 255, 255, 255);

    double luminance = Math.sqrt(0.241 
       * Math.pow(bgColor.red, 2) + 0.691 * Math.pow(bgColor.green, 2) +  0.068 
       * Math.pow(bgColor.blue, 2));
    if (luminance >= 130) {
        return COLOR_BLACK;
    } else {
        return COLOR_WHITE;
    }
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.