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

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


当前回答

对于所有说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) }
    };
};

其他回答

Unity3D c#代码来自Mohsen的回答。

以下是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);
    }

}

我是这样做的,这很容易记住,把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 

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

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

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