【问题标题】:Why doesn't this Javascript RGB to HSL code work?为什么这个 Javascript RGB 到 HSL 代码不起作用?
【发布时间】:2011-01-21 20:37:33
【问题描述】:

我在http://www.mjijackson.com/2008/02/rgb-to-hsl-and-rgb-to-hsv-color-model-conversion-algorithms-in-javascript 找到了这个 RGB 到 HSL 的脚本。我找不到任何其他小的像样的。问题是这段代码甚至没有真正起作用。有人会知道为什么吗? (我不知道一点颜色数学,但也许它正在返回互补?)

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

编辑:当我运行 rgbToHsl(126,210,22) 时,它给了我 [ .24, .81, .45 ],这是橙色的 HSL。

【问题讨论】:

  • 问题标题和函数名不匹配,您到底在寻找什么 rgb to hsl 或 hsl to rgb?另请显示您使用该功能的代码。
  • 什么问题,什么值错了?
  • 它看起来对我有用,当我尝试它时,它肯定会返回一个好的 HSL 数组。是什么让你认为它不起作用?如果不清楚,您必须使用表示为 0 到 255 之间的十进制整数的 RGB 值来调用它。
  • 你的意思是说.24需要乘以360?我并没有完全意识到这一点 - 我希望它会像那样出现。
  • .24 是比率 24/100。自然地,如果您希望它脱离 360 度,您需要自己进行转换。

标签: javascript colors rgb hsl


【解决方案1】:

生成的 HSV 数组必须被解释为三个分数。对于某些程序,如果要将 HSV 表示为整数,则将“H”值乘以 360,将“S”和“V”值乘以 100。您为绿色阴影 RGB [126, 210, 22] 是 HSV [87, 81, 45] 的整数。如果您愿意,可以更改函数以返回此类整数:

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 [Math.floor(h * 360), Math.floor(s * 100), Math.floor(l * 100)];
}

[edit] 也就是说,它仍然给我一些亮度(“L”或“V”)相当暗的东西; Gimp 说 HSV 值应该是 [90, 80, 82],或者以小数形式表示 [.20, .80, .82]。

[another edit] 一个问题可能是 HSL 和 HSV 是不同的方案......仍在环顾四周。

如果有人想要将 RGB 转换为 HSV(例如您在 Gimp 中看到的),可以,这是一个版本:

function rgbToHsv(r, g, b) {
    var
        min = Math.min(r, g, b),
        max = Math.max(r, g, b),
        delta = max - min,
        h, s, v = max;

    v = Math.floor(max / 255 * 100);
    if ( max != 0 )
        s = Math.floor(delta / max * 100);
    else {
        // black
        return [0, 0, 0];
    }

    if( r == max )
        h = ( g - b ) / delta;         // between yellow & magenta
    else if( g == max )
        h = 2 + ( b - r ) / delta;     // between cyan & yellow
    else
        h = 4 + ( r - g ) / delta;     // between magenta & cyan

    h = Math.floor(h * 60);            // degrees
    if( h < 0 ) h += 360;

    return [h, s, v];
}

【讨论】:

  • rgbToHsv(210, 210, 210) 除以 0 h = ( g - b ) / delta;
  • @BrunoLM 它仍然是 0.0.1 alpha 版本 :-) 我怀疑只有当你给它一个中性(灰色)颜色时它才会这样做 - 我不确定应该怎么做那。我猜“色调”会是黑色,饱和度会是 100%,值可能是 max/255?我得再玩一会儿。
  • @Pointy 这正是我的测试:P。我解决了使用另一个 var 进行除法的问题。 var deltadiv = delta == 0 ? 1 : delta;。结果是0, 0, 82,在Photoshop 上告诉我它是rgb(209, 209, 209)。很公平:)
  • 这是您的代码,其中包含针对这种情况的修复程序以及我在另一个网站上找到的 HsvToRgbstackoverflow.com/questions/5833624/…
  • @BrunoLM 哇谢谢!!就个人而言,我目前没有使用这样的代码(在我当前的网站上),但是您对细节和完整性的关注肯定会改善未来 Stackoverflow 客户的体验:-)
【解决方案2】:

下面的函数将RGB颜色转换为像Photoshop颜色选择器一样的Hue Saturation Brightness颜色,结果在范围内:

  • 色相 0-360(度)
  • 饱和度:0-100 (%)
  • 亮度:0-100 (%)

我还是不明白为什么人们用HSV(Hue Saturation Value)这个词而不是HSB(Hue Saturation Brightness),反正是术语的问题,结果都是一样的

   //Converts to color HSB object (code from here http://www.csgnetwork.com/csgcolorsel4.html with some improvements)
   function rgb2hsb(r, g, b)
   {    
    r /= 255; g /= 255; b /= 255; // Scale to unity.   
    var minVal = Math.min(r, g, b),
    maxVal = Math.max(r, g, b),
    delta = maxVal - minVal,
    HSB = {hue:0, sat:0, bri:maxVal},
    del_R, del_G, del_B;

    if( delta !== 0 )
    {
        HSB.sat = delta / maxVal;
        del_R = (((maxVal - r) / 6) + (delta / 2)) / delta;
        del_G = (((maxVal - g) / 6) + (delta / 2)) / delta;
        del_B = (((maxVal - b) / 6) + (delta / 2)) / delta;

        if (r === maxVal) {HSB.hue = del_B - del_G;}
        else if (g === maxVal) {HSB.hue = (1 / 3) + del_R - del_B;}
        else if (b === maxVal) {HSB.hue = (2 / 3) + del_G - del_R;}

        if (HSB.hue < 0) {HSB.hue += 1;}
        if (HSB.hue > 1) {HSB.hue -= 1;}
    }

    HSB.hue *= 360;
    HSB.sat *= 100;
    HSB.bri *= 100;

    return HSB;
   }

使用示例:

var hsb = rgb2hsb(126,210,22);
alert("hue = " + hsb.hue + "saturation = " + hsb.sat + "brightness = " + hsb.bri);

【讨论】:

    【解决方案3】:

    简短但准确

    看起来您的代码没问题(但它返回 hue=0.24 - 将其乘以 360 度以获得角度整数值) - 但是尝试这个较短的代码(更多:hsl2rgbrgb2hsvhsv2rgbsl22sv):

    // in: r,g,b in [0,1], out: h in [0,360) and s,l in [0,1]
    function rgb2hsl(r,g,b) {
      let v=Math.max(r,g,b), c=v-Math.min(r,g,b), f=(1-Math.abs(v+v-c-1)); 
      let h= c && ((v==r) ? (g-b)/c : ((v==g) ? 2+(b-r)/c : 4+(r-g)/c)); 
      return [60*(h<0?h+6:h), f ? c/f : 0, (v+v-c)/2];
    }
    

    function rgb2hsl(r,g,b) {
      let v=Math.max(r,g,b), c=v-Math.min(r,g,b), f=(1-Math.abs(v+v-c-1)); 
      let h= c && ((v==r) ? (g-b)/c : ((v==g) ? 2+(b-r)/c : 4+(r-g)/c)); 
      return [60*(h<0?h+6:h), f ? c/f : 0, (v+v-c)/2];
    }
    
    console.log(`rgb: (0.36,0.3,0.24) --> hsl: (${rgb2hsl(0.36,0.3,0.24)})`);
    
    
    // ---------------
    // UX
    // ---------------
    
    rgb= [0,0,0];
    hs= [0,0,0];
    
    let $ = x => document.querySelector(x);
    
    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)];
    
    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(', ')
      tr = `RGB: ${rr}`
      th = `HSL: ${hs.map((x,i)=>i? (x*100).toFixed(2)+'%':x|0).join(', ')}`
      $('.box').style.backgroundColor=`rgb(${rr})`;  
      $('.infoRGB').innerHTML=`${tr}`;  
      $('.infoHS').innerHTML =`${th}`;  
      
      $('#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;  
    }
    
    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>

    我开发了 S_HSL wiki 公式(用绿色边框标记) - 其中 MAX=max(r,g,b) 和 MIN=min(r,g,b) - 在上面的代码中我做了一些改进并做出analysis 表明结果是正确的。这让我可以在最后得到相当短的代码

    【讨论】:

      【解决方案4】:

      你必须像hsl(155,100%,30%)一样更改为hsl格式,才能在HTML中使用。

      //this change hsl to :  "hsl(155,100%,30%)"
      function hsl2str({h,s,l,a=1}) {
          return "hsl("+h+","+s*100+"%,"+l*100+"%,"+a+")";
      }
      //for html, the h is 0-360, so you need this function
      function rgb2hsl({r,g,b,a=1}) {
          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;
              }
          }
      
          return {h: h*60,s,l,a};
      }
      

      【讨论】:

        猜你喜欢
        • 2012-07-28
        • 2012-02-22
        • 1970-01-01
        • 1970-01-01
        • 2013-12-19
        • 2018-11-05
        • 2023-03-03
        相关资源
        最近更新 更多