Public
Edited
May 20, 2024
Insert cell
Insert cell
Insert cell
function rgb2hsb(r, g, b, rangeR = 255, rangeG = 255, rangeB = 255, rangeH = 360, rangeS = 100, rangeBri = 100){
let nr = r / rangeR, ng = g / rangeG, nb = b / rangeB;
let max = Math.max(nr, ng, nb);
let min = Math.min(nr, ng, nb);
let bri = max;
let sat = max === 0 ? 0 : ((max - min) / max);
let hue, diff = (max - min);
switch (max){
case min:
hue = 0;
break;
case nr:
hue = (1. / 6.) * (ng-nb) / diff;
break;
case ng:
hue = (1. / 6.) * (2. + (nb - nr) / diff);
break;
case nb:
hue = (1. / 6.) * (4. + (nr - ng) / diff);
break;
}
if (hue < 0) hue += 1.
return [hue * rangeH, sat * rangeS, bri * rangeBri];
}
Insert cell
function hsb2rgb(hue, sat, bri, rangeH = 360, rangeS = 100, rangeBri = 100, rangeR = 255, rangeG = 255, rangeB = 255){
let nh = hue / rangeH, ns = sat / rangeS, nbri = bri / rangeBri;
let i = Math.floor(nh * 6);
let f = nh * 6 - i;
let p = nbri * (1 - ns);
let q = nbri * (1 - f * ns);
let t = nbri * (1 - (1 - f) * ns);
let r, g, b;
switch (i % 6) {
case 0: r = nbri, g = t, b = p; break;
case 1: r = q, g = nbri, b = p; break;
case 2: r = p, g = nbri, b = t; break;
case 3: r = p, g = q, b = nbri; break;
case 4: r = t, g = p, b = nbri; break;
case 5: r = nbri, g = p, b = q; break;
}
return [r * rangeR, b * rangeB, g * rangeG];
}
Insert cell
function hsl2hsb(hue, sat, lit, rangH=360, rangS=100, rangL=100, _rangH=360, _rangS=100, _rangB=100) {
let h = hue / rangH, s = sat / rangS, l = lit / rangL;
let _h = h, _s, _b;
l *= 2;
s *= (l <= 1) ? l : 2 - l;
_b = (l + s) / 2;
_s = (2 * s) / (l + s);
return [_h * _rangH, _s * _rangS, _b * _rangB];
}
Insert cell
function hsb2hsl(hue, sat, bri, rangH=360, rangS=100, rangB=100, _rangH=360, _rangS=100, _rangL=100) {
let h = hue / rangH, s = sat / rangS, b = bri / rangB;
let _h = h,_s = s * b,_l = (2 - s) * b;
_s /= (_l <= 1) ? _l : 2 - _l;
_l /= 2;
return [_h * _rangH, _s * _rangS, _l * _rangL]
}
Insert cell
function hsl2rgb(hue, sat, lit, rangH=360, rangS=100, rangL=100, rangR=255, rangG=255, rangB=255) {
let hsb = hsl2hsb(hue, sat, lit, rangH, rangS, rangL, 1, 1, 1);
return hsb2rgb(hsb[0], hsb[1], hsb[2], 1, 1, 1, rangR, rangG, rangB);
}
Insert cell
function rgb2hsl(r, g, b, rangR=255, rangG=255, rangB=255, rangH=360, rangS=100, rangL=100) {
let hsb = rgb2hsb(r, g, b, rangR, rangG, rangB, 1, 1, 1);
return hsb2hsl(hsb[0], hsb[1], hsb[2], 1, 1, 1, rangH, rangS, rangL);
}
Insert cell
function cmyk2rgb(cyan, mag, yellow, dark, rangC=100, rangM=100, rangY=100, rangK=100, rangR=255, rangG=255, rangB=255) {
let c = cyan/rangC, m = mag/rangM, y=yellow/rangY, k=dark/rangK;
c = c * (1 - k) + k;
m = m * (1 - k) + k;
y = y * (1 - k) + k;
let r = 1 - c, g = 1 - m, b = 1 - y;
return [r * rangR, g * rangG, b * rangB];
}
Insert cell
function rgb2cmyk(red, green, blue, rangR=255, rangG=255, rangB=255, rangC=100, rangM=100, rangY=100, rangK=100){
let r = red / rangR, g = green / rangG, b = blue / rangB;
let c = 1 - r, m = 1 - g, y = 1 - b, k = k = Math.min(c, Math.min(m, y));
c = k === 1 ? 0 : (c - k) / (1 - k);
m = k === 1 ? 0 : (m - k) / (1 - k);
y = k === 1 ? 0 : (y - k) / (1 - k);
return [c * rangC, m * rangM, y * rangY, k * rangK];
}
Insert cell
function lab2rgb(l, a, b, _rangeR=255, _rangeG=255, _rangeB=255){
let y = (l + 16) / 116, x = a / 500 + y, z = y - b / 200, _r, _g, _b;
x = 0.95047 * ((x * x * x > 0.008856) ? x * x * x : (x - 16/116) / 7.787);
y = 1.00000 * ((y * y * y > 0.008856) ? y * y * y : (y - 16/116) / 7.787);
z = 1.08883 * ((z * z * z > 0.008856) ? z * z * z : (z - 16/116) / 7.787);
_r = x * 3.2406 + y * -1.5372 + z * -0.4986;
_g = x * -0.9689 + y * 1.8758 + z * 0.0415;
_b = x * 0.0557 + y * -0.2040 + z * 1.0570;
_r = (_r > 0.0031308) ? (1.055 * Math.pow(_r, 1/2.4) - 0.055) : 12.92 * _r;
_g = (_g > 0.0031308) ? (1.055 * Math.pow(_g, 1/2.4) - 0.055) : 12.92 * _g;
_b = (_b > 0.0031308) ? (1.055 * Math.pow(_b, 1/2.4) - 0.055) : 12.92 * _b;
_r = Math.max(0, Math.min(1, _r));
_g = Math.max(0, Math.min(1, _g));
_b = Math.max(0, Math.min(1, _b));
return [_r * _rangeR, _g * _rangeG, _b * _rangeB];
}

Insert cell
function rgb2lab(red, green, blue, rangeR=255, rangeG=255, rangeB=255){
let r = red / rangeR, g = green / rangeG, b = blue / rangeB, x, y, z;
r = (r > 0.04045) ? Math.pow((r + 0.055) / 1.055, 2.4) : r / 12.92;
g = (g > 0.04045) ? Math.pow((g + 0.055) / 1.055, 2.4) : g / 12.92;
b = (b > 0.04045) ? Math.pow((b + 0.055) / 1.055, 2.4) : b / 12.92;
x = (r * 0.4124 + g * 0.3576 + b * 0.1805) / 0.95047;
y = (r * 0.2126 + g * 0.7152 + b * 0.0722) / 1.00000;
z = (r * 0.0193 + g * 0.1192 + b * 0.9505) / 1.08883;
x = (x > 0.008856) ? Math.pow(x, 1/3) : (7.787 * x) + 16/116;
y = (y > 0.008856) ? Math.pow(y, 1/3) : (7.787 * y) + 16/116;
z = (z > 0.008856) ? Math.pow(z, 1/3) : (7.787 * z) + 16/116;
return [(116 * y) - 16, 500 * (x - y), 200 * (y - z)]
}
Insert cell
function deltaE(l0, a0, b0, l1, a1, b1){
let dl = l1 - l0, da = a1 - a0, db = b1 - b0, c0 = Math.sqrt(a0**2+b0**2), c1 = Math.sqrt(a1**2+b1**2),dc=c1 - c0;
let dh = da**2 + db**2 - dc**2;
dh = dh < 0 ? 0 : Math.sqrt(dh);
let sc = 1.0 + 0.045*c0, sh = 1.0 + 0.045*c0;
let dlklsl = dl / (1.0), dckcsc = dc / sc, dhkhsh = dh / sh;
let res = dlklsl**2 + dckcsc ** 2 + dhkhsh ** 2;
return res < 0 ? 0 : Math.sqrt(res);
}
Insert cell
function ryb2rgb(red, yellow, blue, rangeR=1,rangeY=1,rangeB=1,_rangeR=255,_rangeG=255,_rangeB=255) {
let r = red / rangeR, y = yellow / rangeY, b = blue / rangeB;
const f = (ryb) => {
if (ryb[0] === 0 && ryb[1] === 0 && ryb[2] === 0) {
// white
return [1, 1, 1];
} else if (ryb[0] === 1 && ryb[1] === 0 && ryb[2] === 0) {
// red
return [1, 0, 0];
} else if (ryb[0] === 0 && ryb[1] === 1 && ryb[2] === 0) {
// yellow
return [1, 1, 0];
} else if (ryb[0] === 1 && ryb[1] === 1 && ryb[2] === 0) {
// orange
return [1, 0.5, 0];
} else if (ryb[0] === 0 && ryb[1] === 0 && ryb[2] === 1) {
// blue
return [0.163, 0.373, 0.60];
} else if (ryb[0] === 1 && ryb[1] === 0 && ryb[2] === 1) {
// violet
return [0.5, 0, 0.5];
} else if (ryb[0] === 0 && ryb[1] === 1 && ryb[2] === 1) {
// green
return [0, 0.66, 0.2];
} else if (ryb[0] === 1 && ryb[1] === 1 && ryb[2] === 1) {
// black
return [0, 0, 0];
} else {
let res = [0,0,0];
for (let i = 0; i < res.length; ++i) {
res[i] = f([0,0,0])[i] * (1 - ryb[0]) * (1 - ryb[1]) * (1 - ryb[2]) +
f([0,0,1])[i] * (1 - ryb[0]) * (1 - ryb[1]) * ryb[2] +
f([0,1,0])[i] * (1 - ryb[0]) * ryb[1] * (1 - ryb[2]) +
f([1,0,0])[i] * ryb[0] * (1 - ryb[1]) * (1 - ryb[2]) +
f([0,1,1])[i] * (1 - ryb[0]) * ryb[1] * ryb[2] +
f([1,0,1])[i] * ryb[0] * (1 - ryb[1]) * ryb[2] +
f([1,1,0])[i] * ryb[0] * ryb[1] * (1 - ryb[2]) +
f([1,1,1])[i] * ryb[0] * ryb[1] * ryb[2];
}
return res;
}
}
let re = f([r,y,b]);
return [re[0] * _rangeR, re[1] * _rangeG, re[2] *_rangeB];
}
Insert cell
function rgb2ryb(red, green, blue, rangeR=255,rangeG=255,rangeB=255,_rangeR=1,_rangeY=1,_rangeB=1) {
let r = red/rangeR, g = green/rangeG, b = blue/rangeB;
const f = (rgb) => {
if (rgb[0] === 0 && rgb[1] === 0 && rgb[2] === 0) {
// black
return [1, 1, 1];
} else if (rgb[0] === 1 && rgb[1] === 0 && rgb[2] === 0) {
// red
return [1, 0, 0];
} else if (rgb[0] === 0 && rgb[1] === 1 && rgb[2] === 0) {
// green
return [0, 1, 0.483];
} else if (rgb[0] === 1 && rgb[1] === 1 && rgb[2] === 0) {
// yellow
return [0, 1, 0];
} else if (rgb[0] === 0 && rgb[1] === 0 && rgb[2] === 1) {
// blue
return [0, 0, 1];
} else if (rgb[0] === 1 && rgb[1] === 0 && rgb[2] === 1) {
// magenta
return [0.309, 0, 0.469];
} else if (rgb[0] === 0 && rgb[1] === 1 && rgb[2] === 1) {
// lightblue
return [0, 0.053, 0.210];
} else if (rgb[0] === 1 && rgb[1] === 1 && rgb[2] === 1) {
// white
return [0, 0, 0];
} else {
let res = [0,0,0];
for (let i = 0; i < res.length; ++i) {
res[i] = f([0,0,0])[i] * (1 - rgb[0]) * (1 - rgb[1]) * (1 - rgb[2]) +
f([0,0,1])[i] * (1 - rgb[0]) * (1 - rgb[1]) * rgb[2] +
f([0,1,0])[i] * (1 - rgb[0]) * rgb[1] * (1 - rgb[2]) +
f([1,0,0])[i] * rgb[0] * (1 - rgb[1]) * (1 - rgb[2]) +
f([0,1,1])[i] * (1 - rgb[0]) * rgb[1] * rgb[2] +
f([1,0,1])[i] * rgb[0] * (1 - rgb[1]) * rgb[2] +
f([1,1,0])[i] * rgb[0] * rgb[1] * (1 - rgb[2]) +
f([1,1,1])[i] * rgb[0] * rgb[1] * rgb[2];
}
return res;
}
}
let re = f([r,g,b]);
return [re[0] * _rangeR, re[1] * _rangeY, re[1] * _rangeB];
}
Insert cell
function rgb2yiq(red, green, blue, rangeR=255,rangeG=255,rangeB=255){
let r = red/rangeR, g = green/rangeG, b = blue/rangeB;
let y = 0.30 * r + 0.59 * g + 0.11 * b;
let i = -0.27 * (b - y) + 0.74 * (r - y);
let q = 0.41*(b - y) + 0.48 * (r - y);
return [y,i,q];
}
Insert cell
function yiq2rgb(y,i,q,rangeR=255,rangeG=255,rangeB=255) {
let r = y + 0.9469 * i + 0.6236 * q;
let g = y - 0.2748 * i - 0.6357 * q;
let b = y - 1.1* i + 1.7* q;
return [r * rangeR, g * rangeG, b * rangeB];
}
Insert cell
function yuv2yiq(y,u,v) {
return[y, u * -0.54464 + v * 0.83867, u * 0.83867 + v * 0.54464];
}
Insert cell
function yiq2yuv(y,i,q) {
return[y, i * -0.54464 + q * 0.83867, i * 0.83867 + q * 0.54464]
}
Insert cell
function yuv2rgb(y,u,v,rangeR=255,rangeG=255,rangeB=255){
let yiq = yuv2yiq(y,u,v);
return yiq2rgb(yiq[0],yiq[1],yiq[2],rangeR,rangeG,rangeB);
}
Insert cell
function rgb2yuv(r,g,b,rangeR=255,rangeG=255,rangeB=255) {
let yiq = rgb2yiq(r,g,b,rangeR,rangeG,rangeB);
return yiq2yuv(...yiq)
}
Insert cell
function ncs2rgb(ncsString, rangeR=255, rangeG=255,rangeB=255) {
// from https://github.com/m90/ncs-color/blob/master/ncscolor.js
const ncsRe = /^(?:NCS|NCS\sS)\s(\d{2})(\d{2})-(N|R|G|B|Y)(\d{2})?(R|G|B|Y)?$/
let ncs = ncsString.trim().toUpperCase().match(ncsRe)
if (ncs === null) {
throw new Error("Invalid NCS color");
}
let Sn = parseInt(ncs[1], 10);
let Cn = parseInt(ncs[2], 10);
let C1 = ncs[3];
let N = parseInt(ncs[4], 10) || 0;
if (C1 !== 'N') {
let S = (1.05 * Sn - 5.25),C = Cn,Ra,x1,Ba,x2,x3,x5,Ga,x6,x7,x8,Rc,Gc,Bc,top,ss;

// extract red
if (C1 === 'Y' && N <= 60) {
Ra = 1;
} else if ((C1 === 'Y' && N > 60) || (C1 === 'R' && N <= 80)) {
if (C1 === 'Y') {
x1 = N - 60;
} else {
x1 = N + 40;
}
Ra = ((Math.sqrt(14884 - Math.pow(x1, 2))) - 22) / 100;
} else if ((C1 === 'R' && N > 80) || (C1 === 'B')) {
Ra = 0;
} else if (C1 === 'G') {
x1 = (N - 170);
Ra = ((Math.sqrt(33800 - Math.pow(x1, 2))) - 70) / 100;
}

// extract blue
if (C1 === 'Y' && N <= 80) {
Ba = 0;
} else if ((C1 === 'Y' && N > 80) || (C1 === 'R' && N <= 60)) {
if (C1 === 'Y') {
x2 = (N - 80) + 20.5;
} else {
x2 = (N + 20) + 20.5;
}
Ba = (104 - (Math.sqrt(11236 - Math.pow(x2, 2)))) / 100;
} else if ((C1 === 'R' && N > 60) || (C1 === 'B' && N <= 80)) {
if (C1 === 'R') {
x3 = (N - 60) - 60;
} else {
x3 = (N + 40) - 60;
}
Ba = ((Math.sqrt(10000 - Math.pow(x3, 2))) - 10) / 100
} else if ((C1 === 'B' && N > 80) || (C1 === 'G' && N <= 40)) {
if (C1 === 'B') {
x5 = (N - 80) - 131;
} else {
x5 = (N + 20) - 131;
}
Ba = (122 - (Math.sqrt(19881 - Math.pow(x5, 2)))) / 100;
} else if (C1 === 'G' && N > 40) {
Ba = 0;
}

// exctract green
if (C1 === 'Y') {
Ga = (85 - 17 / 20 * N) / 100;
} else if (C1 === 'R' && N <= 60) {
Ga = 0;
} else if (C1 === 'R' && N > 60) {
x6 = (N - 60) + 35;
Ga = (67.5 - (Math.sqrt(5776 - Math.pow(x6, 2)))) / 100;
} else if (C1 === 'B' && N <= 60) {
x8 = (1 * N - 68.5);
Ga = (6.5 + (Math.sqrt(7044.5 - Math.pow(x8, 2)))) / 100;
} else if ((C1 === 'B' && N > 60) || (C1 === 'G' && N <= 60)) {
Ga = 0.9;
} else if (C1 === 'G' && N > 60) {
x7 = (N - 60);
Ga = (90 - (1 / 8 * x7)) / 100;
}

// extract saturation
x2 = (Ra + Ga + Ba) / 3;
Rc = ((x2 - Ra) * (100 - C) / 100) + Ra;
Gc = ((x2 - Ga) * (100 - C) / 100) + Ga;
Bc = ((x2 - Ba) * (100 - C) / 100) + Ba;

// extract blackness
top = Math.max(Rc, Gc, Bc);

ss = 1 / top;

return [
(Rc * ss * (100 - S) / 100) * rangeR,
(Gc * ss * (100 - S) / 100) * rangeG,
(Bc * ss * (100 - S) / 100) * rangeB
];
} else {
var v = (1 - Sn / 100) * rangeR
return [v,v,v];
}
}
Insert cell
function xyz2rgb(x, y, z, rangeX=1,rangeY=1,rangeZ=1,rangeR=255,rangeG=255,rangeB=255) {
let xx = x / rangeX, yy = y / rangeY, zz = z / rangeZ;
let r = xx * 3.240481 + yy * -1.537151 + zz * -0.498536,
g = xx * -0.969256 + yy * 1.875990 + zz * 0.041556,
b = xx * 0.055647 + yy * -0.204041 + zz * 1.057311
if ( r > 0.0031308 ) {
r = 1.055 * ( r ** ( 1 / 2.4 ) ) - 0.055;
} else {
r = 12.92 * r;
}
if ( g > 0.0031308 ) {
g = 1.055 * ( g ** ( 1 / 2.4 ) ) - 0.055;
} else {
g = 12.92 * g;
}
if ( b > 0.0031308 ) {
b = 1.055 * ( b ** ( 1 / 2.4 ) ) - 0.055;
} else {
b = 12.92 * b;
}
return [r * rangeR, b * rangeB, g * rangeG];
}
Insert cell
function rgb2xyz(r, g, b, rangeR=255,rangeG=255,rangeB=255,rangeX=1,rangeY=1,rangeZ=1) {
let rr = ( r / rangeR ), gg = ( g / rangeG ), bb = ( b / rangeB );
if ( rr > 0.04045 ) {
rr = ( ( rr + 0.055 ) / 1.055 ) ** 2.4;
} else {
rr = rr / 12.92;
}
if ( gg > 0.04045 ) {
gg = ( ( gg + 0.055 ) / 1.055 ) ** 2.4;
} else {
gg = gg / 12.92;
}
if ( bb > 0.04045 ) {
bb = ( ( bb + 0.055 ) / 1.055 ) ** 2.4;
} else {
bb = bb / 12.92;
}
let x = rr * 0.412453 + gg * 0.357580 + bb * 0.180423,
y = rr * 0.212671 + gg * 0.715160 + bb * 0.072169,
z = rr * 0.019334 + gg * 0.119193 + bb * 0.950227;
return [x * rangeX, y * rangeY, z * rangeZ];
}
Insert cell
function xyz2lms(x, y, z, rangeX=1, rangeY=1, rangeZ=1, matName="E") {
let xx = x / rangeX, yy = y / rangeY, zz = z / rangeZ;
const options = {
E:[
[0.38971, 0.68898, -0.07868],
[-0.22981, 1.18340, 0.04641],
[0,0,1]
],
D65:[
[0.4002, 0.7076, -0.0808],
[-0.2263, 1.1653, 0.0457],
[0, 0, 0.9182]
],
BFD:[
[0.8951, 0.2664, -0.1614],
[-0.7502, 1.7135, 0.0367],
[0.0389, -0.0685, 1.0296]
],
CAT97:[
[0.8562, 0.3372, -0.1934],
[-0.8360, 1.8327, 0.0033],
[0.0357, -0.0469, 1.0112]
],
CAT02:[
[0.7328, 0.4296, -0.1624],
[-0.7036, 1.6975, 0.0061],
[0.0030, 0.0136, 0.9834]
],
CAT16:[
[0.401288, 0.650173, -0.051461],
[-0.250268, 1.204414, 0.045854],
[-0.002079, 0.048592, 0.953127]
]
}
const mat = options[matName];
return [mat[0][0]*xx+mat[0][1]*yy+mat[0][2]*zz, mat[1][0]*xx+mat[1][1]*yy+mat[1][2]*zz, mat[2][0]*xx+mat[2][1]*yy+mat[2][2]*zz];
}
Insert cell
function lms2xyz(l, m, s, rangeX=1, rangeY=1, rangeZ=1) {
let x = 1.91020 * l + -1.11212 * m + 0.20191 * s,
y = 0.37095 * l + 0.62905 * m + 0 * s,
z = s;
return [x * rangeX, y * rangeY, z * rangeZ];
}
Insert cell
function rgb2lms(r, g, b, rangeR=255,rangeG=255,rangeB=255,matName="E") {
let xyz = rgb2xyz(r, g, b, rangeR, rangeG, rangeB, 1, 1, 1);
return xyz2lms(xyz[0],xyz[1],xyz[2],1,1,1,matName);
}
Insert cell
function lms2rgb(l,m,s,rangeR=255,rangeG=255,rangeB=255) {
let xyz = lms2xyz(l, m, s, 1, 1, 1);
return xyz2rgb(xyz[0],xyz[1],xyz[2],1,1,1,rangeR,rangeG,rangeB);
}
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more