Почему этот код Javascript RGB to HSL не работает?
Я нашел этот сценарий RGB to HSL на http://www.mjijackson.com/2008/02/rgb-to-hsl-and-rgb-to-hsv-color-model-conversion-algorithms-in-javascript. Я не могу найти других маленьких приличных. Проблема в том, что этот код даже не работает. Кто-нибудь знает почему? (Я немного знаю цветовую математику, но, может быть, она возвращает дополнительное?)
function rgbToHsl(r, g, b){
r /= 255, g /= 255, b /= 255;
var max = Math.max(r, g, b), min = Math.min(r, g, b);
var h, s, l = (max + min) / 2;
if(max == min){
h = s = 0; // achromatic
}else{
var d = max - min;
s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
switch(max){
case r: h = (g - b) / d + (g < b ? 6 : 0); break;
case g: h = (b - r) / d + 2; break;
case b: h = (r - g) / d + 4; break;
}
h /= 6;
}
return [h, s, l];
}
Изменить: когда я бегу rgbToHsl(126,210,22)
это дает мне [ .24, .81, .45 ], который является HSL для оранжевого цвета.
3 ответа
Результирующий массив HSV должен интерпретироваться как три дроби. В некоторых программах, если вы хотите выразить HSV в виде целых чисел, вы умножаете значение "H" на 360, а значения "S" и "V" на 100. Значение HSV, которое вы указываете для RGB зеленого оттенка [126, 210, 22] - ВПГ [87, 81, 45] в целых числах. Вы можете изменить функцию, чтобы она возвращала такие целые числа, если вы хотите:
function rgbToHsl(r, g, b){
r /= 255, g /= 255, b /= 255;
var max = Math.max(r, g, b), min = Math.min(r, g, b);
var h, s, l = (max + min) / 2;
if(max == min){
h = s = 0; // achromatic
}else{
var d = max - min;
s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
switch(max){
case r: h = (g - b) / d + (g < b ? 6 : 0); break;
case g: h = (b - r) / d + 2; break;
case b: h = (r - g) / d + 4; break;
}
h /= 6;
}
return [Math.floor(h * 360), Math.floor(s * 100), Math.floor(l * 100)];
}
[править] тем не менее, он по-прежнему дает мне что-то с яркостью ("L" или "V"), что слишком темно; Гимп говорит, что значение ВПГ должно быть [90, 80, 82] или в дробных выражениях [.20,.80,.82].
[другое редактирование] Ну, одна проблема может заключаться в том, что HSL и HSV - это разные схемы... все еще оглядываемся
Хорошо, если кто-то хочет, чтобы RGB перешел на HSV (как, например, вы увидите в Gimp), вот версия этого:
function rgbToHsv(r, g, b) {
var
min = Math.min(r, g, b),
max = Math.max(r, g, b),
delta = max - min,
h, s, v = max;
v = Math.floor(max / 255 * 100);
if ( max != 0 )
s = Math.floor(delta / max * 100);
else {
// black
return [0, 0, 0];
}
if( r == max )
h = ( g - b ) / delta; // between yellow & magenta
else if( g == max )
h = 2 + ( b - r ) / delta; // between cyan & yellow
else
h = 4 + ( r - g ) / delta; // between magenta & cyan
h = Math.floor(h * 60); // degrees
if( h < 0 ) h += 360;
return [h, s, v];
}
Попробуйте это ( вики, анализ ошибок, больше: hsl2rgb, rgb2hsv, hsv2rgb и sl22sv):
// in: r,g,b in [0,1], out: h in [0,360) and s,v in [0,1]
function rgb2hsl(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(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];
}
console.log(`rgb: (0.36,0.3,0.24) --> hsl: (${rgb2hsl(0.36,0.3,0.24)})`);
// ---------------
// UX
// ---------------
rgb= [0,0,0];
hs= [0,0,0];
let $ = x => document.querySelector(x);
let hsl2rgb = (h,s,l, a=s*Math.min(l,1-l), f= (n,k=(n+h/30)%12) => l - a*Math.max(Math.min(k-3,9-k,1),-1)) => [f(0),f(8),f(4)];
function changeRGB(i,e) {
rgb[i]=e.target.value/255;
hs = rgb2hsl(...rgb);
refresh();
}
function changeHS(i,e) {
hs[i]=e.target.value/(i?255:1);
rgb= hsl2rgb(...hs);
refresh();
}
function refresh() {
rr = rgb.map(x=>x*255|0).join(', ')
tr = `RGB: ${rr}`
th = `HSL: ${hs.map((x,i)=>i? (x*100).toFixed(2)+'%':x|0).join(', ')}`
$('.box').style.backgroundColor=`rgb(${rr})`;
$('.infoRGB').innerHTML=`${tr}`;
$('.infoHS').innerHTML =`${th}`;
$('#r').value=rgb[0]*255;
$('#g').value=rgb[1]*255;
$('#b').value=rgb[2]*255;
$('#h').value=hs[0];
$('#s').value=hs[1]*255;
$('#l').value=hs[2]*255;
}
refresh();
.box {
width: 50px;
height: 50px;
margin: 20px;
}
body {
display: flex;
}
<div>
<input id="r" type="range" min="0" max="255" oninput="changeRGB(0,event)">R<br>
<input id="g" type="range" min="0" max="255" oninput="changeRGB(1,event)">G<br>
<input id="b" type="range" min="0" max="255" oninput="changeRGB(2,event)">B<br>
<pre class="infoRGB"></pre>
</div>
<div>
<div class="box hsl"></div>
</div>
<div>
<input id="h" type="range" min="0" max="360" oninput="changeHS(0,event)">H<br>
<input id="s" type="range" min="0" max="255" oninput="changeHS(1,event)">S<br>
<input id="l" type="range" min="0" max="255" oninput="changeHS(2,event)">L<br>
<pre class="infoHS"></pre><br>
</div>
Функция ниже конвертирует RGB
цвет в цветовой тон насыщенности цвета, как в палитре цветов Photoshop, результаты находятся в следующих диапазонах:
- Оттенок 0-360 (градусы)
- Насыщенность: 0-100 (%)
- Яркость: 0-100 (%)
Я до сих пор не понимаю, почему люди используют термин HSV
(Значение насыщенности оттенка) вместо HSB
(Hue Saturation Brightness), в любом случае это вопрос терминологии, результаты одинаковы
//Converts to color HSB object (code from here http://www.csgnetwork.com/csgcolorsel4.html with some improvements)
function rgb2hsb(r, g, b)
{
r /= 255; g /= 255; b /= 255; // Scale to unity.
var minVal = Math.min(r, g, b),
maxVal = Math.max(r, g, b),
delta = maxVal - minVal,
HSB = {hue:0, sat:0, bri:maxVal},
del_R, del_G, del_B;
if( delta !== 0 )
{
HSB.sat = delta / maxVal;
del_R = (((maxVal - r) / 6) + (delta / 2)) / delta;
del_G = (((maxVal - g) / 6) + (delta / 2)) / delta;
del_B = (((maxVal - b) / 6) + (delta / 2)) / delta;
if (r === maxVal) {HSB.hue = del_B - del_G;}
else if (g === maxVal) {HSB.hue = (1 / 3) + del_R - del_B;}
else if (b === maxVal) {HSB.hue = (2 / 3) + del_G - del_R;}
if (HSB.hue < 0) {HSB.hue += 1;}
if (HSB.hue > 1) {HSB.hue -= 1;}
}
HSB.hue *= 360;
HSB.sat *= 100;
HSB.bri *= 100;
return HSB;
}
Пример использования:
var hsb = rgb2hsb(126,210,22);
alert("hue = " + hsb.hue + "saturation = " + hsb.sat + "brightness = " + hsb.bri);
Вам нужно перейти в формат hsl так же, как hsl(155,100%,30%)
, который можно использовать в HTML.
//this change hsl to : "hsl(155,100%,30%)"
function hsl2str({h,s,l,a=1}) {
return "hsl("+h+","+s*100+"%,"+l*100+"%,"+a+")";
}
//for html, the h is 0-360, so you need this function
function rgb2hsl({r,g,b,a=1}) {
r/=255,g/=255,b/=255;
var max=Math.max(r,g,b),min=Math.min(r,g,b);
var h,s,l=(max+min)/2;
if(max==min) {
h=s=0; // achromatic
} else {
var d=max-min;
s=l>0.5? d/(2-max-min):d/(max+min);
switch(max) {
case r: h=(g-b)/d+(g<b? 6:0); break;
case g: h=(b-r)/d+2; break;
case b: h=(r-g)/d+4; break;
}
}
return {h: h*60,s,l,a};
}