HSV to RGB
by Lamik
HTML
<div>
<button class="btn" onclick="setColIndexChart(0)">Chart R</button>
<button class="btn" onclick="setColIndexChart(1)">Chart G</button>
<button class="btn" onclick="setColIndexChart(2)">Chart B</button>
</div>
<div>Value <input type="range" min="0" max="100" value="50" oninput="setVal(event)"></div>
<div>Saturation <input type="range" min="0" max="100" value="100" oninput="setSat(event)"></div>
<div>Wiki-Opt max <span id="error"></span> </div>
<div id="labelOpt">Optimized</div>
<svg viewBox="0 0 360 60" class="chart">
<text x="0" y="59" class="axis">0</text>
<text x="0" y="10" class="axis">1</text>
<text x="320" y="59" class="axis">360 hue</text>
<polyline id="chartA" fill="none" stroke="#0074d9" stroke-width="1" points=""/>
</svg>
<div id="labelWiki">Wiki</div>
<svg viewBox="0 0 360 60" class="chart">
<text x="0" y="59" class="axis">0</text>
<text x="0" y="10" class="axis">1</text>
<text x="320" y="59" class="axis">360 hue</text>
<polyline id="chartB" fill="none" stroke="#0074d9" stroke-width="1" 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: 10px sans-serif;}
#labelOpt { margin-top: 20px }
JavaScript
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)];
}
function hsv2rgb_wiki(h,s,v) {
let c =v*s;
let k = h/60;
let x = c*(1 - Math.abs(k%2-1));
let r1 = g1 = b1 = 0;
if(k>=0 && k<=1) { r1=c; g1=x }
if(k>1 && k<=2) { r1=x; g1=c }
if(k>2 && k<=3) { g1=c; b1=x }
if(k>3 && k<=4) { g1=x; b1=c }
if(k>4 && k<=5) { r1=x; b1=c }
if(k>5 && k<=6) { r1=c; b1=x }
let m = v-c;
return [r1+m,g1+m,b1+m]
}
// ----------------------------
// TEST code
// ----------------------------
$ = x=>document.querySelector(x);
function calcMaxError() {
s = colorSat;
v = colorVal;
err = [];
for(let h=0; h<361; h++) {
o = hsv2rgb(h,s,v);
w = hsv2rgb_wiki(h,s,v);
e = Math.max( Math.abs(o[0]-w[0]), Math.abs(o[1]-w[1]), Math.abs(o[2]-w[2]));
err.push({ h, e });
}
err.sort((a,b)=> b.e-a.e);
$('#error').innerHTML = `err=${err[0].e} for hue=${err[0].h}°`
}
function setColors(h,s,l) {
opt = hsv2rgb(h,s,l);
wiki = hsv2rgb_wiki(h,s,l);
chartAA( h, opt[colorIdx]);
chartBB( h, wiki[colorIdx]);
$('#colA').insertAdjacentHTML('beforeend', `<div class="color" style="background: ${rgbToStyle(opt)}"</div>`);
$('#colB').insertAdjacentHTML('beforeend',`<div class="color" style="background: ${rgbToStyle(wiki)}"</div>`);
}
function refresh() {
s = colorSat;
l = colorVal;
$('#colA').innerHTML = "opt";
$('#colB').innerHTML = "wiki";
chartAA(0,0,1); chartBB(0,0,1); // clean charts
let info = ['R','G','B'][colorIdx]
+ ` (val: ${colorVal}, sat: ${colorSat})`;
$('#labelWiki').innerHTML = "Wiki " + info;
$('#labelOpt').innerHTML = "Optimized " + info;
for(let h=0; h<361; h++) setColors(h,s,l);
calcMaxError();
}
function rgbToStyle(c) {
return `rgb(${c[0]*255},${c[1]*255},${c[2]*255})`
}
function...