这是我根据Myndex之前写的更新后的代码。
对于测试示例purple,我使用十六进制#9d5fb0
(代表R:157, G:95, B:176),对于绿色,我使用十六进制#318261
(代表R:49, G:130, B:97)
JS:
function HexToRGB(hex) {
// to allow shorthand input like #FFF or FFFFFF without # sign make it #FFFFFF
hex = String(hex)
if(hex.length==3){hex='#'+hex.substr(0, 1)+hex.substr(0, 1)+hex.substr(1, 1)+hex.substr(1, 1)+hex.substr(2, 1)+hex.substr(2, 1)
if(hex.length==4){hex='#'+hex.substr(1, 1)+hex.substr(1, 1)+hex.substr(2, 1)+hex.substr(2, 1)+hex.substr(3, 1)+hex.substr(3, 1)
if(hex.length==6){hex='#'+hex
let R = parseInt(hex.substr(1, 2),16)
let G = parseInt(hex.substr(3, 2),16)
let B = parseInt(hex.substr(5, 2),16)
console.log("rgb from "+hex+" = "+[R,G,B])
return [R,G,B]
}
程序员常用的灰度计算公式是:
GRAY = round((R + G + B) / 3);
JS实现:
function RGBToGRAY(rgb) {
let avg = parseInt((rgb[0]+rgb[1]+rgb[2])/3);
return [avg,avg,avg];
}
这将把紫色转换为#8f8f8f,因为平均值= 143
这将把绿色转换为#5c5c5c,因为平均值= 92
92和143之间的差异太大,会错误地通过我的预期测试。 Adobe的模拟将相同的示例转换为灰度:
十六进制#777777代表
十六进制#747474代表
116和119之间的差异明显很小,应该未能通过我的预期差异测试。因此,RGBToGRAY方法被证明不准确。
现在,正如Myndex所解释的那样,我们应该使其线性并应用伽马2.2校正。
R´^2.2 = Rlin G´^2.2 = Glin B´^2.2 = Blin
JS:
function linearFromRGB(rgb) {
// make it decimal
let R = rgb[0]/255.0; // red channel decimal
let G = rgb[1]/255.0; // green channel decimal
let B = rgb[2]/255.0; // blue channel decimal
// apply gamma
let gamma = 2.2;
R = Math.pow(R, gamma); // linearize red
G = Math.pow(G, gamma); // linearize green
B = Math.pow(B, gamma); // linearize blue
let linear = [R,G,B];
console.log('linearized rgb = '+linear);
return linear;
}
紫色的伽马校正线性结果现在为R:0.3440,G:0.1139,B:0.4423,绿色的结果为R:0.0265,G:0.2271,B:0.1192
现在通过应用系数来获取亮度L或(XYZ比例中的Y)如下:
Y = Rlin * 0.2126 + Glin * 0.7152 + Blin * 0.0722
JS
function luminanceFromLin(rgblin) {
let Y = (0.2126 * (rgblin[0]));
Y = Y + (0.7152 * (rgblin[1]));
Y = Y + (0.0722 * (rgblin[2]));
console.log('luminance from linear = '+Y);
return Y;
}
现在计算两个Y(或L)值之间的感知对比度:
(Llighter - Ldarker) / (Llighter + 0.1)
JS
function perceivedContrast(Y1,Y2){
let C = ((Math.max(Y1,Y2)-Math.min(Y1,Y2))/(Math.max(Y1,Y2)+0.1));
console.log('perceived contrast from '+Y1+','+Y2+' = '+C);
return C;
}
现在所有上述功能都合并为一个步骤的输入/输出
function perceivedContrastFromHex(hex1,hex2){
let lin1 = linearFromRGB(HexToRGB(hex1));
let lin2 = linearFromRGB(HexToRGB(hex2));
let y1 = luminanceFromLin(lin1);
let y2 = luminanceFromLin(lin2);
return perceivedContrast(y1,y2);
}
最后进行测试
var P = perceivedContrastFromHex('#318261','#9d5fb0');
// compares the purple and green example
alert(P);
// shows 0.034369592139888626
var P = perceivedContrastFromHex('#000','#fff');
// compares pure black and white
alert(P);
// shows 0.9090909090909091