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

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


当前回答

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

其他回答

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

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

由于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)]

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

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

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

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