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

我试图评估颜色选择器选择的颜色的黑暗程度,看看它是否“太黑”,如果是这样,设置为白色。我想我可以使用十六进制值的第一个字符来完成这个任务。它的工作,但它改变了一些合法的“光”颜色。

我有以下密码:

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

必须有一个更有效的方法与十六进制数学知道一个颜色已经超越了一定程度的黑暗?如果 lightcolor + “一些十六进制值”<=“一些十六进制值”然后设置为 white

我已经增加了 tinyColor,这可能是有用的,但我不确定。

67960 次浏览

您必须分别提取三个 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月以来,tinycolor现在有了 getBrightness()功能,尽管使用的是 CCIR601加权因子而不是上面的 ITU-R 加权因子。

剪辑

得到的 luma 值范围为0。. 255,其中0是最暗的,255是最亮的。大于128的值被 tinycolor认为是轻的。(厚颜无耻地抄袭@pau 的评论。Moreno 和@Alnitak)

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

你可以计算 亮度:

因此,亮度是表面出现亮度的指示器。

所以选择文本是白色还是黑色是很好的。

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,否则为白色。

亮度和亮度之间有一个重要的区别。亮度,在一天结束的时候,是衡量有多少能量通过一个特定的区域,完全忽略了我们的感知系统如何感知这些能量。另一方面,亮度是衡量我们如何感知能量,并考虑到亮度和我们的感知系统之间的关系。(令人困惑的是,有一个术语叫做相对亮度,它似乎与亮度术语同义。它把我绊倒了)。

准确地说,你正在寻找“亮度”或“值”或“相对亮度”,正如其他人所建议的那样。你可以用几种不同的方法来计算(比如人类!)http://en.wikipedia.org/wiki/HSL_and_HSV#Lightness

  1. 取 R,G 和 B 的最大值。
  2. 取 R、 G 和 B 的最大值和最小值的平均值。
  3. 以这三者的平均数为例。
  4. 按照其他人的建议使用一些加权平均数。

TinyColor库(你已经提到过了)提供了几个检查和操作颜色的函数,其中包括:

  • 获得亮度

    返回颜色的感知亮度,从0到255,由 网页内容无障碍指南(1.0版)定义。

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

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

    tinycolor("#fff").isLight(); // true
    tinycolor("#000").isLight(); // false
    
  • 很黑暗

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

    tinycolor("#fff").isDark(); // false
    tinycolor("#000").isDark(); // true
    
  • 获取亮度

    返回颜色的感知亮度,从 网页内容无障碍指南(2.0版)定义的0-1开始。

    tinycolor("#fff").getLuminance(); // 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;
}
}

这个工作与巫术,例如 # 埃菲

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);

我找到了这个 WooCommerce Wordpress PHP 函数(十六进制是光)并转换成了 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;
}

@ Sliffcak,谢谢你的评论... 使用 substring,因为 substr是不被推荐的:

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

我把“ Alnitak”和“ SergioCabral”的答案合并在下面。我还实现了一个适用于标准和短表单的十六进制值解析器。

const hexToRgb = (hex) =>
(value =>
value.length === 3
? value.split('').map(c => parseInt(c.repeat(2), 16))
: value.match(/.{1,2}/g).map(v => parseInt(v, 16)))
(hex.replace('#', ''));


// Luma - https://stackoverflow.com/a/12043228/1762224
const isHexTooDark = (hexColor) =>
(([r, g, b]) =>
(0.2126 * r + 0.7152 * g + 0.0722 * b) < 40)
(hexToRgb(hexColor));


// Brightness - https://stackoverflow.com/a/51567564/1762224
const isHexTooLight = (hexColor) =>
(([r, g, b]) =>
(((r * 299) + (g * 587) + (b * 114)) / 1000) > 155)
(hexToRgb(hexColor));


console.log(isHexTooDark('#222'));  // true
console.log(isHexTooLight('#DDD')); // true