如何通过编程计算两种颜色之间的对比度?

很简单,拿黄色和白色来说:

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

在上帝的地球上,什么样的物理定律使得黄色文字不能在白色背景下阅读,而蓝色文字可以?

为了我的可定制小部件,我尝试了所有可能的颜色模型,我找到了转换函数; 都不能说,绿色可以在白色和黄色不能,只是基于数字比较。

我查看了 Adsense (它是由所有互联网中的 Budda 创建的) ,猜猜他们做了什么,他们做了预置和彩色单元格距离计算。我做不到。我的用户有权选择即使是最炎症的视网膜,不美观的组合,只要文本仍然可以阅读。

53401 次浏览

According to Wikipedia, when converting to grayscale representation of luminance, "one must obtain the values of its red, green, and blue" and mix them in next proportion: R:30% G:59% B:11%

Therefore white will have 100% luminance and yellow will have 89%. At the same time, green has as small as 59%. 11% is almost four times lower than 41% difference!

And even lime (#00ff00) is not good for reading large amounts of texts.

IMHO for good contrast colors' brightness should differ at least for 50%. And this brightness should be measured as converted to grayscale.

upd: Recently found a comprehensive tool for that on the web which in order uses formula from w3 document Threshold values could be taken from #1.4 Here is an implementation for this more advanced thing.

function luminance(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) {
var lum1 = luminance(rgb1[0], rgb1[1], rgb1[2]);
var lum2 = luminance(rgb2[0], rgb2[1], rgb2[2]);
var brightest = Math.max(lum1, lum2);
var darkest = Math.min(lum1, lum2);
return (brightest + 0.05) /
(darkest + 0.05);
}


console.log(contrast([255, 255, 255], [255, 255, 0])); // 1.074 for yellow
console.log(contrast([255, 255, 255], [0, 0, 255])); // 8.592 for blue
// minimal recommended contrast ratio is 4.5, or 3 for larger font-sizes

For more information, check the WCAG 2.0 documentation on how to compute this value.

There are various ways for calculating contrast, but a common way is this formula:

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

You do this for both colors, and then you take the difference. This obviously gives a much greater contrast for blue on white than yellow on white.

Recently I came across the answer on this page, and I used the code make a script for Adobe Illustrator to calculate the contrast ratio's.

Here you can see the result: http://screencast.com/t/utT481Ut

Some of the shorthand notations of the script above where confusing for me and where not working in Adobe extend script. Therefore I thought would be nice to share my improvement/interpretation of the code that kirilloid shared.

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

And of course you need to call this function

within a for loop I get all the colors from my illustrator object

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

More information about contrast ratio: http://webaim.org/resources/contrastchecker/

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;


};

Based on the kirilloid answer:

Angular Service that will calculate contrast and luminescence by passing in the hex value:

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


}]);

const getLuminanace = (values) => {
const rgb = values.map((v) => {
const val = v / 255;
return val <= 0.03928 ? val / 12.92 : ((val + 0.055) / 1.055) ** 2.4;
});
return Number((0.2126 * rgb[0] + 0.7152 * rgb[1] + 0.0722 * rgb[2]).toFixed(3));
};


const getContrastRatio = (colorA, colorB) => {
const lumA = getLuminanace(colorA);
const lumB = getLuminanace(colorB);


return (Math.max(lumA, lumB) + 0.05) / (Math.min(lumA, lumB) + 0.05);
};


// usage:
const back_color = [255,255,255]; //white
const text_color = [255,255,0]; //yellow


getContrastRatio(back_color, text_color); // 1.0736196319018405


For calculate the contrast programmatically, you can use the NPM's color package; if you just want a tool for compare colors then you can use a Contrast Ratio Calculator