HSL转RGB颜色转换

245

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

据我所知,HSL并不是非常常用的颜色表示方式,因此我在搜索转换器时没有太多的运气。


3
刚刚注意到 less.js 项目有许多颜色处理函数,包括 hsl_to_rgb:http://github.com/cloudhead/less.js/blob/master/lib/less/functions.js - dmkc
1
在浏览器端 - d3.js 有很好的 API 来实现这个功能: https://github.com/mbostock/d3/wiki/Colors - matanster
5
尽管在https://stackoverflow.com/help/on-topic中明确指出算法是“主题内”的,但我的问题被标记为“脱离主题”--怎么回事? - Lee Goddard
5
这是我在这个网站上见过的最糟糕的关闭投票,这话可不是说说而已!我是第一个投票重新开放的人。 - Theodore R. Smith
2
我十年前问过这个问题,惊讶地发现添加了php和python标签。现在我改回原来的措辞 :) - hhafez
显示剩余5条评论
25个回答

381
Garry Tan在他的博客上发布了一个JavaScript解决方案(他将其归功于现已关闭的mjijackson.com,但在这里存档,以及原始作者有一个gist - 感谢user2441511)。
以下是重新发布的代码(根据ES5后的约定进行更新):

HSL转RGB:

const { abs, min, max, round } = Math;

/**
 * Converts an HSL color value to RGB. Conversion formula
 * adapted from https://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) {
  let r, g, b;

  if (s === 0) {
    r = g = b = l; // achromatic
  } else {
    const q = l < 0.5 ? l * (1 + s) : l + s - l * s;
    const p = 2 * l - q;
    r = hueToRgb(p, q, h + 1/3);
    g = hueToRgb(p, q, h);
    b = hueToRgb(p, q, h - 1/3);
  }

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

function hueToRgb(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;
}

##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);
  const vmax = max(r, g, b), vmin = min(r, g, b);
  let h, s, l = (vmax + vmin) / 2;

  if (vmax === vmin) {
    return [0, 0, l]; // achromatic
  }

  const d = vmax - vmin;
  s = l > 0.5 ? d / (2 - vmax - vmin) : d / (vmax + vmin);
  if (vmax === r) h = (g - b) / d + (g < b ? 6 : 0);
  if (vmax === g) h = (b - r) / d + 2;
  if (vmax === b) h = (r - g) / d + 4;
  h /= 6;

  return [h, s, l];
}

9
我正在尝试在项目中使用这个,但我的结果只是灰度图像。这是HSL<->RGB的限制吗?维基百科文章似乎表明只有一个值被设置到所有三个通道。 - Bill
12
我想指出,使用Math.round会在比例尺的低端和高端(值为0和255)引入小的不准确性。不在范围末端的值可以向上或向下舍入达到它们的值,但值只能向下舍入到0,或向上舍入到255。这意味着映射到0和255的值的范围正好是其他值的一半。要解决此问题,请改用此公式:min(floor(val*256),255)。这样映射就几乎完美了。 - marcus erronius
22
如果你得到的是灰度值,很可能是因为使用了h + 1/3h - 1/3。在许多编程语言中,这将使用整数除法运算,其中1/3会被计算成零。为了得到正确的结果,请改用浮点型字面量,例如:h + 1.0/3.0 - marcus erronius
9
RGB转HSL函数不起作用,这是一个不起作用的示例:https://jsfiddle.net/fs5L02k0/2/,这是已修复的函数:https://jsfiddle.net/t5nq6jjc/1 -- 公式源自:https://nl.wikipedia.org/wiki/HSL_(kleurruimte)#Omzetten_van_RGB_naar_HSL - Hanna
5
请查看代码中的说明:输入的 hsl 值应该在 0 到 1 之间。你需要调用 hslToRgb(0.447 /*161/360*/, 0.55, 0.63) - Sphinxxx
显示剩余19条评论

49

发现了最简单的方法,使用Python来拯救救援 :D

colorsys.hls_to_rgb(h, l, s)

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


8
我简直不敢相信Python里居然有这样的标准模块!真是救了我。我已经为维基百科HSL条目中的转换算法苦战了两个小时,似乎那个算法无法得出正确的输出结果。 - Ray
2
Ruby等效代码:http://www.rubydoc.info/gems/color/1.8/Color/RGB 例:Color::HSL.new(40,50,60).to_rgb - xxjjnn
1
我使用brython在浏览器中获取颜色选择器,这正是我所需要的! - EvertW
hls_to_rgb 矢量化 - undefined

26

Java实现Mohsen代码

请注意,所有整数都声明为float(即1f),必须是float,否则您将得到灰色的颜色。

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 to 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;
}

25

简短而精确 - JS

使用此JS代码(更多信息:rgb2hslhsv2rgbrgb2hsvhsl2hsv)- 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>

我在 维基百科 上发现并精确描述了下面的公式,并进行了误差分析

enter image description here


2
优秀的答案。我将其翻译成Python并用于一个小项目中,效果非常好。 - aecend

20

1
+1 很棒的答案。链接正是我所寻找的。被采纳的答案似乎只对Python有用。 - AturSams

15

如果您正在寻找符合HSL和RGB CSS语义的内容,您可以使用CSS 3规范中指定的算法。该规范可在此处查看。

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

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


11

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);
}

这里有一个比维基上更简单的算法:https://dev59.com/-VoV5IYBdhLWcg3wEraD#54014428 - Kamil Kiełczewski

8
这是我常用的记忆方式,很容易理解。就把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
@JoelFan - 这很简单,但不正确。对于纯理性表达式(仅包含+-*/),即颜色转换的定义所使用的表达式,没有办法通过sine函数来表示具有相同独立(输入)变量的表达式。尽管如此,这对于理解原则(但不适用于执行转换)非常好。 - MarianD
这个解决方案的问题在于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) 来计算前两个sin,我们得到:AVERAGE=L*( sin(h+60) + sin(h+240) ) 再次计算 AVERAGE= L*2*sin(h+150)*cos(-180/2) = 0(因为cos(-180/2)=cos(90)=0)。因此,饱和度的计算是错误的,实际上饱和度在这里起到了亮度的作用。 - Kamil Kiełczewski
@JoelFan 这个解决方案的第二个问题是我们需要将H加上180度才能与https://en.wikipedia.org/wiki/HSL_and_HSV#Converting_to_RGB(测试用例:H = 0的红色)具有“兼容性”的版本,但颜色数量仍然存在问题-在上述解决方案中,黄色,洋红色和青色被省略和/或以错误的方式映射。这里有一个js fiddle进行比较:https://jsfiddle.net/Lamik/9s24uc1o/10/ - Kamil Kiełczewski

7

#Php实现Chris的C#代码

还可以从这里了解它的数学原理。

这基本上是一堆函数,用于在HSL(色调饱和度亮度)之间进行转换

在PHP 5.6.15上测试并工作正常

TL;DR:完整代码可以在Pastebin上找到


##Hex到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://dev59.com/bW445IYBdhLWcg3wkLPU
* 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范围内更容易处理,但对于人类可读性,以度数、百分比、百分比形式呈现更容易理解。此函数将HSL范围设置为0-1,并返回以度数、百分比、百分比表示的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(度数,百分比,百分比格式)转换为范围在0-1的HSL

此函数将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 输出:以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;
}

###Hue转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转Hex

输入: HSL格式为度数、百分比、百分比 输出: Hex格式为00ff22(不带#号)。

先转换为RGB,然后分别转换为hex。

/**
* 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;
}

我对 rgbToHsl 进行了编辑,你可能需要更新你的 PHP 代码。代码中存在一个错误。在 rgbToHsl() 中,s = maxSub / (2 - maxSub) 应该是 s = maxSub / (2 - maxAdd) - Lex
@Lex 根据这里这里的内容,我的代码实际上是正确的。我认为你可能将if l < 0.5else混淆了。你能解释一下你的想法吗?感谢你抽出时间给予反馈! - Cullub
1
抱歉,你是对的,但还存在一些操作顺序问题。使用此计算 (2 - maxSub) = 1.7333333333333334 将 #8cd08c 转换为 HSL,但应该像第二个链接示例中那样使用 ( 2 - max - min ) = 0.6352941176470588。使用 2 - maxAdd 可以让我更接近 Photoshop 的输出结果,因此我认为它是正确的。 - Lex
这真的很有帮助,我一直在将其转换为JS的过程中。https://github.com/bambii7/glow - Lex
这里有一个比维基上更简单的hsl2rgb算法:https://dev59.com/-VoV5IYBdhLWcg3wEraD#54014428 - Kamil Kiełczewski
显示剩余2条评论

6
这里是一个快速、超级简单的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

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接