JS实现RGB,HSL,HSB相互转换

前言

最近呢,在写色彩选择器小插件的时候需要用到RGB,HSL,HSB相互转换的一些东西,就想着好好整理一下这方面的内容,顺便用js实现一下三者之间的转换,通过对色彩转换的学习,对平时整整ps,摄影也是有一定的基础帮助的,恩!

色彩模型

关于色彩模型的相关知识,主要是整理了别人的分享主要参考了色彩模型介绍HSL,HSV维基百科上的内容,这里简单做下整理

RGB模型

RGB模型也称为加色法混色模型,以RGB三色光互相叠加来实现混色的方法。
它是一种以硬件为导向的色彩模型,它描述了显示器的电子枪打在Red红、Green绿、Blue蓝三色发光极上的显色方式,因而适合于显示器等发光体的显示。
rgb.png

  • 优点:对机器友好
  • 缺点:对用户很不友好

HSL

HSL色彩的表述方式是:H(hue)色相,S(saturation)饱和度,以及L(lightness)亮度。

HSL的H(hue)分量,代表的是人眼所能感知的颜色范围,这些颜色分布在一个平面的色相环上,取值范围是0°到360°的圆心角,每个角度可以代表一种颜色。色相值的意义在于,我们可以在不改变光感的情况下,通过旋转色相环来改变颜色。在实际应用中,我们需要记住色相环上的六大主色,用作基本参照:360°/0°红、60°黄、120°绿、180°青、240°蓝、300°洋红,它们在色相环上按照60°圆心角的间隔排列。
h.png

HSL的S(saturation)分量,指的是色彩的饱和度,它用0%至100%的值描述了相同色相、明度下色彩纯度的变化。数值越大,颜色中的灰色越少,颜色越鲜艳,呈现一种从理性(灰度)到感性(纯色)的变化。
s.png
HSL的L(lightness)分量,指的是色彩的明度,作用是控制色彩的明暗变化。它同样使用了0%至100%的取值范围。数值越小,色彩越暗,越接近于黑色;数值越大,色彩越亮,越接近于白色。
l.png

HSV

HSV色彩的表述方式是:H(hue)色相,S(saturation)饱和度,以及V(Value)明度。

与HSL有些类似,但也有不同,二者在数学上都是圆柱,但HSV(色相,饱和度,明度)在概念上可以被认为是颜色的倒圆锥体(黑点在下顶点,白色在上底面圆心),HSL在概念上表示了一个双圆锥体和圆球体(白色在上顶点,黑色在下顶点,最大横切面的圆心是半程灰色)。注意尽管在HSL和HSV中“色相”指称相同的性质,它们的“饱和度”的定义是明显不同的。
comp.png

HSL和HSV对比

HSL类似于HSV。对于一些人,HSL更好的反映了“饱和度”和“亮度”作为两个独立参数的直觉观念,但是在某些情况时,它的饱和度定义是错误的,因为非常柔和的几乎白色的颜色在HSL可以被定义为是完全饱和的。对于HSV还是HSL更适合于人类用户界面是有争议的。

  • 在HSL中,饱和度分量总是从完全饱和色变化到等价的灰色(在HSV中,在极大值V的时候,饱和度从全饱和色变化到白色,这可以被认为是反直觉的)。
  • 在HSL中,亮度跨越从黑色过选择的色相到白色的完整范围(在HSV中,V分量只走一半行程,从黑到选择的色相)。
    在软件中,通常以一个线性或圆形色相选择器和在其中为选定的色相选取饱和度和明度/亮度的一个二维区域(通常为方形或三角形)形式提供给用户基于色相的颜色模型。这种时候,HSL和HSV都可以使用,但HSV传统上更常用。HSL,HSV维基百科给了一些例子,这里就不再赘述。

相互转换JS代码实现

根据转换公式(参考转换公式转换公式2),可以对将RGB转换成HSL或HSB,也可用HSL或HSB转成成RGB,贴上代码。

转换公式(来自维基百科)

p1.png
p2.png
p3.png

rgb转hsl

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
// r,g,b范围为[0,255],转换成h范围为[0,360]
// s,l为百分比形式,范围是[0,100],可根据需求做相应调整
function rgbtohsl(r,g,b){
r=r/255;
g=g/255;
b=b/255;
var min=Math.min(r,g,b);
var max=Math.max(r,g,b);
var l=(min+max)/2;
var difference = max-min;
var h,s,l;
if(max==min){
h=0;
s=0;
}else{
s=l>0.5?difference/(2.0-max-min):difference/(max+min);
switch(max){
case r: h=(g-b)/difference+(g < b ? 6 : 0);break;
case g: h=2.0+(b-r)/difference;break;
case b: h=4.0+(r-g)/difference;break;
}
h=Math.round(h*60);
}
s=Math.round(s*100);//转换成百分比的形式
l=Math.round(l*100);
return [h,s,l];
}
console.log(rgbtohsl(2,5,10)); //[218, 67, 2]

rgb转hsv

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
// r,g,b范围为[0,255],转换成h范围为[0,360]
// s,v为百分比形式,范围是[0,100],可根据需求做相应调整
function rgbtohsv(r,g,b){
r=r/255;
g=g/255;
b=b/255;
var h,s,v;
var min=Math.min(r,g,b);
var max=v=Math.max(r,g,b);
var l=(min+max)/2;
var difference = max-min;
if(max==min){
h=0;
}else{
switch(max){
case r: h=(g-b)/difference+(g < b ? 6 : 0);break;
case g: h=2.0+(b-r)/difference;break;
case b: h=4.0+(r-g)/difference;break;
}
h=Math.round(h*60);
}
if(max==0){
s=0;
}else{
s=1-min/max;
}
s=Math.round(s*100);
v=Math.round(v*100);
return [h,s,v];
}

hsl转rgb

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
//输入的h范围为[0,360],s,l为百分比形式的数值,范围是[0,100]
//输出r,g,b范围为[0,255],可根据需求做相应调整
function hsltorgb(h,s,l){
var h=h/360;
var s=s/100;
var l=l/100;
var rgb=[];
if(s==0){
rgb=[Math.round(l*255),Math.round(l*255),Math.round(l*255)];
}else{
var q=l>=0.5?(l+s-l*s):(l*(1+s));
var p=2*l-q;
var tr=rgb[0]=h+1/3;
var tg=rgb[1]=h;
var tb=rgb[2]=h-1/3;
for(var i=0; i<rgb.length;i++){
var tc=rgb[i];
console.log(tc);
if(tc<0){
tc=tc+1;
}else if(tc>1){
tc=tc-1;
}
switch(true){
case (tc<(1/6)):
tc=p+(q-p)*6*tc;
break;
case ((1/6)<=tc && tc<0.5):
tc=q;
break;
case (0.5<=tc && tc<(2/3)):
tc=p+(q-p)*(4-6*tc);
break;
default:
tc=p;
break;
}
rgb[i]=Math.round(tc*255);
}
}
return rgb;
}

hsb转rgb

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
//输入的h范围为[0,360],s,l为百分比形式的数值,范围是[0,100]
//输出r,g,b范围为[0,255],可根据需求做相应调整
function hsvtorgb(h,s,v){
var s=s/100;
var v=v/100;
var h1=Math.floor(h/60) % 6;
var f=h/60-h1;
var p=v*(1-s);
var q=v*(1-f*s);
var t=v*(1-(1-f)*s);
var r,g,b;
switch(h1){
case 0:
r=v;
g=t;
b=p;
break;
case 1:
r=q;
g=v;
b=p;
break;
case 2:
r=p;
g=v;
b=t;
break;
case 3:
r=p;
g=q;
b=v;
break;
case 4:
r=t;
g=p;
b=v;
break;
case 5:
r=v;
g=p;
b=q;
break;
}
return [Math.round(r*255),Math.round(g*255),Math.round(b*255)];
}

参考
http://cdc.tencent.com/2011/05/09/%E8%89%B2%E7%94%9F%E5%BF%83%E4%B8%AD%EF%BC%9A%E4%BA%BA%E6%80%A7%E5%8C%96%E7%9A%84hsl%E6%A8%A1%E5%9E%8B/#
https://en.wikipedia.org/wiki/HSL_and_HSV
https://zh.wikipedia.org/wiki/HSL%E5%92%8CHSV%E8%89%B2%E5%BD%A9%E7%A9%BA%E9%97%B4