Як перевірити, чи «шестигранний» колір занадто чорний?


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 = чорний
Андреас

4
@Andreas Легкість HSL не враховує людське сприйняття. Значення L 0,5 матиме різну сприйняту яскравість для різних відтінків.
Альнітак

1
@Alnitak Ви маєте рацію, але опис TO не так точно. Тож будь-яке значення нижче 3/8 могло бути досить темним для його призначення.
Андреас

1
@Андреа - це залежить - якщо ви подивитесь на значення освітленості МСЕ у моїй відповіді, ви побачите, що синій колір сприймається лише на 1/10 як яскравий, як зелений.
Альнітак

Відповіді:


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
}

EDIT

З травня 2014 року tinycolorтепер getBrightness()функціонує, хоча використовує вагові коефіцієнти CCIR601 замість МСЕ-R вище.

EDIT

Отриманий діапазон значень луми становить 0..255, де 0 - найтемніший, а 255 - найлегший. Значення більше 128 вважаються світлими tinycolor. (безсоромно скопійовано з коментарів @ pau.moreno та @Alnitak)


12
я не бачив хорошого маніпулювання бітом у JavaScript протягом певного часу. класні речі. en.wikipedia.org/wiki/Rec._709#Luma_coefficients
jbabey

2
Хороший код, але після тестування я пропоную var luma = (r + g + b) / 3; якщо (luma <128) {// стане кориснішим. }
Террі Лін

2
@TerryLin Чому? Наведені коефіцієнти - це стандартні значення МСЕ, які дозволяють сприймати те, що зелене сприймається яскравіше, ніж червоне (а потім синє).
Альнітак

1
Отриманий lumaдіапазон значень є 0..255, де 0найтемніший і 255найлегший (три коефіцієнти дорівнюють одному).
pau.moreno

1
@gabssnake лише з травня 2014 року, а isDark()поріг жорстко
зазначається

21

Бібліотека TinyColor (ви вже згадували про неї) пропонує кілька функцій для огляду та маніпулювання кольорами, серед них:


15

Я знайшов цю функцію PHP WooCommerce Wordpress ( 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
Супер класно, THX! Я перевірив його декількома кольорами, виявлення було правильним у всіх них :)
Девід Даль Буско,

colorIsDarkOrLight (колір) {var hex = color.replace ("#", ""); var c_r, c_g, c_b, яскравість = ""; if (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; },
Педро

Використовуйте з шестигранними 3 символами та 6
Педро

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. Візьмемо середнє значення max і min від R, G і B.
  3. Візьміть середнє значення всіх трьох.
  4. Використовуйте деякі середньозважені, як пропонують інші.

AFAIK лише розрахунок луми, описаний на сторінці Вікіпедії, є моделлю, що базується на сприйнятті.
Альнітак

2
Приємно вказати на різницю між фізичною енергією світла та сприйнятою яскравістю, але я думаю, у вас все досить змішано. У розділі статті, що пов’язана з Вікіпедією, до якої ви посилаєтесь, є четверта куля, в якій сказано: " Більш сприйнятною альтернативою є використання luma, Y ', як вимір легкості" (акцент міна), а потім переходимо до того, щоб дати формулу, представлену в статті Alnitak і відповіді Робіна. Іншими словами, метод, котрий ви пропустили та рекомендували, - той, який найкраще відповідає людському сприйняттю.
Джон Y

@JohnY так, саме це я намагався сказати - він залишився єдиним, який насправді відповідає решті його відповіді.
Альнітак

Так, виявляється, я єдиний тут плутався. Я з цим все в порядку :) Мені просто хотілося зрозуміти, що між енергією та сприйняттям є різна різниця. Відповідно оновлю відповідь.
Девід Нгуен

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

Ви можете змінити його для повернення trueабо falseшляхом зміни

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

до

return (yiq < 40);

@Vivek це тому, що вам потрібно використовувати повні шістнадцяткові значення (# 000000 та #ffffff)
TheCrazyProfessor

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;
    }
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.