Chuyển đổi màu HSL sang RGB [đã đóng]


174

Tôi đang tìm kiếm một thuật toán JavaScript / PHP để chuyển đổi giữa màu HSL sang RGB.

Dường như với tôi rằng HSL không được sử dụng rộng rãi nên tôi không gặp nhiều may mắn khi tìm kiếm một công cụ chuyển đổi.


2
Chỉ cần lưu ý rằng dự án less.js có một số hàm thao tác màu, bao gồm hsl_to_rgb: github.com/cloudhead/less.js/blob/master/lib/less/fifts.js
dmkc

1
Ở phía trình duyệt - d3.js có API tốt cho việc này: github.com/mbostock/d3/wiki/Colors
matanster

vui lòng kiểm tra jsPlease.HEX_to_HSV('#ffeb3b')
Lex

4
Được đánh dấu là lạc đề mặc dù yêu cầu một thuật toán, rõ ràng là một 'chủ đề' tại stackoverflow.com/help/on-topic - điều gì mang lại?
LeeGee

2
Đây là lần bỏ phiếu tệ nhất mà tôi từng thấy trên trang này và điều đó đã nói lên rất nhiều điều! Tôi là người bỏ phiếu đầu tiên để mở lại.
Theodore R. Smith

Câu trả lời:


300

Garry Tan đã đăng một giải pháp Javascript trên blog của mình (mà anh ta gán cho mjijackson.com hiện không còn tồn tại, nhưng được lưu trữ ở đâytác giả gốc có một ý chính - nhờ user2441511).

Mã được đăng lại dưới đây:

HSL sang 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 sang 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];
}

15
Tôi thích cách các bình luận cho tôi biết phạm vi của các biến và những gì mong đợi là đầu ra. Thật gọn gàng. Cảm ơn!
Gleno

9
Tôi đang cố gắng sử dụng điều này cho một dự án, nhưng kết quả của tôi chỉ được đưa ra dưới dạng thang độ xám. Đây có phải là giới hạn của HSL <-> RGB không? Bài viết trên wikipedia dường như đề xuất rằng chỉ một giá trị duy nhất được đặt cho cả 3 kênh.
Bill

10
Tôi muốn chỉ ra rằng việc sử dụng Math.roundgiới thiệu những điểm không chính xác nhỏ ở đầu thấp và cao (giá trị 0 và 255) của thang đo. Các giá trị xuất hiện ở hai đầu của phạm vi có thể làm tròn lên hoặc xuống để đạt đến giá trị của chúng, nhưng các giá trị chỉ có thể được làm tròn xuống 0 hoặc tối đa 255. Điều này có nghĩa là phạm vi của các giá trị ánh xạ đến 0 và 255 là chính xác một nửa số đó cho các giá trị khác. Để khắc phục điều này, sử dụng công thức này thay thế : min(floor(val*256),255). Điều này làm cho bản đồ gần như hoàn hảo.
marcus erronius

13
Ngoài ra, nếu bạn đang nhận được các giá trị thang độ xám, có thể là do các dòng sử dụng h + 1/3h - 1/3. Trong nhiều ngôn ngữ, điều này sử dụng phân chia số nguyên, trong đó 1/3bằng không. để có kết quả chính xác, thay vào đó hãy sử dụng chữ nổi h + 1.0/3.0.
marcus erronius

6
Chức năng RGB đến HSL không hoạt động. Đây là một ví dụ về nó không hoạt động: jsfiddle.net/fs5L02k0/2 và đây là chức năng, đã sửa jsfiddle.net/t5nq6jjc/1 - Công thức được áp dụng từ: nl.wikipedia.org/wiki/iêu
Hanna

44

Tìm thấy cách dễ nhất, trăn để giải cứu : D

colorsys.hls_to_rgb(h, l, s)

Chuyển đổi màu từ tọa độ HLS sang tọa độ RGB.


6
Tôi không thể tin rằng có một mô-đun chuẩn như vậy trong Python! Điều này thực sự giải cứu tôi. Tôi đã vật lộn với thuật toán hội tụ trong mục nhập HSL của Wikipedia trong 2 giờ. Có vẻ như thuật toán không thể có được đầu ra đúng.
Ray

2
Tương đương với Ruby: rubydoc.info/gems/color/1.8/Color/RGB, vdColor::HSL.new(40,50,60).to_rgb
xxjjnn

1
Tôi sử dụng brython để có một công cụ chọn màu trong trình duyệt, đây chính là thứ tôi cần!
EvertW

23

Java triển khai mã của Mohsen

Lưu ý rằng tất cả các số nguyên được khai báo là float (tức là 1f) và phải là float, nếu không bạn sẽ có màu xám.

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

Đây là thuật toán đơn giản hơn trên wiki: stackoverflow.com/a/54014428/860099
Kamil Kiełczewski

19

Bài viết cho HSL và HSV trên wikipedia chứa một số công thức. Các tính toán là một chút khó khăn, vì vậy có thể hữu ích để xem xét các triển khai hiện có .


1
+1 Câu trả lời tuyệt vời. Các liên kết là chính xác những gì tôi đang tìm kiếm. Câu trả lời được chấp nhận dường như chỉ hữu ích cho python.
AturSams

Đây là thuật toán đơn giản hơn trên wiki stackoverflow.com/a/54014428/860099
Kamil Kiełczewski

13

Nếu bạn đang tìm kiếm thứ gì đó chắc chắn phù hợp với ngữ nghĩa CSS cho HSL và RGB, bạn có thể sử dụng thuật toán được chỉ định trong đặc tả CSS 3 , có nội dung:

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

Tôi tin rằng đây là nguồn cho một số câu trả lời khác ở đây.


đây là thuật toán đơn giản hơn stackoverflow.com/a/54014428/860099
Kamil Kiełczewski

7

Mã C # từ câu trả lời của Mohsen.

Đây là mã từ câu trả lời của Mohsen trong C # nếu có ai khác muốn nó. Lưu ý: Colorlà một lớp tùy chỉnh và Vector4là từ OpenTK. Cả hai đều dễ dàng thay thế bằng một cái gì đó khác của sự lựa chọn của bạn.

Hsl đến 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);
}

Đây là thuật toán đơn giản hơn trên wiki: stackoverflow.com/a/54014428/860099
Kamil Kiełczewski

7

Php triển khai mã C # của Chris

Cũng từ đây , giải thích toán học của nó rất tốt.

Về cơ bản, đây là một loạt các chức năng để chuyển đổi sang và từ HSL (Hue Saturation Lightness)

Đã thử nghiệm và làm việc trên PHP 5.6.15

TL; DR : Mã đầy đủ có thể được tìm thấy ở đây trên Pastebin .


Hex đến HSL

Đầu vào: Màu lục ở định dạng: [#] 0f4 hoặc [#] 00ff44 (dấu thăng tùy chọn)
Đầu ra: HSL theo Độ, Phần trăm, Phần trăm

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

Đầu vào: RGB trong phạm vi 0-255 Đầu ra: HSL theo Độ, Phần trăm, Phần trăm.

/**
 * 
 *Credits:
 * /programming/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 (phạm vi 0-1) đến định dạng Độ, Phần trăm, Phần trăm

Đối với các phép tính toán, HSL dễ xử lý hơn trong phạm vi 0-1, nhưng đối với khả năng đọc của con người, nó dễ dàng hơn ở Độ, Phần trăm, Phần trăm. Hàm này nhận HSL trong các phạm vi 0-1 và trả về HSL theo Độ, Phần trăm, Phần trăm.

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

Định dạng HSL (Độ, Phần trăm, Phần trăm) sang HSL trong phạm vi 0-1

Hàm này chuyển đổi HSL theo định dạng Độ, Phần trăm, Phần trăm, thành các phạm vi 0-1 để tính toán dễ dàng hơn.

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

Đầu vào: HSL ở định dạng Độ, Phần trăm, Phần trăm Đầu ra: RGB ở định dạng 255, 255, 255.

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

Huế đến RGB

Hàm này được gọi bởi hslToRgb để chuyển đổi màu sắc thành các giá trị RGB riêng biệt.

/**
 * 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 đến Hex

Đầu vào: HSL ở định dạng Độ, Phần trăm, Phần trăm Đầu ra: Hex ở định dạng 00ff22(không có dấu thăng).

Chuyển đổi sang RGB, sau đó chuyển đổi riêng sang 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;
}

Tôi đã thực hiện chỉnh sửa rgbToHsl, bạn có thể muốn cập nhật mã php của mình. Có / là một lỗi trong mã. Trong rgbToHsl () s = maxSub / (2 - maxSub)nên làs = maxSub / (2 - maxAdd)
Lex

@Lex Theo đâyđây , mã của tôi thực sự là chính xác. Tôi nghĩ rằng bạn có thể nhầm lẫn if l < 0.5với else. Bạn có thể giải thích suy nghĩ của bạn? Cảm ơn đã dành thời gian để đưa ra phản hồi mặc dù!
Cullub

1
xin lỗi, bạn nói đúng, nhưng vẫn còn một vấn đề về hoạt động. # 8cd08c đến HSL bằng cách sử dụng calc này (2 - maxSub) = 1.7333333333333334khi nó phải như trong ví dụ liên kết thứ hai ( 2 - max - min ) = 0.6352941176470588. Việc sử dụng 2 - maxAddgiúp tôi luôn gần với đầu ra của photoshops hơn nên tôi cho rằng nó là chính xác.
Lex

Ồ được thôi. Cảm ơn đã chỉ ra rằng! Tôi đã sửa nó bây giờ. Hy vọng điều này là hữu ích!
Cullub

Nó thực sự hữu ích, tôi đang trong quá trình chuyển đổi nó thành JS github.com/bambii7/glow
Lex

6

Đây là cách tôi làm điều dễ nhớ là nghĩ về RGB như ba nan hoa trên một bánh xe, cách nhau 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 

Phần khó khăn là bão hòa, là một tỷ lệ xuống mức trung bình của ba.

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 

Đây phải là câu trả lời được chấp nhận ... đơn giản và trực quan hơn nhiều! Bạn có thể đảo ngược thuật toán?
JoelFan

@JoelFan - Nó đơn giản nhưng không chính xác . Có không có cách nào cho các biểu thức hợp lý thuần túy (với chỉ +, -, *, và /) - như được sử dụng theo định nghĩa cho các chuyển đổi màu - để thể hiện chúng với sự giúp đỡ của các sinechức năng độc lập với nhau (đầu vào) biến. Mặc dù vậy, thật tốt khi hiểu nguyên tắc (nhưng không phải để thực hiện chuyển đổi).
MarianD

Vấn đề với giải pháp này là AVERAGE luôn luôn bằng ZERO: (R1 + G1 + B1) = L*[ SIN(H) + SIN(H+120) + SIN(H+240) ]- và bây giờ nếu chúng ta sử dụng công thức sin(a)+sin(b) = 2*sin((a+b)/2)*cos((a-b)/2)cho hai tội lỗi đầu tiên, chúng ta sẽ nhận được: AVERAGE=L*( sin(h+60) + sin(h+240) )và một lần nữa AVERAGE= L*2*sin(h+150)*cos(-180/2) = 0(vì cos (-180/2) = cos (90) = 0). Vì vậy, tính toán cho bão hòa là sai và trên thực tế bão hòa hoạt động ở đây là độ chói.
Kamil Kiełczewski

@JoelFan Vấn đề thứ hai với giải pháp này là chúng ta cần thêm 180 độ vào H để có phiên bản "tương thích" với en.wikipedia.org/wiki/HSL_and_HSV#Converting_to_RGB (trường hợp thử nghiệm: màu đỏ cho H = 0) nhưng cũng có nó vẫn còn vấn đề với số lượng màu - trong giải pháp trên, màu vàng, đỏ tươi và lục lam là không phổ biến và / hoặc ánh xạ sai. Có js fiddle với sự so sánh: jsfiddle.net/Lamik/9s24uc1o/10
Kamil Kiełczewski

3

Đây là phiên bản nhanh, siêu đơn giản, không phân nhánh trong 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));
}

Không được ngắn hơn thế nhiều ~


Liên kết đến bằng chứng ban đầu về khái niệm: https://www.shadertoy.com/view/XljGzV

(Tuyên bố miễn trừ trách nhiệm: không phải mã của tôi!)


2

Đây là chức năng javascript được sửa đổi, nó xuất ra Hue trong tập 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));

2

Tôi đã nhận được điều này từ Trình chọn HSL của Brandon Mathis mã nguồn .

Ban đầu nó được viết bằng CoffeeScript . Tôi đã chuyển đổi nó thành JavaScript bằng trình chuyển đổi trực tuyến và lấy ra cơ chế để xác minh đầu vào của người dùng là giá trị RGB hợp lệ. Câu trả lời này đã làm việc cho usecase của tôi, vì câu trả lời được bình chọn nhiều nhất trên bài đăng này tôi thấy không tạo ra giá trị HSL hợp lệ.

Lưu ý rằng nó trả về một hslagiá trị, ađại diện cho độ mờ / độ trong suốt. 0là hoàn toàn trong suốt, và 1hoàn toàn mờ đục.

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

Tôi đã sử dụng điều này như là một cơ sở cho một phương pháp Python. Cảm ơn.
JayJay123

đây không phải là HSL sang RGB như người đăng yêu cầu
bryc

1

Thay vào đó, khi bạn cần RGB đến HSV và ngược lại:

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

1

Mã Unity3D C # từ câu trả lời của Mohsen.

Đây là mã từ câu trả lời của Mohsen trong C # được nhắm mục tiêu cụ thể cho Unity3D. Nó được điều chỉnh từ câu trả lời C # được đưa ra bởi Alec Thilenius ở trên.

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

}

1

Đối với tất cả những người nói rằng giải pháp Garry Tan chuyển đổi không chính xác từ RGB sang HSL và ngược lại. Nó bởi vì anh ta đã bỏ đi một phần số trong mã của mình. Tôi đã sửa mã của anh ấy (javascript). Xin lỗi vì liên kết trên tiếng Nga, nhưng tiếng Anh vắng mặt - 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) }
    };
};

1

Một giá trị hsl | một màu, được đặt trong javascript, sẽ được chuyển đổi ngay lập tức thành rgb | a Tất cả những gì bạn cần làm sau đó là truy cập giá trị kiểu được tính

document.body.style.color = 'hsla(44, 100%, 50%, 0.8)';

console.log(window.getComputedStyle(document.body).color);

// displays: rgba(255, 187, 0, 0.8)

Về mặt kỹ thuật, tôi đoán, đây không phải là thậm chí bất kỳ dòng mã nào - nó chỉ được thực hiện tự động. Vì vậy, tùy thuộc vào môi trường của bạn, bạn có thể thoát khỏi điều này. Không phải là không có nhiều phản hồi rất chu đáo ở đây. Tôi không biết mục tiêu của bạn là gì.

Bây giờ, nếu bạn muốn chuyển đổi từ rbg | a sang hsl | a thì sao?


1

Triển khai C ++ với hiệu năng có thể tốt hơn mã @Mohsen. Nó sử dụng phạm vi [0-6] cho màu sắc, tránh phân chia và nhân với 6. Phạm vi S và L 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;
          }
      }
}

0

Với H, S và L trong phạm vi [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 };
    }
}

0

Tôi cần một trọng lượng thực sự nhẹ, Nó không phải là 100%, nhưng nó đủ gần cho một số usecase.

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

0

PHP triển khai mã của @ Mohsen (bao gồm cả Kiểm tra!)

Xin lỗi để đăng lại này. Nhưng tôi thực sự chưa thấy bất kỳ triển khai nào khác mang lại chất lượng mà tôi cần.

/**
 * 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 */
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.