Why doesn't this Javascript RGB to HSL code work?

前端 未结 4 1037
独厮守ぢ
独厮守ぢ 2020-11-27 07:31

I found this RGB to HSL script over at http://www.mjijackson.com/2008/02/rgb-to-hsl-and-rgb-to-hsv-color-model-conversion-algorithms-in-javascript. I can\'t find any other s

相关标签:
4条回答
  • 2020-11-27 07:43

    Function below converts RGB color into Hue Saturation Brightness color like Photoshop color picker, results are in the ranges:

    • Hue 0-360 (degrees)
    • Saturation: 0-100 (%)
    • Brightness: 0-100 (%)

    I still don't understand why people use the term HSV (Hue Saturation Value) instead of HSB (Hue Saturation Brightness), anyway it's a matter fo terminology, the results are the same

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

    Usage example:

    var hsb = rgb2hsb(126,210,22);
    alert("hue = " + hsb.hue + "saturation = " + hsb.sat + "brightness = " + hsb.bri);
    
    0 讨论(0)
  • 2020-11-27 07:48

    The resulting HSV array has to be interpreted as three fractions. For some programs, if you want to express HSV as integers, you multiply the "H" value by 360 and the "S" and "V" values by 100. The HSV value you quote for your green shade RGB[126, 210, 22] is HSV [87, 81, 45] in integers. You could change the function to return such integers if you want to:

    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] that said, it's still giving me something with a brightness ("L" or "V") that's considerably too dark; Gimp says that the HSV value should be [90, 80, 82], or in fractional terms [.20, .80, .82].

    [another edit] well one problem could be that HSL and HSV are different schemes ... still looking around.

    OK in case anybody wants RGB to HSV (like you'd see in Gimp for example) here's a version of that:

    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];
    }
    
    0 讨论(0)
  • 2020-11-27 07:50

    You have to change to the hsl format just like hsl(155,100%,30%), that can be use in 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};
    }
    
    0 讨论(0)
  • 2020-11-27 08:01

    Short but precise

    It looks that your code is ok (but it returns hue=0.24 - multiply this by 360 degree to get angle integer value) - however Try this shorter one ( more: hsl2rgb, rgb2hsv, hsv2rgb and sl22sv):

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

    I develop S_HSL wiki formulas (marked by green border) - where MAX=max(r,g,b) and MIN=min(r,g,b) - and in above code I make some improvements and make analysis which shows that results are correct. This allows me to get quite short code at the end

    0 讨论(0)
提交回复
热议问题