【问题标题】:HSL to RGB color conversionHSL 到 RGB 颜色转换
【发布时间】:2011-01-22 03:09:44
【问题描述】:

我正在寻找一种将 HSL 颜色转换为 RGB 的算法。

在我看来,HSL 的使用不是很广泛,所以我在寻找转换器时运气不佳。

【问题讨论】:

标签: algorithm colors rgb hsl


【解决方案1】:

Garry Tan 在 his blog 上发布了一个 Javascript 解决方案(他将其归因于现已解散的 mjijackson.com、but is archived herethe original author has a gist - 感谢 user2441511)。

代码在下面重新发布:

HSL 转 RGB:

/**
 * Converts an HSL color value to RGB. Conversion formula
 * adapted from http://en.wikipedia.org/wiki/HSL_color_space.
 * Assumes h, s, and l are contained in the set [0, 1] and
 * returns r, g, and b in the set [0, 255].
 *
 * @param   {number}  h       The hue
 * @param   {number}  s       The saturation
 * @param   {number}  l       The lightness
 * @return  {Array}           The RGB representation
 */
function hslToRgb(h, s, l){
    var r, g, b;

    if(s == 0){
        r = g = b = l; // achromatic
    }else{
        var hue2rgb = function hue2rgb(p, q, t){
            if(t < 0) t += 1;
            if(t > 1) t -= 1;
            if(t < 1/6) return p + (q - p) * 6 * t;
            if(t < 1/2) return q;
            if(t < 2/3) return p + (q - p) * (2/3 - t) * 6;
            return p;
        }

        var q = l < 0.5 ? l * (1 + s) : l + s - l * s;
        var p = 2 * l - q;
        r = hue2rgb(p, q, h + 1/3);
        g = hue2rgb(p, q, h);
        b = hue2rgb(p, q, h - 1/3);
    }

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

RGB 转 HSL:

/**
 * Converts an RGB color value to HSL. Conversion formula
 * adapted from http://en.wikipedia.org/wiki/HSL_color_space.
 * Assumes r, g, and b are contained in the set [0, 255] and
 * returns h, s, and l in the set [0, 1].
 *
 * @param   {number}  r       The red color value
 * @param   {number}  g       The green color value
 * @param   {number}  b       The blue color value
 * @return  {Array}           The HSL representation
 */
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];
}

【讨论】:

  • 我正在尝试将其用于项目,但我的结果仅以灰度显示。这是 HSLRGB 的限制吗?维基百科文章似乎建议对所有 3 个频道仅设置一个值。
  • 我想指出的是,使用Math.round 会在刻度的低端和高端(0 和 255 的值)处引入小的误差。不在范围末端的值可以向上或向下舍入以达到它们的值,但值只能向下舍入到 0 或最多 255。这意味着映射到 0 和 255 的值的范围恰好是其他值的一半。要解决此问题,请改用以下公式:min(floor(val*256),255)。这使得映射几乎完美。
  • 另外,如果你得到灰度值,可能是因为使用h + 1/3h - 1/3的行。在许多语言中,这使用整数除法,其中1/3 为零。要获得正确的结果,请改用浮点文字,即:h + 1.0/3.0.
  • RGB 转 HSL 功能不起作用。这是一个不工作的例子:jsfiddle.net/fs5L02k0/2,这里是函数,固定的jsfiddle.net/t5nq6jjc/1——公式来自:nl.wikipedia.org/wiki/…
  • @SubJunk - 阅读代码中的描述:输入hsl的值应该在0到1之间。你需要调用hslToRgb(0.447 /*161/360*/, 0.55, 0.63)
【解决方案2】:

找到了最简单的方法,python到rescue:D

colorsys.hls_to_rgb(h, l, s)

将颜色从 HLS 坐标转换为 RGB 坐标。

【讨论】:

  • 我不敢相信 Python 中有这样一个标准模块!这真的救了我。我在 Wikipedia 的 HSL 条目中的转换算法苦苦挣扎了 2 个小时。似乎算法无法得到正确的输出。
  • Ruby 等效项:rubydoc.info/gems/color/1.8/Color/RGB 例如Color::HSL.new(40,50,60).to_rgb
  • 我使用brython在浏览器中获取颜色选择器,这正是我所需要的!
【解决方案3】:

Mohsen 代码的 Java 实现

请注意,所有整数都声明为浮点数(即 1f)并且必须为浮点数,否则您将选择灰色。

HSL 转 RGB

 /**
 * Converts an HSL color value to RGB. Conversion formula
 * adapted from http://en.wikipedia.org/wiki/HSL_color_space.
 * Assumes h, s, and l are contained in the set [0, 1] and
 * returns r, g, and b in the set [0, 255].
 *
 * @param h       The hue
 * @param s       The saturation
 * @param l       The lightness
 * @return int array, the RGB representation
 */
public static int[] hslToRgb(float h, float s, float l){
    float r, g, b;

    if (s == 0f) {
        r = g = b = l; // achromatic
    } else {
        float q = l < 0.5f ? l * (1 + s) : l + s - l * s;
        float p = 2 * l - q;
        r = hueToRgb(p, q, h + 1f/3f);
        g = hueToRgb(p, q, h);
        b = hueToRgb(p, q, h - 1f/3f);
    }
    int[] rgb = {to255(r), to255(g), to255(b)};
    return rgb;
}
public static int to255(float v) { return (int)Math.min(255,256*v); }

/** Helper method that converts hue to rgb */
public static float hueToRgb(float p, float q, float t) {
    if (t < 0f)
        t += 1f;
    if (t > 1f)
        t -= 1f;
    if (t < 1f/6f)
        return p + (q - p) * 6f * t;
    if (t < 1f/2f)
        return q;
    if (t < 2f/3f)
        return p + (q - p) * (2f/3f - t) * 6f;
    return p;
}

RGB 转 HSL

/**
 * Converts an RGB color value to HSL. Conversion formula
 * adapted from http://en.wikipedia.org/wiki/HSL_color_space.
 * Assumes pR, pG, and bpBare contained in the set [0, 255] and
 * returns h, s, and l in the set [0, 1].
 *
 * @param pR       The red color value
 * @param pG       The green color value
 * @param pB       The blue color value
 * @return float array, the HSL representation
 */
public static float[] rgbToHsl(int pR, int pG, int pB) {
    float r = pR / 255f;
    float g = pG / 255f;
    float b = pB / 255f;

    float max = (r > g && r > b) ? r : (g > b) ? g : b;
    float min = (r < g && r < b) ? r : (g < b) ? g : b;

    float h, s, l;
    l = (max + min) / 2.0f;

    if (max == min) {
        h = s = 0.0f;
    } else {
        float d = max - min;
        s = (l > 0.5f) ? d / (2.0f - max - min) : d / (max + min);

        if (r > g && r > b)
            h = (g - b) / d + (g < b ? 6.0f : 0.0f);

        else if (g > b)
            h = (b - r) / d + 2.0f;

        else
            h = (r - g) / d + 4.0f;

        h /= 6.0f;
    }

    float[] hsl = {h, s, l};
    return hsl;
}

【讨论】:

【解决方案4】:

HSL and HSV on wikipedia 的文章包含一些公式。计算有点棘手,所以看看existing implementations 可能会有用。

【讨论】:

  • +1 很好的答案。该链接正是我想要的。接受的答案似乎只对 python 有用。
【解决方案5】:

如果您正在寻找绝对符合 HSL 和 RGB 的 CSS 语义的东西,您可以使用the algorithm specified in the CSS 3 specification,其内容如下:

HOW TO RETURN hsl.to.rgb(h, s, l): 
   SELECT: 
      l<=0.5: PUT l*(s+1) IN m2
      ELSE: PUT l+s-l*s IN m2
   PUT l*2-m2 IN m1
   PUT hue.to.rgb(m1, m2, h+1/3) IN r
   PUT hue.to.rgb(m1, m2, h    ) IN g
   PUT hue.to.rgb(m1, m2, h-1/3) IN b
   RETURN (r, g, b)

HOW TO RETURN hue.to.rgb(m1, m2, h): 
   IF h<0: PUT h+1 IN h
   IF h>1: PUT h-1 IN h
   IF h*6<1: RETURN m1+(m2-m1)*h*6
   IF h*2<1: RETURN m2
   IF h*3<2: RETURN m1+(m2-m1)*(2/3-h)*6
   RETURN m1

我相信这是这里其他一些答案的来源。

【讨论】:

    【解决方案6】:

    最短但精确 - JS

    使用这个JS代码(更多:rgb2hslhsv2rgbrgb2hsvhsl2hsv)-php版本here

    // 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 + 错误analysis 中发现并精确描述的公式,

    【讨论】:

    • 优秀的答案。我将它翻译成 Python 用于一个小项目,效果很好。
    【解决方案7】:

    Mohsen 回答中的 C# 代码。

    如果其他人想要的话,这里是 Mohsen 在 C# 中的回答中的代码。注意:Color 是一个自定义类,Vector4 来自 OpenTK。两者都很容易用您选择的其他东西替换。

    Hsl 转 Rgba

    /// <summary>
    /// Converts an HSL color value to RGB.
    /// Input: Vector4 ( X: [0.0, 1.0], Y: [0.0, 1.0], Z: [0.0, 1.0], W: [0.0, 1.0] )
    /// Output: Color ( R: [0, 255], G: [0, 255], B: [0, 255], A: [0, 255] )
    /// </summary>
    /// <param name="hsl">Vector4 defining X = h, Y = s, Z = l, W = a. Ranges [0, 1.0]</param>
    /// <returns>RGBA Color. Ranges [0, 255]</returns>
    public static Color HslToRgba(Vector4 hsl)
    {
        float r, g, b;
    
        if (hsl.Y == 0.0f)
            r = g = b = hsl.Z;
    
        else
        {
            var q = hsl.Z < 0.5f ? hsl.Z * (1.0f + hsl.Y) : hsl.Z + hsl.Y - hsl.Z * hsl.Y;
            var p = 2.0f * hsl.Z - q;
            r = HueToRgb(p, q, hsl.X + 1.0f / 3.0f);
            g = HueToRgb(p, q, hsl.X);
            b = HueToRgb(p, q, hsl.X - 1.0f / 3.0f);
        }
    
        return new Color((int)(r * 255), (int)(g * 255), (int)(b * 255), (int)(hsl.W * 255));
    }
    
    // Helper for HslToRgba
    private static float HueToRgb(float p, float q, float t)
    {
        if (t < 0.0f) t += 1.0f;
        if (t > 1.0f) t -= 1.0f;
        if (t < 1.0f / 6.0f) return p + (q - p) * 6.0f * t;
        if (t < 1.0f / 2.0f) return q;
        if (t < 2.0f / 3.0f) return p + (q - p) * (2.0f / 3.0f - t) * 6.0f;
        return p;
    }
    

    Rgba 转 Hsl

    /// <summary>
    /// Converts an RGB color value to HSL.
    /// Input: Color ( R: [0, 255], G: [0, 255], B: [0, 255], A: [0, 255] )
    /// Output: Vector4 ( X: [0.0, 1.0], Y: [0.0, 1.0], Z: [0.0, 1.0], W: [0.0, 1.0] )
    /// </summary>
    /// <param name="rgba"></param>
    /// <returns></returns>
    public static Vector4 RgbaToHsl(Color rgba)
    {
        float r = rgba.R / 255.0f;
        float g = rgba.G / 255.0f;
        float b = rgba.B / 255.0f;
    
        float max = (r > g && r > b) ? r : (g > b) ? g : b;
        float min = (r < g && r < b) ? r : (g < b) ? g : b;
    
        float h, s, l;
        h = s = l = (max + min) / 2.0f;
    
        if (max == min)
            h = s = 0.0f;
    
        else
        {
            float d = max - min;
            s = (l > 0.5f) ? d / (2.0f - max - min) : d / (max + min);
    
            if (r > g && r > b)
                h = (g - b) / d + (g < b ? 6.0f : 0.0f);
    
            else if (g > b)
                h = (b - r) / d + 2.0f;
    
            else
                h = (r - g) / d + 4.0f;
    
            h /= 6.0f;
        }
    
        return new Vector4(h, s, l, rgba.A / 255.0f);
    }
    

    【讨论】:

    【解决方案8】:

    Chris's C# Code的php实现

    同样来自here,它很好地解释了它的数学原理。

    这基本上是一堆转换为 HSL(Hue Saturation Lightness)的函数

    在 PHP 5.6.15 上测试和工作

    TL;DR:完整代码可以在here on Pastebin找到。


    十六进制转 HSL

    输入:十六进制颜色,格式:[#]0f4 或 [#]00ff44(井号可选)
    输出:HSL 度数、百分比、百分比

    /**
     * Input: hex color
     * Output: hsl(in ranges from 0-1)
     * 
     * Takes the hex, converts it to RGB, and sends
     * it to RGBToHsl.  Returns the output.
     * 
    */
    function hexToHsl($hex) {
        $r = "";
        $g = "";
        $b = "";
    
        $hex = str_replace('#', '', $hex);
    
        if (strlen($hex) == 3) {
            $r = substr($hex, 0, 1);
            $r = $r . $r;
            $g = substr($hex, 1, 1);
            $g = $g . $g;
            $b = substr($hex, 2, 1);
            $b = $b . $b;
        } elseif (strlen($hex) == 6) {
            $r = substr($hex, 0, 2);
            $g = substr($hex, 2, 2);
            $b = substr($hex, 4, 2);
        } else {
            return false;
        }
    
        $r = hexdec($r);
        $g = hexdec($g);
        $b = hexdec($b);
    
        $hsl =  rgbToHsl($r,$g,$b);
        return $hsl;
    }
    

    RGB 转 HSL

    输入:RGB 范围 0-255 输出:HSL 度数、百分比、百分比。

    /**
     * 
     *Credits:
     * https://stackoverflow.com/questions/4793729/rgb-to-hsl-and-back-calculation-problems
     * http://www.niwa.nu/2013/05/math-behind-colorspace-conversions-rgb-hsl/
     *
     * Called by hexToHsl by default.
     *
     * Converts an RGB color value to HSL. Conversion formula
     * adapted from http://www.niwa.nu/2013/05/math-behind-colorspace-conversions-rgb-hsl/.
     * Assumes r, g, and b are contained in the range [0 - 255] and
     * returns h, s, and l in the format Degrees, Percent, Percent.
     *
     * @param   Number  r       The red color value
     * @param   Number  g       The green color value
     * @param   Number  b       The blue color value
     * @return  Array           The HSL representation
    */
    function rgbToHsl($r, $g, $b){  
        //For the calculation, rgb needs to be in the range from 0 to 1. To convert, divide by 255 (ff). 
        $r /= 255;
        $g /= 255;
        $b /= 255;
    
        $myMax = max($r, $g, $b);
        $myMin = min($r, $g, $b);
    
        $maxAdd = ($myMax + $myMin);
        $maxSub = ($myMax - $myMin);
    
        //luminence is (max + min)/2
        $h = 0;
        $s = 0;
        $l = ($maxAdd / 2.0);
    
        //if all the numbers are equal, there is no saturation (greyscale).
        if($myMin != $myMax){
            if ($l < 0.5) {
                $s = ($maxSub / $maxAdd);
            } else {
                $s = (2.0 - $myMax - $myMin); //note order of opperations - can't use $maxSub here
                $s = ($maxSub / $s);
            }
    
            //find hue
            switch($myMax){
                case $r: 
                    $h = ($g - $b);
                    $h = ($h / $maxSub);
                    break;
                case $g: 
                    $h = ($b - $r); 
                    $h = ($h / $maxSub);
                    $h = ($h + 2.0);
                    break;
                case $b: 
                    $h = ($r - $g);
                    $h = ($h / $maxSub); 
                    $h = ($h + 4.0);
                    break;
            } 
        }
    
        $hsl = hslToDegPercPerc($h, $s, $l);
        return $hsl;
    }
    

    HSL(0-1 范围)转度、百分比、百分比格式

    对于数学计算,HSL 在 0-1 范围内更容易处理,但对于人类可读性,在度数、百分比、百分比中更容易处理。此函数接受 0-1 范围内的 HSL,并以度数、百分比、百分比返回 HSL。

    /**
     * Input: HSL in ranges 0-1.
     * Output: HSL in format Deg, Perc, Perc.
     * 
     * Note: rgbToHsl calls this function by default.
     * 
     * Multiplies $h by 60, and $s and $l by 100.
     */
    function hslToDegPercPerc($h, $s, $l) {
        //convert h to degrees
        $h *= 60;
    
        if ($h < 0) {
            $h += 360;
        }
    
        //convert s and l to percentage
        $s *= 100;
        $l *= 100;
    
        $hsl['h'] = $h;
        $hsl['s'] = $s;
        $hsl['l'] = $l;
        return $hsl;
    }
    

    HSL(度数、百分比、百分比格式)到 HSL 范围 0-1

    此函数将度数、百分比、百分比格式的 HSL 转换为 0-1 范围,以便于计算。

    /**
     * Input: HSL in format Deg, Perc, Perc
     * Output: An array containing HSL in ranges 0-1
     * 
     * Divides $h by 60, and $s and $l by 100.
     * 
     * hslToRgb calls this by default.
    */
    function degPercPercToHsl($h, $s, $l) { 
        //convert h, s, and l back to the 0-1 range
    
        //convert the hue's 360 degrees in a circle to 1
        $h /= 360;
    
        //convert the saturation and lightness to the 0-1 
        //range by multiplying by 100
        $s /= 100;
        $l /= 100;
    
        $hsl['h'] =  $h;
        $hsl['s'] = $s;
        $hsl['l'] = $l;
    
        return $hsl;
    }
    

    HSL 转 RGB

    输入:HSL,格式为 Degrees, Percent, Percent 输出:255, 255, 255 格式的 RGB。

    /**
     * Converts an HSL color value to RGB. Conversion formula
     * adapted from http://www.niwa.nu/2013/05/math-behind-colorspace-conversions-rgb-hsl/.
     * Assumes h, s, and l are in the format Degrees,
     * Percent, Percent, and returns r, g, and b in 
     * the range [0 - 255].
     *
     * Called by hslToHex by default.
     *
     * Calls: 
     *   degPercPercToHsl
     *   hueToRgb
     *
     * @param   Number  h       The hue value
     * @param   Number  s       The saturation level
     * @param   Number  l       The luminence
     * @return  Array           The RGB representation
     */
    function hslToRgb($h, $s, $l){
        $hsl = degPercPercToHsl($h, $s, $l);
        $h = $hsl['h'];
        $s = $hsl['s'];
        $l = $hsl['l'];
    
        //If there's no saturation, the color is a greyscale,
        //so all three RGB values can be set to the lightness.
        //(Hue doesn't matter, because it's grey, not color)
        if ($s == 0) {
            $r = $l * 255;
            $g = $l * 255;
            $b = $l * 255;
        }
        else {
            //calculate some temperary variables to make the 
            //calculation eaisier.
            if ($l < 0.5) {
                $temp2 = $l * (1 + $s);
            } else {
                $temp2 = ($l + $s) - ($s * $l);
            }
            $temp1 = 2 * $l - $temp2;
    
            //run the calculated vars through hueToRgb to
            //calculate the RGB value.  Note that for the Red
            //value, we add a third (120 degrees), to adjust 
            //the hue to the correct section of the circle for
            //red.  Simalarly, for blue, we subtract 1/3.
            $r = 255 * hueToRgb($temp1, $temp2, $h + (1 / 3));
            $g = 255 * hueToRgb($temp1, $temp2, $h);
            $b = 255 * hueToRgb($temp1, $temp2, $h - (1 / 3));
        }
    
        $rgb['r'] = $r;
        $rgb['g'] = $g;
        $rgb['b'] = $b;
    
        return $rgb;
    }
    

    RGB 色调

    hslToRgb 调用此函数将色调转换为单独的 RGB 值。

    /**
     * Converts an HSL hue to it's RGB value.  
     *
     * Input: $temp1 and $temp2 - temperary vars based on 
     * whether the lumanence is less than 0.5, and 
     * calculated using the saturation and luminence
     * values.
     *  $hue - the hue (to be converted to an RGB 
     * value)  For red, add 1/3 to the hue, green 
     * leave it alone, and blue you subtract 1/3 
     * from the hue.
     *
     * Output: One RGB value.
     *
     * Thanks to Easy RGB for this function (Hue_2_RGB).
     * http://www.easyrgb.com/index.php?X=MATH&$h=19#text19
     *
    */
    function hueToRgb($temp1, $temp2, $hue) {
        if ($hue < 0) { 
            $hue += 1;
        }
        if ($hue > 1) {
            $hue -= 1;
        }
    
        if ((6 * $hue) < 1 ) {
            return ($temp1 + ($temp2 - $temp1) * 6 * $hue);
        } elseif ((2 * $hue) < 1 ) {
            return $temp2;
        } elseif ((3 * $hue) < 2 ) {
            return ($temp1 + ($temp2 - $temp1) * ((2 / 3) - $hue) * 6);
        }
        return $temp1;
    }
    

    HSL 转十六进制

    输入:HSL,格式为 Degrees, Percent, Percent 输出:格式为 00ff22 的十六进制(无井号)。

    转换为 RGB,然后分别转换为十六进制。

    /**
     * Converts HSL to Hex by converting it to 
     * RGB, then converting that to hex.
     * 
     * string hslToHex($h, $s, $l[, $prependPound = true]
     * 
     * $h is the Degrees value of the Hue
     * $s is the Percentage value of the Saturation
     * $l is the Percentage value of the Lightness
     * $prependPound is a bool, whether you want a pound 
     *  sign prepended. (optional - default=true)
     *
     * Calls: 
     *   hslToRgb
     *
     * Output: Hex in the format: #00ff88 (with 
     * pound sign).  Rounded to the nearest whole
     * number.
    */
    function hslToHex($h, $s, $l, $prependPound = true) {
        //convert hsl to rgb
        $rgb = hslToRgb($h,$s,$l);
    
        //convert rgb to hex
        $hexR = $rgb['r'];
        $hexG = $rgb['g'];
        $hexB = $rgb['b'];
    
        //round to the nearest whole number
        $hexR = round($hexR);
        $hexG = round($hexG);
        $hexB = round($hexB);
    
        //convert to hex
        $hexR = dechex($hexR);
        $hexG = dechex($hexG);
        $hexB = dechex($hexB);
    
        //check for a non-two string length
        //if it's 1, we can just prepend a
        //0, but if it is anything else non-2,
        //it must return false, as we don't 
        //know what format it is in.
        if (strlen($hexR) != 2) {
            if (strlen($hexR) == 1) {
                //probably in format #0f4, etc.
                $hexR = "0" . $hexR;
            } else {
                //unknown format
                return false;
            }
        }
        if (strlen($hexG) != 2) {
            if (strlen($hexG) == 1) {
                $hexG = "0" . $hexG;
            } else {
                return false;
            }
        }
        if (strlen($hexB) != 2) {
            if (strlen($hexB) == 1) {
                $hexB = "0" . $hexB;
            } else {
                return false;
            }
        }
    
        //if prependPound is set, will prepend a
        //# sign to the beginning of the hex code.
        //(default = true)
        $hex = "";
        if ($prependPound) {
            $hex = "#";
        }
    
        $hex = $hex . $hexR . $hexG . $hexB;
    
        return $hex;
    }
    

    【讨论】:

    • 我对@9​​87654336@ 进行了编辑,您可能需要更新您的php 代码。代码中存在/存在错误。在 rgbToHsl() s = maxSub / (2 - maxSub) 应该是 s = maxSub / (2 - maxAdd)
    • @Lex 根据herehere,我的代码实际上是正确的。我认为您可能会将if l &lt; 0.5else 混淆。你能解释一下你的想法吗?感谢您抽出宝贵时间提供反馈!
    • 抱歉,您是对的,但仍然存在操作顺序问题。 #8cd08c 使用此计算 (2 - maxSub) = 1.7333333333333334 到 HSL,当它应该与第二个链接示例 ( 2 - max - min ) = 0.6352941176470588 一样时。使用 2 - maxAdd 让我始终更接近 Photoshop 输出,所以我认为它是正确的。
    • 哦,好的。感谢您指出了这一点!我现在修好了。希望这有帮助!
    • 真的很有帮助,我一直在转JS的过程中github.com/bambii7/glow
    【解决方案9】:

    这就是我的做法,很容易记住,将 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 
    

    【讨论】:

    • 这应该是公认的答案......更简单,更直观!你能把算法倒过来吗?
    • @JoelFan - 这很简单,但不正确。对于纯有理表达式(只有 +-**/),没有办法 - 正如定义中用于颜色转换的那样 - 用具有相同独立(输入)变量的sine 函数的帮助。尽管如此,理解原理还是很好的(但用于执行转换)。
    • 这个解决方案的问题是 AVERAGE 总是等于零:(R1 + G1 + B1) = L*[ SIN(H) + SIN(H+120) + SIN(H+240) ] - 现在,如果我们使用公式 sin(a)+sin(b) = 2*sin((a+b)/2)*cos((a-b)/2) 前两个罪,我们得到:AVERAGE=L*( sin(h+60) + sin(h+240) ) 和再次 AVERAGE= L*2*sin(h+150)*cos(-180/2) = 0 (因为 cos(-180/2)=cos(90)=0)。所以饱和度的计算是错误的,实际上饱和度在这里作为亮度起作用。
    • @JoelFan 此解决方案的第二个问题是我们需要将 180 度添加到 H 以具有与 en.wikipedia.org/wiki/HSL_and_HSV#Converting_to_RGB 的“兼容”版本(测试用例:H = 0 的红色)而且它颜色数量仍然存在问题 - 在上述解决方案中,黄色、洋红色和青色被忽略和/或以错误的方式映射。有js摆弄对比:jsfiddle.net/Lamik/9s24uc1o/10
    【解决方案10】:

    这是 GLSL 中一个快速、超级简单、无分支的版本:

    vec3 hsl2rgb( vec3 c ) {
        vec3 rgb = clamp(abs(mod(c.x*6.0 + vec3(0.0, 4.0, 2.0), 6.0)-3.0)-1.0, 0.0, 1.0);
        return c.z + c.y * (rgb-0.5)*(1.0-abs(2.0*c.z-1.0));
    }
    

    不会比这更短了~


    原始概念验证的链接:https://www.shadertoy.com/view/XljGzV

    (免责声明:不是我的代码!)

    【讨论】:

      【解决方案11】:

      这里是修改后的javascript函数,它输出0-360度的色调。

      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 ; break;
                    case g: h = 2 + ( (b - r) / d); break;
                    case b: h = 4 + ( (r - g) / d); break;
                }
                h*=60;
                if (h < 0) h +=360;
            }
           return([h, s, l]);
        }  
      alert(rgbToHsl(125,115,145));
      

      【讨论】:

        【解决方案12】:

        我从 Brandon Mathis 的 HSL Picker 源代码中得到这个。

        它是originally written in CoffeeScript。我使用在线转换器将其转换为 JavaScript,并取出验证用户输入是否为有效 RGB 值的机制。这个答案适用于我的用例,因为我发现在这篇文章中投票最多的答案不会产生有效的 HSL 值。

        请注意,它返回一个hsla 值,a 表示不透明度/透明度。 0 完全透明,1 完全不透明。

        function rgbToHsl(rgb) {
          var a, add, b, diff, g, h, hue, l, lum, max, min, r, s, sat;
          r = parseFloat(rgb[0]) / 255;
          g = parseFloat(rgb[1]) / 255;
          b = parseFloat(rgb[2]) / 255;
          max = Math.max(r, g, b);
          min = Math.min(r, g, b);
          diff = max - min;
          add = max + min;
          hue = min === max ? 0 : r === max ? ((60 * (g - b) / diff) + 360) % 360 : g === max ? (60 * (b - r) / diff) + 120 : (60 * (r - g) / diff) + 240;
          lum = 0.5 * add;
          sat = lum === 0 ? 0 : lum === 1 ? 1 : lum <= 0.5 ? diff / add : diff / (2 - add);
          h = Math.round(hue);
          s = Math.round(sat * 100);
          l = Math.round(lum * 100);
          a = parseFloat(rgb[3]) || 1;
          return [h, s, l, a];
        }
        

        【讨论】:

        • 我将此作为 Python 方法的基础。谢谢。
        • 这不是海报要求的 HSL 到 RGB
        【解决方案13】:

        在 javascript 中设置的 hsl|a 颜色值将立即生效 转换为 rgb|a 你需要做的就是访问 计算样式值

        document.body.style.color = 'hsla(44, 100%, 50%, 0.8)';
        
        console.log(window.getComputedStyle(document.body).color);
        
        // displays: rgba(255, 187, 0, 0.8)
        

        从技术上讲,我猜这甚至不是任何行代码 - 它是 刚刚自动完成。所以,根据你的环境,你 也许能够摆脱这一点。不是说没有 这里有很多非常周到的回应。我不知道你的 目标是。

        现在,如果你想从 rbg|a 转换为 hsl|a 怎么办?

        【讨论】:

          【解决方案14】:

          H、S 和 L 在 [0,1] 范围内:

          ConvertHslToRgb: function (iHsl)
          {
              var min, sv, sextant, fract, vsf;
          
              var v = (iHsl.l <= 0.5) ? (iHsl.l * (1 + iHsl.s)) : (iHsl.l + iHsl.s - iHsl.l * iHsl.s);
              if (v === 0)
                  return { Red: 0, Green: 0, Blue: 0 };
          
              min = 2 * iHsl.l - v;
              sv = (v - min) / v;
              var h = (6 * iHsl.h) % 6;
              sextant = Math.floor(h);
              fract = h - sextant;
              vsf = v * sv * fract;
          
              switch (sextant)
              {
                  case 0: return { r: v, g: min + vsf, b: min };
                  case 1: return { r: v - vsf, g: v, b: min };
                  case 2: return { r: min, g: v, b: min + vsf };
                  case 3: return { r: min, g: v - vsf, b: v };
                  case 4: return { r: min + vsf, g: min, b: v };
                  case 5: return { r: v, g: min, b: v - vsf };
              }
          }
          

          【讨论】:

            【解决方案15】:

            当您需要 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)];
            }
            

            【讨论】:

              【解决方案16】:

              来自 Mohsen 答案的 Unity3D C# 代码。

              这是 Mohsen 在 C# 中专门针对 Unity3D 的答案中的代码。它改编自上面 Alec Thilenius 给出的 C# 答案。

              using UnityEngine;
              using System.Collections;
              
              public class ColorTools {
              
                  /// <summary>
                  /// Converts an HSL color value to RGB.
                  /// Input: Vector4 ( X: [0.0, 1.0], Y: [0.0, 1.0], Z: [0.0, 1.0], W: [0.0, 1.0] )**strong text**
                  /// Output: Color ( R: [0.0, 1.0], G: [0.0, 1.0], B: [0.0, 1.0], A: [0.0, 1.0] )
                  /// </summary>
                  /// <param name="hsl">Vector4 defining X = h, Y = s, Z = l, W = a. Ranges [0, 1.0]</param>
                  /// <returns>RGBA Color. Ranges [0.0, 1.0]</returns>
                  public static Color HslToRgba(Vector4 hsl)
                  {
                      float r, g, b;
              
                      if (hsl.y == 0.0f)
                          r = g = b = hsl.z;
                      else
                      {
                          var q = hsl.z < 0.5f ? hsl.z * (1.0f + hsl.y) : hsl.z + hsl.y - hsl.z * hsl.y;
                          var p = 2.0f * hsl.z - q;
                          r = HueToRgb(p, q, hsl.x + 1.0f / 3.0f);
                          g = HueToRgb(p, q, hsl.x);
                          b = HueToRgb(p, q, hsl.x - 1.0f / 3.0f);
                      }
              
                      return new Color(r, g, b, hsl.w);
                  }
              
                  // Helper for HslToRgba
                  private static float HueToRgb(float p, float q, float t)
                  {
                      if (t < 0.0f) t += 1.0f;
                      if (t > 1.0f) t -= 1.0f;
                      if (t < 1.0f / 6.0f) return p + (q - p) * 6.0f * t;
                      if (t < 1.0f / 2.0f) return q;
                      if (t < 2.0f / 3.0f) return p + (q - p) * (2.0f / 3.0f - t) * 6.0f;
                      return p;
                  }
              
                  /// <summary>
                  /// Converts an RGB color value to HSL.
                  /// Input: Color ( R: [0.0, 1.0], G: [0.0, 1.0], B: [0.0, 1.0], A: [0.0, 1.0] )
                  /// Output: Vector4 ( X: [0.0, 1.0], Y: [0.0, 1.0], Z: [0.0, 1.0], W: [0.0, 1.0] )
                  /// </summary>
                  /// <param name="rgba"></param>
                  /// <returns></returns>
                  public static Vector4 RgbaToHsl(Color rgba)
                  {
              
                      float max = (rgba.r > rgba.g && rgba.r > rgba.b) ? rgba.r : 
                          (rgba.g > rgba.b) ? rgba.g : rgba.b;
                      float min = (rgba.r < rgba.g && rgba.r < rgba.b) ? rgba.r : 
                          (rgba.g < rgba.b) ? rgba.g : rgba.b;
              
                      float h, s, l;
                      h = s = l = (max + min) / 2.0f;
              
                      if (max == min)
                          h = s = 0.0f;
                      else
                      {
                          float d = max - min;
                          s = (l > 0.5f) ? d / (2.0f - max - min) : d / (max + min);
              
                          if (rgba.r > rgba.g && rgba.r > rgba.b)
                              h = (rgba.g - rgba.b) / d + (rgba.g < rgba.b ? 6.0f : 0.0f);
              
                          else if (rgba.g > rgba.b)
                              h = (rgba.b - rgba.r) / d + 2.0f;
              
                          else
                              h = (rgba.r - rgba.g) / d + 4.0f;
              
                          h /= 6.0f;
                      }
              
                      return new Vector4(h, s, l, rgba.a);
                  }
              
              }
              

              【讨论】:

                【解决方案17】:

                对于所有说 Garry Tan 解决方案从 RGB 到 HSL 并返回的转换不正确的人。这是因为他在代码中遗漏了数字的小数部分。 我更正了他的代码(javascript)。 抱歉,俄罗斯语言的链接,但英语缺席 - HSL-wiki

                function toHsl(r, g, b)
                {
                    r /= 255.0;
                    g /= 255.0;
                    b /= 255.0;
                    var max = Math.max(r, g, b);
                    var min = Math.min(r, g, b);
                    var h, s, l = (max + min) / 2.0;
                
                    if(max == min)
                    {
                        h = s = 0; 
                    }
                    else
                    {
                        var d = max - min;
                        s = (l > 0.5 ? d / (2.0 - max - min) : d / (max + min));
                
                        if(max == r && g >= b)
                        {
                            h = 1.0472 * (g - b) / d ;
                        }
                        else if(max == r && g < b)
                        {
                            h = 1.0472 * (g - b) / d + 6.2832;
                        }
                        else if(max == g)
                        {
                            h = 1.0472 * (b - r) / d + 2.0944;
                        }
                        else if(max == b)
                        {
                            h = 1.0472 * (r - g) / d + 4.1888;
                        }
                    }
                    return {
                        str: 'hsl(' + parseInt(h / 6.2832 * 360.0 + 0.5) + ',' + parseInt(s * 100.0 + 0.5) + '%,' + parseInt(l * 100.0 + 0.5) + '%)',
                        obj: { h: parseInt(h / 6.2832 * 360.0 + 0.5), s: parseInt(s * 100.0 + 0.5), l: parseInt(l * 100.0 + 0.5) }
                    };
                };
                

                【讨论】:

                  【解决方案18】:

                  @Mohsen 代码的 PHP 实现(包括测试!)

                  很抱歉重新发布。但我真的没有看到任何其他实现可以提供我需要的质量。

                  /**
                   * Converts an HSL color value to RGB. Conversion formula
                   * adapted from http://en.wikipedia.org/wiki/HSL_color_space.
                   * Assumes h, s, and l are contained in the set [0, 1] and
                   * returns r, g, and b in the set [0, 255].
                   *
                   * @param   {number}  h       The hue
                   * @param   {number}  s       The saturation
                   * @param   {number}  l       The lightness
                   * @return  {Array}           The RGB representation
                   */
                    
                  function hue2rgb($p, $q, $t){
                              if($t < 0) $t += 1;
                              if($t > 1) $t -= 1;
                              if($t < 1/6) return $p + ($q - $p) * 6 * $t;
                              if($t < 1/2) return $q;
                              if($t < 2/3) return $p + ($q - $p) * (2/3 - $t) * 6;
                              return $p;
                          }
                  function hslToRgb($h, $s, $l){
                      if($s == 0){
                          $r = $l;
                          $g = $l;
                          $b = $l; // achromatic
                      }else{
                          $q = $l < 0.5 ? $l * (1 + $s) : $l + $s - $l * $s;
                          $p = 2 * $l - $q;
                          $r = hue2rgb($p, $q, $h + 1/3);
                          $g = hue2rgb($p, $q, $h);
                          $b = hue2rgb($p, $q, $h - 1/3);
                      }
                  
                      return array(round($r * 255), round($g * 255), round($b * 255));
                  }
                  
                  /* Uncomment to test * /
                  for ($i=0;$i<360;$i++) {
                    $rgb=hslToRgb($i/360, 1, .9);
                    echo '<div style="background-color:rgb(' .$rgb[0] . ', ' . $rgb[1] . ', ' . $rgb[2] . ');padding:2px;"></div>';
                  }
                  /* End Test */
                  

                  【讨论】:

                    【解决方案19】:

                    C++ 实现的性能可能比@Mohsen 代码更好。它使用 [0-6] 范围作为色调,避免除以 6。S 和 L 范围为 [0,1]

                    void fromRGBtoHSL(float rgb[], float hsl[])
                    {
                         const float maxRGB = max(rgb[0], max(rgb[1], rgb[2]));
                         const float minRGB = min(rgb[0], min(rgb[1], rgb[2]));
                         const float delta2 = maxRGB + minRGB;
                         hsl[2] = delta2 * 0.5f;
                    
                         const float delta = maxRGB - minRGB;
                         if (delta < FLT_MIN)
                             hsl[0] = hsl[1] = 0.0f;
                         else
                         {
                             hsl[1] = delta / (hsl[2] > 0.5f ? 2.0f - delta2 : delta2);
                             if (rgb[0] >= maxRGB)
                             {
                                 hsl[0] = (rgb[1] - rgb[2]) / delta;
                                 if (hsl[0] < 0.0f)
                                     hsl[0] += 6.0f;
                             }
                             else if (rgb[1] >= maxRGB)
                                 hsl[0] = 2.0f + (rgb[2] - rgb[0]) / delta;
                             else
                                 hsl[0] = 4.0f + (rgb[0] - rgb[1]) / delta;
                         }
                    }
                    
                    void fromHSLtoRGB(const float hsl[], float rgb[])
                    {
                        if(hsl[1] < FLT_MIN)
                            rgb[0] = rgb[1] = rgb[2] = hsl[2];
                        else if(hsl[2] < FLT_MIN)
                            rgb[0] = rgb[1] = rgb[2] = 0.0f;
                        else
                        {
                            const float q = hsl[2] < 0.5f ? hsl[2] * (1.0f + hsl[1]) : hsl[2] + hsl[1] - hsl[2] * hsl[1];
                            const float p = 2.0f * hsl[2] - q;
                            float t[] = {hsl[0] + 2.0f, hsl[0], hsl[0] - 2.0f};
                    
                            for(int i=0; i<3; ++i)
                            {
                                if(t[i] < 0.0f)
                                    t[i] += 6.0f;
                                else if(t[i] > 6.0f)
                                    t[i] -= 6.0f;
                    
                                if(t[i] < 1.0f)
                                    rgb[i] = p + (q - p) * t[i];
                                else if(t[i] < 3.0f)
                                    rgb[i] = q;
                                else if(t[i] < 4.0f)
                                    rgb[i] = p + (q - p) * (4.0f - t[i]);
                                else
                                    rgb[i] = p;
                              }
                          }
                    }
                    

                    【讨论】:

                      【解决方案20】:

                      我需要一个非常轻量级的,它不是 100%,但对于某些用例来说已经足够接近了。

                      float3 Hue(float h, float s, float l)
                      {
                          float r = max(cos(h * 2 * UNITY_PI) * 0.5 + 0.5, 0);
                          float g = max(cos((h + 0.666666) * 2 * UNITY_PI) * 0.5 + 0.5, 0);
                          float b = max(cos((h + 0.333333) * 2 * UNITY_PI) * 0.5 + 0.5, 0);
                          float gray = 0.2989 * r + 0.5870 * g + 0.1140 * b;
                          return lerp(gray, float3(r, g, b), s) * smoothstep(0, 0.5, l) + 1 * smoothstep(0.5, 1, l);
                      }
                      

                      【讨论】:

                        【解决方案21】:

                        PHP - 最短但精确

                        这里我将my JS answer(数学细节在那里)重写为PHP - 你可以运行它here

                        function hsl2rgb($h,$s,$l) 
                        {
                          $a = $s * min($l, 1-$l);
                          $k = function($n,$h) { return ($n+$h/30)%12;};
                          $f = function($n) use ($h,$s,$l,$a,$k) { 
                              return $l - $a * max( min($k($n,$h)-3, 9-$k($n,$h), 1),-1);
                          };
                          return [ $f(0), $f(8), $f(4) ];
                        }   
                        

                        【讨论】:

                          【解决方案22】:

                          Typescript 中的 HSL 到 RGB

                          以上所有选项都不适用于我在 TS 中的代码。

                          我调整了其中一个,现在它就像一个魅力:

                          type HslType = { h: number; s: number; l: number }
                          
                          const hslToRgb = (hsl: HslType): RgbType => {
                            let { h, s, l } = hsl
                          
                            // IMPORTANT if s and l between 0,1 remove the next two lines:
                            s /= 100
                            l /= 100
                          
                            const k = (n: number) => (n + h / 30) % 12
                            const a = s * Math.min(l, 1 - l)
                            const f = (n: number) =>
                              l - a * Math.max(-1, Math.min(k(n) - 3, Math.min(9 - k(n), 1)))
                            return {
                              r: Math.round(255 * f(0)),
                              g: Math.round(255 * f(8)),
                              b: Math.round(255 * f(4)),
                            }
                          }
                          

                          【讨论】:

                            猜你喜欢
                            • 2012-08-25
                            • 1970-01-01
                            • 1970-01-01
                            • 1970-01-01
                            • 2022-11-25
                            • 1970-01-01
                            • 2015-10-15
                            • 2011-03-29
                            • 1970-01-01
                            相关资源
                            最近更新 更多