HSV to RGB
by Lamik
HTML
<div>Charts showing the hue (Y axis) as function of (X axis) r (red line), g (green line), b (blue line). There is also button for error comparison with wiki version.</div>
<div>R <input type="range" min="0" max="255" value="0" oninput="setC(0,event)"></div>
<div>G <input type="range" min="0" max="255" value="0" oninput="setC(1,event)"></div>
<div>B <input type="range" min="0" max="255" value="0" oninput="setC(2,event)"></div>
<div>Wiki-Opt max err <button onclick="calcErr()" >Calc (~1min, progress in console)</button> <span id="error"></span></div>
<div id="rgb"></div>
<div id="hsvNew"></div>
<div id="hsvWiki"></div>
<div id="labelOpt">New</div>
<svg viewBox="0 0 100 10" class="chart">
<text x="0" y="10" class="axis">0</text>
<text x="0" y="2" class="axis">360 H</text>
<text x="98" y="10" class="axis">1</text>
<polyline id="chartNewRH" fill="none" stroke="#990000" stroke-width="0.2" points=""/>
<polyline id="chartNewGH" fill="none" stroke="#009900" stroke-width="0.2" points=""/>
<polyline id="chartNewBH" fill="none" stroke="#000099" stroke-width="0.2" points=""/>
</svg>
<div id="labelOpt">Wiki</div>
<svg viewBox="0 0 100 10" class="chart">
<text x="0" y="10" class="axis">0</text>
<text x="0" y="2" class="axis">360 H</text>
<text x="98" y="10" class="axis">1</text>
<polyline id="chartWikiRH" fill="none" stroke="#990000" stroke-width="0.2" points=""/>
<polyline id="chartWikiGH" fill="none" stroke="#009900" stroke-width="0.2" points=""/>
<polyline id="chartWikiBH" fill="none" stroke="#000099" stroke-width="0.2" points=""/>
</svg>
<div class="test">
<div id="colA" class="col"></div>
<div id="colB" class="col"></div>
</div>
CSS
.col { margin: 5px; width: 50px; height: 50px; }
#btn { display: block; margin: 10px; }
.test { display: flex; height: 400px}
.color { width: 50px; height: 1px; }
.chart { border: 1px solid black; }
.axis { font: 2px sans-serif;}
#labelOpt { margin-top: 20px }
JavaScript
function rgb2hsl_new(r,g,b) {
let a=Math.max(r,g,b), n=a-Math.min(r,g,b), f = (1-Math.abs(a+a-n-1));
let h= n && ((a==r) ? (g-b)/n : ((a==g) ? 2+(b-r)/n : 4+(r-g)/n));
return [60*(h<0?h+6:h), f ? n/f : 0, (a+a-n)/2];
}
function rgb2hsl_wiki(r,g,b) {
let a = Math.max(r,g,b);
let i = Math.min(r,g,b);
let n = a-i;
let l = (a+i)/2
let f= (1-Math.abs(a+i-1));
let s = f ? n/f : 0;
let h= 0;
if(n) {
if(a==r) h=60*( 0+(g-b)/n );
if(a==g) h=60*( 2+(b-r)/n );
if(a==b) h=60*( 4+(r-g)/n );
}
return [(h<0?h+360:h)%360,s,l];
}
// ----------------------
// TEST code
// ----------------------
function hsv2rgb(h,s,v)
{
let f= (n,k=(n+h/60)%6) => v-v*s*Math.max(Math.min(k,4-k,1),0);
return [f(5),f(3),f(1)];
}
$ = x=>document.querySelector(x);
function calcMaxError() {
lastErr = {e:0};
for(let i=0; i<256; i++) {
console.log(`calculation...${(100*i/255)|0}%`)
for(let j=0; j<256; j++) {
for(let k=0; k<256; k++) {
let c = [i/255, j/255, k/255];
w = rgb2hsl_wiki(...c);
n = rgb2hsl_new(...c);
e = Math.max( Math.abs(n[0]-w[0]), Math.abs(n[1]-w[1]), Math.abs(n[2]-w[2]));
if(lastErr.e<e) lastErr = {e, wiki:w, new:n, c, i ,j, k}
}
}
}
$('#error').innerHTML = JSON.stringify(lastErr);
}
function chartH(x,y,c,which,r) {
let a = $(`#chart${which}${c}H`).getAttribute('points') +` ${x*100}, ${(10-y/36)}`;
$(`#chart${which}${c}H`).setAttribute('points',r? "":a);
}
function draw(which) {
chartH(0,0,'R',which,1) // clean
chartH(0,0,'G',which,1) // clean
chartH(0,0,'B',which,1) // clean
let rgb2hsv = which == 'Wiki' ? rgb2hsl_wiki : rgb2hsl_new;
for(let i=0; i<256; i++) {
let c= i/255;
chartH(c, rgb2hsv(c, color[1], color[2])[0], 'R',which )
chartH(c, rgb2hsv(color[0], c, color[2])[0], 'G',which )
chartH(c, rgb2hsv(color[0], color[1], c)[0],...