将 Hsl 转换为 rgb 和 hex

Posted

技术标签:

【中文标题】将 Hsl 转换为 rgb 和 hex【英文标题】:convert Hsl to rgb and hex 【发布时间】:2016-08-11 20:02:21 【问题描述】:

我需要一个颜色转换器来将 hsl 转换为 rgb 和十六进制值。我会像this 那样做类似的事情。我为此使用 jquery 和 jquery ui 范围滑块。这是我的代码:

$(function() 
    $( "#hsl_hue_range" ).slider(
        min: 0,
        max: 100,
        value: 0,
        range: false,
        animate:"slow",
        orientation: "horizontal",
        slide: function( event, ui ) 
            var hsl_hue = ui.value;
        
    );
);

$(function() 
    $( "#hsl_saturation_range" ).slider(
        min: 0,
        max: 100,
        value: 0,
        range: false,
        animate:"slow",
        orientation: "horizontal",
        slide: function( event, ui ) 
            var hsl_saturation = ui.value;
        
    );
);

$(function() 
    $( "#hsl_light_range" ).slider(
        min: 0,
        max: 100,
        value: 0,
        range: false,
        animate:"slow",
        orientation: "horizontal",
        slide: function( event, ui ) 
            var hsl_light = ui.value;
        
    );
);

我想要这样的解决方案:

转换器的输入可以由变量给出。比如hsl_huehsl_saturationhsl_light

有没有办法做到这一点? 如果不行,我该怎么办?

【问题讨论】:

【参考方案1】:

最短

试试这个(wiki,错误analysis,更多:rgb2hsl,hsv2rgbrgb2hsv 和 hsl2hsv)

// input: h in [0,360] and s,v 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)];
   

要计算 hsl2hex,请使用 rgb2hex(...hsl2rgb(30,1,0.5))。从格式转换字符串,例如rgb(255, 255, 255) 到十六进制使用rgbStrToHex(处理空字符串大小写)如下

// 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('');

// hexStr e.g #abcdef, result "rgb(171,205,239)"
let hexStr2rgb  = (hexStr) => `rgb($hexStr.substr(1).match(/../g).map(x=>+`0x$x`))`;

// rgb - color str e.g."rgb(12,233,43)", result color hex e.g. "#0ce92b"
let rgbStrToHex= rgb=> '#'+rgb.match(/\d+/g).map(x=>(+x).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))`);
console.log(`rgb: $hexStr2rgb("#ff647b") --> hex: $rgbStrToHex("rgb(255,100, 123)")`)


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

【讨论】:

rgb2hex 期望值介于 0 和 1 之间?最常见的格式是 0-255 和 %(即 CSS 颜色) @Kaiido OP 想要将 hsl 转换为十六进制 - 他可以通过例如rgb2hex(...hsl2rgb(30,1,0.5)) 但是,通过在上面的代码中将 Math.ceil(x*255) 更改为 Math.ceil(x),也可以轻松更改该函数以处理 [0-255] 值。 当然我明白了,我的意思是,当您不能直接传递 rgb 的常用值时,称它为 rgb2hex 有点误导。【参考方案2】:

新方法(灵感来自@Kamil-Kiełczewski solution) 接受 degree, percentage, percentage 并返回 css hex 颜色:

function hslToHex(h, s, l) 
  l /= 100;
  const a = s * Math.min(l, 1 - l) / 100;
  const f = n => 
    const k = (n + h / 30) % 12;
    const color = l - a * Math.max(Math.min(k - 3, 9 - k, 1), -1);
    return Math.round(255 * color).toString(16).padStart(2, '0');   // convert to Hex and prefix "0" if needed
  ;
  return `#$f(0)$f(8)$f(4)`;

示例:

hslToHex(360, 100, 50)  // "#ff0000" -> red

原始版本:(还可以,只是更长)

获取degree, percentage, percentage 并返回 css hex 颜色:

function hslToHex(h, s, l) 
  h /= 360;
  s /= 100;
  l /= 100;
  let r, g, b;
  if (s === 0) 
    r = g = b = l; // achromatic
   else 
    const 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;
    ;
    const q = l < 0.5 ? l * (1 + s) : l + s - l * s;
    const p = 2 * l - q;
    r = hue2rgb(p, q, h + 1 / 3);
    g = hue2rgb(p, q, h);
    b = hue2rgb(p, q, h - 1 / 3);
  
  const toHex = x => 
    const hex = Math.round(x * 255).toString(16);
    return hex.length === 1 ? '0' + hex : hex;
  ;
  return `#$toHex(r)$toHex(g)$toHex(b)`;

示例:

hslToHex(360, 100, 50)  // "#ff0000" -> red

【讨论】:

【参考方案3】:

解决此问题的另一种方法是利用现代浏览器的window.getComputedStyle 功能:

    在页面上创建一个元素(它可以被隐藏,例如使用display:none,但这似乎会抑制不透明度/“A”值的输出)

    使用您选择的表示设置该元素的颜色值属性,例如e.style.color = 'hsla(100, 50%, 75%, 0.8)';(甚至命名颜色如'rebeccapurple'

    使用window.getComputedStyle(e).color 读回值。它将是rgb(r,g,b)rgba(r,g,b,a) 形式的字符串。

Live demo on CodePen

【讨论】:

【参考方案4】:

我最近有理由解决这个问题,并提出了一个基于画布的解决方案。我在这里记录它只是为了后代。

在我的情况下,我还需要考虑给定一系列背景颜色和半透明 Alpha 通道对转换的累积影响...

var HSL2COLOR = function () 
    return function (hsl, bg) 
        function checkHex(v) 
            return 1 === v.length ? '0'+v : v;
        
        var data, r, g, b, a,
        cnv = document.createElement('canvas'),
        ctx = cnv.getContext('2d'),
        alpha = /a\(/.test(hsl),
        output = ;

        return cnv.width = cnv.height = 1,
        bg && (ctx.fillStyle = bg, ctx.fillRect(0, 0, 1, 1)),
        ctx.fillStyle = hsl,
        ctx.fillRect(0, 0, 1, 1),

        data = ctx.getImageData(0, 0, 1, 1).data,
        r = data[0],
        g = data[1],
        b = data[2],
        a = (data[3] / 255).toFixed(2),

        alpha ? (output.hsla = hsl, bg ? output.rgb = 'rgb('+r+','+g+','+b+')' : output.rgba = 'rgb('+r+','+g+','+b+','+a+')')  : (output.hsl = hsl, output.rgb = 'rgb('+r+','+g+','+b+')'),
        output.hex = '#'+checkHex(r.toString(16))+checkHex(g.toString(16))+checkHex(b.toString(16)),
        output;
    ;
();

// hsl: no alpha-channel + no background color
console.log(HSL2COLOR('hsl(170, 60%, 45%)'));
/*=>  
        hsl: "hsl(170, 60%, 45%)", 
        rgb: "rgb(45,183,160)", 
        hex: "#2db7a0" 
     
*/
// hsla: alpha-channel + no background color 
console.log(HSL2COLOR('hsla(170, 60%, 45%, 0.35)'));
/*=> 
        hsla: "hsla(170, 60%, 45%, 0.35)",
        rgba: "rgb(42,183,160,0.35)", 
        hex: "#2ab7a0" 
     
*/
// hsla: alpha-channel + background color
console.log(HSL2COLOR('hsla(170, 60%, 45%, 0.35)','#f00'));
/*=> 
        hsla: "hsla(170, 60%, 45%, 0.35)",
        rgb: "rgb(181,64,56)", 
        hex: "#b54038" 
     
*/

从上面的结果可以看出,当输入中有 alpha 通道但没有指定背景颜色时,HEX 值并不是特别具有代表性 - 因为画布基本上将透明背景视为黑色。尽管如此,rgba 值仍然保持一致。

无论如何,我实现了我需要的,也许这对某些人来说有时会有用。

BP

【讨论】:

【参考方案5】:

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

你可以在这里找到更多信息 - HSL to RGB color conversion

【讨论】:

【参考方案6】:

我制作了一个small library,可以轻松转换颜色。

这是我的 HSL 转 RGB 方法,它使用了库中的其他一些实用方法:

Color.hslToRgb = function(hsl, formatted) 
  var a, b, g, h, l, p, q, r, ref, s;
  if (isString(hsl)) 
    if (!hsl.match(Color.HSL_REGEX)) 
      return;
    
    ref = hsl.match(/hsla?\((.+?)\)/)[1].split(',').map(function(value) 
      value.trim();
      return parseFloat(value);
    ), h = ref[0], s = ref[1], l = ref[2], a = ref[3];
   else if ((isObject(hsl)) && (hasKeys(hsl, ['h', 's', 'l']))) 
    h = hsl.h, s = hsl.s, l = hsl.l, a = hsl.a;
   else 
    return;
  
  h /= 360;
  s /= 100;
  l /= 100;
  if (s === 0) 
    r = g = b = l;
   else 
    q = l < 0.5 ? l * (1 + s) : l + s - l * s;
    p = 2 * l - q;
    r = Color.hueToRgb(p, q, h + 1 / 3);
    g = Color.hueToRgb(p, q, h);
    b = Color.hueToRgb(p, q, h - 1 / 3);
  
  return getRgb(Math.round(r * 255), Math.round(g * 255), Math.round(b * 255), a, formatted);
;

如果您不想使用 npm,也可以在 GitHub 上找到该库。

【讨论】:

如果您想为人们提供除 NPM 之外的其他选择,因为这似乎是同构的,您可以在 bower 上发布它。

以上是关于将 Hsl 转换为 rgb 和 hex的主要内容,如果未能解决你的问题,请参考以下文章

rgb和hsl转换(js)

使用 Objective C 从 RGB 转换为 HSL

PHP 将HEX转换为RGB和RGB转换为HEX

如何将 RGB 颜色转换为 HSV?

求HEX色值转CMYK/HSL/HSB值的VBA代码

VB中HSL怎么转换为RGB?