web-dev-qa-db-fra.com

Comment calculer par programme le rapport de contraste entre deux couleurs?

Très simple, prenez jaune et blanc:

back_color = {r:255,g:255,b:255}; //white
text_color = {r:255,g:255,b:0}; //yellow

Quelle loi de la physique sur la Terre de Dieu aux constantes universelles, fait que le texte jaune ne peut pas être lu sur des fonds blancs, mais le texte bleu peut?

Par souci de mon widget personnalisable, j'ai essayé tous les modèles de couleurs possibles pour lesquels j'ai trouvé des fonctions de conversion; aucun ne peut dire que le vert peut être sur le blanc et le jaune ne peut pas, basé uniquement sur des comparaisons numériques.

J'ai regardé Adsense (qui est créé par la Budda de tout Internet) et devinez ce qu'ils ont fait: ils ont fait des calculs de distance et de préréglages. Je ne peux pas faire ça. Mes utilisateurs ont le droit de choisir même les combinaisons les plus rétino-inflammatoires et les moins esthétiques, à condition que le texte puisse toujours être lu.

46
Silviu-Marian

Selon Wikipedia, lors de la conversion en représentation de la luminance en niveaux de gris, "il faut obtenir les valeurs de ses couleurs rouge, vert et bleu" et les mélanger dans la proportion suivante: R: 30% G: 59% B: 11%

Par conséquent, le blanc aura une luminance de 100% et le jaune, de 89%. Dans le même temps, le vert a aussi peu que 59%. 11% est presque quatre fois moins que 41% de différence!

Et même la chaux (#00ff00) n'est pas bonne pour lire de grandes quantités de textes.

À mon humble avis, la luminosité des couleurs de contraste doit être au moins différente de 50%. Et cette luminosité doit être mesurée convertie en niveaux de gris.

upd: Nous avons récemment trouvé un outil complet pour cela sur le Web qui utilise dans l’ordre les formules de w3 document Les valeurs seuils pourraient être prises à partir de # 1.4 Voici une implémentation pour cette solution plus avancée.

function luminanace(r, g, b) {
    var a = [r, g, b].map(function (v) {
        v /= 255;
        return v <= 0.03928
            ? v / 12.92
            : Math.pow( (v + 0.055) / 1.055, 2.4 );
    });
    return a[0] * 0.2126 + a[1] * 0.7152 + a[2] * 0.0722;
}
function contrast(rgb1, rgb2) {
    return (luminanace(rgb1[0], rgb1[1], rgb1[2]) + 0.05)
         / (luminanace(rgb2[0], rgb2[1], rgb2[2]) + 0.05);
}
contrast([255, 255, 255], [255, 255, 0]); // 1.074 for yellow
contrast([255, 255, 255], [0, 0, 255]); // 8.592 for blue
// minimal recommended contrast ratio is 4.5, or 3 for larger font-sizes
52
kirilloid

Il existe différentes manières de calculer le contraste, mais la formule la plus courante est la suivante:

brightness = (299*R + 587*G + 114*B) / 1000

Vous faites cela pour les deux couleurs, puis vous prenez la différence. Cela donne évidemment un contraste beaucoup plus grand pour le bleu sur blanc que pour le jaune sur blanc.

19
orlp

Récemment, j'ai trouvé la réponse sur cette page et j'ai utilisé le code pour créer un script permettant à Adobe Illustrator de calculer le rapport de contraste. 

Ici vous pouvez voir le résultat: http://screencast.com/t/utT481Ut

Certaines des notations abrégées du script ci-dessus étaient déroutantes pour moi et ne fonctionnaient pas dans le script d’extension Adobe. Par conséquent, j'ai pensé qu'il serait agréable de partager mon amélioration/interprétation du code partagé par kirilloid.

function luminance(r, g, b) {
    var colorArray = [r, g, b];
    var colorFactor;
    var i;
    for (i = 0; i < colorArray.length; i++) {
        colorFactor = colorArray[i] / 255;
        if (colorFactor <= 0.03928) {
            colorFactor = colorFactor / 12.92;
        } else {
            colorFactor = Math.pow(((colorFactor + 0.055) / 1.055), 2.4);
        }
        colorArray[i] = colorFactor;
    }
    return (colorArray[0] * 0.2126 + colorArray[1] * 0.7152 + colorArray[2] * 0.0722) + 0.05;
}

Et bien sûr, vous devez appeler cette fonction

dans une boucle, je reçois toutes les couleurs de mon objet illustrator

//just a snippet here to demonstrate the notation
var selection = app.activeDocument.selection;
for (i = 0; i < selection.length; i++) {
   red[i] = selection[i].fillColor.red;
   //I left out the rest,because it would become to long
}

//this can then be used to calculate the contrast ratio.
var foreGround = luminance(red[0], green[0], blue[0]);
var background = luminance(red[1], green[1], blue[1]);
luminanceValue = foreGround / background;
luminanceValue = round(luminanceValue, 2);

//for rounding the numbers I use this function:
function round(number, decimals) {
   return +(Math.round(number + "e+" + decimals) + "e-" + decimals);
}

Plus d'informations sur le rapport de contraste: http://webaim.org/resources/contrastchecker/

1
user1495594

Basé sur la réponse kirilloïde:

Service angulaire qui calculera le contraste et la luminescence en passant dans la valeur hexadécimale:

.service('ColorContrast', [function() {
var self = this;

/**
 * Return iluminance value (base for getting the contrast)
 */
self.calculateIlluminance = function(hexColor) {
    return calculateIluminance(hexColor);
};

/**
 * Calculate contrast value to white
 */
self.contrastToWhite = function(hexColor){
    var whiteIlluminance = 1;
    var illuminance = calculateIlluminance(hexColor);
    return whiteIlluminance / illuminance;
};

/**
* Bool if there is enough contrast to white
*/
self.isContrastOkToWhite = function(hexColor){
    return self.contrastToWhite(hexColor) > 4.5;
};

/**
 * Convert HEX color to RGB
 */
var hex2Rgb = function(hex) {
    var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
    return result ? {
        r: parseInt(result[1], 16),
        g: parseInt(result[2], 16),
        b: parseInt(result[3], 16)
    } : null;
};

/**
 * Calculate iluminance
 */
var calculateIlluminance = function(hexColor) {
    var rgbColor = hex2Rgb(hexColor);
    var r = rgbColor.r, g = rgbColor.g, b = rgbColor.b;
    var a = [r, g, b].map(function(v) {
        v /= 255;
        return (v <= 0.03928) ?
            v / 12.92 :
            Math.pow(((v + 0.055) / 1.055), 2.4);
    });
    return a[0] * 0.2126 + a[1] * 0.7152 + a[2] * 0.0722;
};

}]);
1
Tom
module.exports = function colorcontrast (hex) {
    var color = {};

    color.contrast = function(rgb) {
        // check if we are receiving an element or element background-color
        if (rgb instanceof jQuery) {
            // get element background-color
            rgb = rgb.css('background-color');
        } else if (typeof rgb !== 'string') {
            return;
        }

        // Strip everything except the integers eg. "rgb(" and ")" and " "
        rgb = rgb.split(/\(([^)]+)\)/)[1].replace(/ /g, '');

        // map RGB values to variables
        var r = parseInt(rgb.split(',')[0], 10),
            g = parseInt(rgb.split(',')[1], 10),
            b = parseInt(rgb.split(',')[2], 10),
            a;

        // if RGBA, map alpha to variable (not currently in use)
        if (rgb.split(',')[3] !== null) {
            a = parseInt(rgb.split(',')[3], 10);
        }

        // calculate contrast of color (standard grayscale algorithmic formula)
        var contrast = (Math.round(r * 299) + Math.round(g * 587) + Math.round(b * 114)) / 1000;

        return (contrast >= 128) ? 'black' : 'white';
    };

    // Return public interface
    return color;

};
0
davidcondrey