web-dev-qa-db-fra.com

Comment vérifier si la couleur hexadécimale est "trop ​​noire"?

J'essaie d'évaluer l'obscurité d'une couleur choisie par un sélecteur de couleurs pour voir si elle est "trop ​​noire", et si oui, réglez-la sur blanc. J'ai pensé que je pourrais utiliser les premiers caractères de la valeur hexadécimale pour le retirer. Ça marche, mais ça change aussi des couleurs légitimement "claires".

J'ai du code qui fait ça:

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

Il doit y avoir un moyen plus efficace avec les mathématiques hexadécimales de savoir qu'une couleur a dépassé un certain niveau d'obscurité? Comme si lightcolor + "une valeur hexadécimale" <= "une valeur hexadécimale", définissez-le sur blanc.

J'ai ajouté tinyColor, qui pourrait être utile pour cela, mais je ne sais pas avec certitude.

Un tas!

97
Dshiz

Vous devez extraire les trois composants RVB individuellement, puis utiliser une formule standard pour convertir les valeurs RVB résultantes en leur luminosité perçue.

En supposant une couleur à six caractères:

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
}

MODIFIER

Depuis mai 2014, tinycolor possède désormais une fonction getBrightness(), mais en utilisant les facteurs de pondération CCIR601 au lieu de ceux de l'UIT-R ci-dessus.

MODIFIER

La plage de valeurs de luma résultante est de 0 à 255, où 0 est le plus sombre et 255 le plus clair. Les valeurs supérieures à 128 sont considérées comme légères par tinycolor. (copié sans vergogne des commentaires de @ pau.moreno et @Alnitak)

209
Alnitak

La bibliothèque TinyColor (vous l'avez déjà mentionné) fournit plusieurs fonctions pour inspecter et manipuler les couleurs, parmi elles:

  • getBrightness

    Renvoie la luminosité perçue d'une couleur, de 0 à 255, telle que définie par Web Content Accessibility Guidelines (Version 1.0) .

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

    Renvoie un booléen indiquant si la luminosité perçue de la couleur est claire.

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

    Retourne un booléen indiquant si la luminosité perçue de la couleur est sombre.

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

    Renvoie la luminance perçue d'une couleur, de 0 à 1 telle que définie par Web Content Accessibility Guidelines (Version 2.0) .

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

J'ai trouvé ce WooCommerce Wordpress PHP ( wc_hex_is_light ) et je me suis converti en JavaScript. Ça marche bien!

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;
}
8
Sergio Cabral

Vous pouvez calculer la luminance :

La luminance est donc un indicateur de la luminosité de la surface.

Il est donc génial de choisir si le texte doit être blanc ou noir.

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

La méthode ci-dessus vous permet de passer la couleur dans différents formats, mais l'algorithme est essentiellement juste en luminance_get.

Lorsque je l'ai utilisé, je mettais la couleur sur noir si la luminance était supérieure à 180, blanc sinon.

6
Robin

Il y a une distinction importante ici entre la luminance et la luminosité. La luminance, à la fin de la journée, est une mesure de la quantité d'énergie qui traverse une certaine zone et ignore complètement la façon dont nos systèmes perceptuels perçoivent cette énergie. La luminosité, d'autre part, est une mesure de la façon dont nous percevons cette énergie et prend en compte la relation entre la luminance et notre système perceptuel. (Comme point de confusion, il existe un terme appelé luminance relative, qui semble être utilisé comme synonyme de termes de luminosité. Cela m'a bien déclenché).

Pour être précis, vous recherchez "luminosité" ou "valeur" ou "relativement luminance" comme d'autres l'ont suggéré. Vous pouvez calculer cela de plusieurs manières différentes (c'est d'être humain!) http://en.wikipedia.org/wiki/HSL_and_HSV#Lightness

  1. Prenez le maximum de R, G et B.
  2. Prenez la moyenne du max et du min de R, G et B.
  3. Prenez la moyenne des trois.
  4. Utilisez une moyenne pondérée comme d'autres l'ont suggéré ici.
5
David Nguyen

Ce travail avec hex, par exemple #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;
}

Vous pouvez le modifier pour renvoyer true ou false par modification

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

à

return (yiq < 40);
5
TheCrazyProfessor

Une solution possible serait de convertir votre couleur de RGB à HSB . HSB signifie teinte, saturation et luminosité (également connu sous le nom de HSV, où V est pour valeur). Vous n'avez alors qu'un seul paramètre à vérifier: la luminosité.

2
Ohad

Je me rends compte que cette conversation a quelques années, mais elle est toujours d'actualité. Je voulais ajouter que mon équipe rencontrait le même problème dans Java (SWT) et j'ai trouvé que c'était un peu plus précis:

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;
    }
}
1
Chris Clark