我正在寻找一个算法之间的HSL颜色转换为RGB。

在我看来,HSL不是很广泛地使用,所以我没有太多的运气寻找一个转换器。


当前回答

简短而精确- JS

使用这个JS代码(更多:rgb2hsl, hsv2rgb rgb2hsv和hsl2hsv) - php版本在这里

// input: h as an angle in [0,360] and s,l in [0,1] - output: r,g,b in [0,1]
function hsl2rgb(h,s,l) 
{
   let a=s*Math.min(l,1-l);
   let f= (n,k=(n+h/30)%12) => l - a*Math.max(Math.min(k-3,9-k,1),-1);
   return [f(0),f(8),f(4)];
}   

// oneliner version 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)]; // r,g,b are in [0-1], result e.g. #0812fa. let rgb2hex = (r,g,b) => "#" + [r,g,b].map(x=>Math.round(x*255).toString(16).padStart(2,0) ).join(''); console.log(`hsl: (30,0.2,0.3) --> rgb: (${hsl2rgb(30,0.2,0.3)}) --> hex: ${rgb2hex(...hsl2rgb(30,0.2,0.3))}`); // --------------- // UX // --------------- rgb= [0,0,0]; hs= [0,0,0]; let $ = x => document.querySelector(x); 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(', ') hh = rgb2hex(...rgb); tr = `RGB: ${rr}` th = `HSL: ${hs.map((x,i)=>i? (x*100).toFixed(2)+'%':x|0).join(', ')}` thh= `HEX: ${hh}` $('.box').style.backgroundColor=`rgb(${rr})`; $('.infoRGB').innerHTML=`${tr}`; $('.infoHS').innerHTML =`${th}\n${thh}`; $('#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; } 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]; } 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>

以下是我在wiki +错误分析中发现并精确描述的公式,

其他回答

维基百科上关于HSL和HSV的文章包含了一些公式。计算有点棘手,所以看一下现有的实现可能会有用。

当你需要RGB到HSV,反之亦然:

function rgbToHsv(r, g, b)
{
    r /= 255, g /= 255, b /= 255;

    var min = Math.min(r, g, b),
    max = Math.max(r, g, b),
    delta = max - min,
    h = 0, s = 0, v = max;

    if (min != max)
    {
        s = (delta / max);

        switch (max)
        {
            case r: h = (g - b) / delta + (g < b ? 6 : 0); break;
            case g: h = (b - r) / delta + 2; break;
            case b: h = (r - g) / delta + 4; break;
        }

        h /= 6;
    }

    return [h, s, v];
}

function hsvToRgb(h, s, v)
{
    var step = h / (1 / 6),
    pos = step - Math.floor(step), // the hue position within the current step
    m = (Math.floor(step) % 2) ? (1 - pos) * v : pos * v, // mix color value adjusted to the brightness(v)
    max = 1 * v,
    min = (1 - s) * v,
    med = m + ((1 - s) * (v - m)),
    r, g, b;

    switch (Math.floor(step))
    {
        case 0:
            r = max;
            g = med;
            b = min;
            break;
        case 1:
            r = med;
            g = max;
            b = min;
            break;
        case 2:
            r = min;
            g = max;
            b = med;
            break;
        case 3:
            r = min;
            g = med;
            b = max;
            break;
        case 4:
            r = med;
            g = min;
            b = max;
            break;
        case 5:
            r = max;
            g = min;
            b = med;
            break;
    }

    return [Math.round(r * 255), Math.round(g * 255), Math.round(b * 255)];
}

由于circuitpython不支持colorsys(或目前移植到),如果你试图在树莓派上处理这个转换,下面的工作(受制于本线程其他地方提到的舍入精度限制):

def hslToRgb (h, s, l): #in range 0-1 for h,s,l
    if s == 0:
        r = g = b = l #achromatic
    else:
        def hue2rgb(p, q, t):
            if t < 0: t += 1
            if t > 1: t -= 1
            if t < 1.0 / 6.0: return p + (q - p) * 6 * t
            if t < 1.0 / 2.0: return q
            if t < 2.0 / 3.0: return p + (q - p) * ((2.0 / 3.0) - t) * 6
            return p
        if l < 0.5:
            q = l * (1 + s)
        else:
            q = l + s - l * s
        p = 2 * l - q
        r = hue2rgb(p, q, h + 1.0/3.0)
        g = hue2rgb(p, q, h)
        b = hue2rgb(p, q, h - 1.0/3.0)
    return [round(r * 255), round(g * 255), round(b * 255)]

我是这样做的,这很容易记住,把RGB想象成一个轮子上的三条辐条,相隔120度。

H = hue (0-360)
S = saturation (0-1)
L = luminance (0-1)

R1 = SIN( H ) * L 
G1 = SIN( H + 120 ) * L 
B1 = SIN( H + 240 ) * L 

棘手的部分是饱和度,即缩小到这三者的平均值。

AVERAGE = (R1 + G1 + B1) / 3 

R2 = ((R1 - AVERAGE) * S) + AVERAGE 
G2 = ((G1 - AVERAGE) * S) + AVERAGE 
B2 = ((B1 - AVERAGE) * S) + AVERAGE 

RED = R2 * 255 
GREEN = G2 * 255 
BLUE = B2 * 255 

Java版本:

/*
Converts color from HSL/A format to RGB/A format
0 <= h <= 360
0 <= s, l, a <= 1
Based on: https://en.wikipedia.org/wiki/HSL_and_HSV#:~:text=%5Bedit%5D-,HSL%20to%20RGB%5Bedit%5D,-Given%20a%20color
 */
public RGB toRGB(double h, double s, double l, Double a) {
    double c = (1 - Math.abs(2 * l - 1)) * s;
    double x = c * (1 - Math.abs((h / 60) % 2 - 1));
    double m = l - c / 2;
    int[] RGBTag = Arrays.stream(getRGBTag(c, x)).mapToInt(e -> (int)Math.round((e + m) * 255)).toArray();
    return RGB(RGBTag[0], RGBTag[1], RGBTag[2], a);

}

private double[] getRGBTag(double c, double x) {
    if (h < 60) {
        return new double[] {c, x, 0};
    } else if (h < 120) {
        return new double[] {x, c, 0};
    } else if (h < 180) {
        return new double[] {0, c, x};
    } else if (h < 240) {
        return new double[] {0, x, c};
    } else if (h < 300) {
        return new double[] {x, 0, c};
    }
    return new double[] {c, 0, x};
}