Onaltılık rengin "çok siyah" olup olmadığı nasıl kontrol edilir?


111

Bir renk seçici tarafından seçilen bir rengin koyuluğunu "çok siyah" olup olmadığını görmek için değerlendirmeye ve öyleyse beyaza ayarlamaya çalışıyorum. Bunu başarmak için onaltılık değerin ilk karakterlerini kullanabileceğimi düşündüm. Çalışıyor, ancak yasal olarak bazı "açık" renkleri de değiştiriyor.

Bunu yapan kodum var:

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

Bir rengin belirli bir karanlık seviyesinin ötesine geçtiğini bilmenin onaltılı matematik ile daha verimli bir yolu olmalı mı? Örneğin açık renk + "bir onaltılık değer" <= "bir onaltılık değer" ise beyaza ayarlayın.

Bunun için yararlı olabilecek tinyColor ekledim, ancak kesin olarak bilmiyorum.


1
Bir renk seçiciyi kaldırmayı ve değerleri kontrol etmeyi denediniz mi? R, G ve B'nin tümü ~ 70'in altına düştüğünde hava kararıyor. Bu doğru yol olmayabilir, ama bu bir.
Rick Kuipers

1
Zaten tinyColor kullandığınız gibi, renk dönüşümü HSL ve bir göz L bileşeni. 1 = beyaz, 0 = siyah
Andreas

4
@Andreas HSL hafifliği insan algısını hesaba katmaz. 0.5'lik bir L değeri, farklı tonlar için farklı bir algılanan parlaklığa sahip olacaktır.
Alnitak

1
@Alnitak Haklısın ama TO'nun tanımı o kadar da değil. Yani 3 / 8'in altındaki herhangi bir değer, onun amacı için yeterince karanlık olabilirdi.
Andreas

1
@Andreas bu bağlıdır - Cevabımdaki ITU parlaklık değerlerine bakarsanız, mavinin yeşil kadar parlak olarak yalnızca 1/10 oranında algılandığını göreceksiniz.
Alnitak

Yanıtlar:


226

Üç RGB bileşenini ayrı ayrı çıkarmanız ve ardından elde edilen RGB değerlerini algılanan parlaklıklarına dönüştürmek için standart bir formül kullanmanız gerekir.

Altı karakterlik bir renk varsayarsak:

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
}

DÜZENLE

Mayıs 2014'ten bu yana , yukarıdaki ITU-R'ler yerine CCIR601 ağırlıklandırma faktörleri kullanılıyor olsa da, tinycolorartık bir getBrightness()işlevi var.

DÜZENLE

Ortaya çıkan luma değer aralığı, 0..255'tir; burada 0 en koyu ve 255 en açık renktir. 128'den büyük değerler, tarafından açık olarak kabul edilir tinycolor. (@ pau.moreno ve @Alnitak tarafından yorumlardan utanmadan kopyalandı)


12
bir süredir javascript'te bazı iyi bit manipülasyonları görmedim. güzel şeyler. en.wikipedia.org/wiki/Rec._709#Luma_coefficients
jbabey

2
İyi kod, ancak test ettikten sonra var luma = (r + g + b) / 3; if (luma <128) {// daha kullanışlı olacaktır. }
Terry Lin

2
@TerryLin Neden? Verilen katsayılar , yeşilin kırmızıdan (ve sonra maviden) daha parlak olarak algılanmasını sağlayan standart ITU değerleridir .
Alnitak

1
Elde edilen lumadeğer aralığı 0..255burada, 0koyu ve 255(bir üç katsayıları toplamı) hafif olan.
pau.moreno

1
@gabssnake sadece Mayıs 2014'ten beri ve isDark()eşik 128'de sabit kodlandı
Alnitak

21

TinyColor kütüphanesi (daha önce söz ettik) teftiş ve aralarında renkleri işlemek için çeşitli işlevler sunar:

  • getBrightness

    Web İçeriği Erişilebilirlik Yönergeleri (Sürüm 1.0) tarafından tanımlanan şekilde 0-255 arasında bir rengin algılanan parlaklığını döndürür .

    tinycolor("#fff").getBrightness(); // 255
  • ışık

    Rengin algılanan parlaklığının açık olup olmadığını gösteren bir boole değeri döndürür.

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

    Rengin algılanan parlaklığının karanlık olup olmadığını belirten bir boole döndürür.

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

    Web İçeriği Erişilebilirlik Yönergeleri (Sürüm 2.0) tarafından tanımlanan şekilde 0-1'den itibaren bir rengin algılanan parlaklığını döndürür .

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

15

Bu WooCommerce Wordpress PHP işlevini ( wc_hex_is_light ) buldum ve JavaScript'e dönüştürdüm. İyi çalışıyor!

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
Süper havalı, teşekkürler! Birkaç renkle test ettim, algılama hepsinde doğruydu :)
David Dal Busco

colorIsDarkOrLight (renk) {var hex = color.replace ("#", ""); var c_r, c_g, c_b, parlaklık = ""; eğer (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); parlaklık = (c_r * 299 + c_g * 587 + c_b * 114) / 1000; } başka {c_r = parseInt (hex.substr (0, 2), 16); c_g = parseInt (hex.substr (2, 2), 16); c_b = parseInt (hex.substr (4, 2), 16); } dönüş parlaklığı> 155; },
Pedro Henrique

Altıgen 3 karakter ve 6 ile kullanın
Pedro Henrique

6

Parlaklığı şu şekilde hesaplayabilirsiniz :

Dolayısıyla parlaklık, yüzeyin ne kadar parlak görüneceğinin bir göstergesidir.

Bu nedenle, metnin siyah mı yoksa beyaz mı olacağını seçmek harika.

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

Yukarıdaki yöntem, rengi farklı formatlarda geçirmenize izin verir, ancak algoritma temelde tamdır luminance_get.

Bunu kullandığımda, parlaklık 180beyazdan büyükse rengi siyaha ayarlıyordum .


5

Burada parlaklık ve parlaklık arasında önemli bir ayrım var. Günün sonunda parlaklık, belirli bir bölgeden ne kadar enerji geçtiğinin bir ölçüsüdür ve algısal sistemlerimizin bu enerjiyi nasıl algıladığını tamamen görmezden gelir. Öte yandan parlaklık, o enerjiyi nasıl algıladığımızın bir ölçüsüdür ve parlaklık ile algısal sistemimiz arasındaki ilişkiyi hesaba katar. (Bir kafa karışıklığı olarak, parlaklık terimleriyle eşanlamlı olarak kullanılıyor gibi görünen göreceli parlaklık denen bir terim var. Bu beni çok heyecanlandırdı).

Kesin olarak, diğerlerinin önerdiği gibi "parlaklık" veya "değer" veya "görece parlaklık" arıyorsunuz. Bunu birkaç farklı şekilde hesaplayabilirsiniz (insan olabilir!) Http://en.wikipedia.org/wiki/HSL_and_HSV#Lightness

  1. Maksimum R, G ve B'yi alın.
  2. R, G ve B'den maks ve min ortalamasını alın.
  3. Üçünün ortalamasını alın.
  4. Başkalarının burada önerdiği gibi, biraz ağırlıklı ortalamayı kullanın.

AFAIK yalnızca Wikipedia sayfasında açıklanan luma hesaplaması, algı temelli bir modeldir.
Alnitak

2
Fiziksel ışık enerjisi ile algılanan parlaklık arasındaki ayrıma işaret etmek güzel, ama bence bazı şeyleri biraz karıştırmışsınız. Wikipedia makalesinin bağlantı verdiğiniz bölümünde dördüncü bir madde işareti var ve "A Algısal olarak daha uygun bir alternatif, hafiflik boyutu olarak luma, Y ′ kullanmaktır" (vurgu benim) şeklinde ifade eden ve ardından Alnitak'ta sunulan formülü vermeye devam ve Robin'in cevapları. Diğer bir deyişle, dışarıda bıraktığınız ve tavsiye etmediğiniz yöntem, insan algısına en iyi uyan yöntemdir.
John Y

@JohnY evet, söylemeye çalıştığım şey buydu - cevabının geri kalanına gerçekten uyan tek kişiyi dışarıda bıraktı.
Alnitak

Evet, burada kafası karışan tek kişi benim. Sorun değil :) Sadece enerji ile algı arasında bir fark olduğu ana noktayı anlamak istedim. Cevabımı buna göre güncelleyeceğim.
David Nguyen

4

Bu hex ile çalışır, örneğin #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;
}

İade etmek trueveya falsedeğiştirmek için değiştirebilirsiniz

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

-e

return (yiq < 40);

@Vivek, tam onaltılık değerler kullanmanız gerektiğinden (# 000000 ve #ffffff)
TheCrazyProfessor

2

Olası bir çözüm, renginizi RGB'den HSB'ye dönüştürmek olabilir . HSB, renk tonu, doygunluk ve parlaklık anlamına gelir (HSV olarak da bilinir, burada V değer anlamına gelir). O zaman kontrol etmeniz gereken tek bir parametre vardır: parlaklık.


1

Bu konuşmanın birkaç yıllık olduğunun farkındayım ama yine de geçerli. Ekibimin Java'da (SWT) aynı sorunu yaşadığını eklemek istedim ve bunu biraz daha doğru buldum:

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;
    }
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.