Convert HSB/HSV color to HSL

2019-01-18 13:36发布

Ho do I convert HSB color to HSL?

Photoshop shows HSB color in its color picker. HSL color can be used in CSS.

I tried this JS:

function hsb2hsl(h, s, b) {
  return {
    h: h,
    s: s,
    l: b-s/2
  }
}

But hsb2hsl(0, 100, 50).l == 0 instead of 25

Update: Can I do that without converting HSB → RGB → HSL?

8条回答
家丑人穷心不美
2楼-- · 2019-01-18 14:17

Let's picture what actually are HSB(V), HSL, and how are constructed:

Convert HSB to HSL - Color picker

Hue color value goes from 0 to 360 degrees (where 0 is red) for both HSB and HSL.
On top of HUE are applied this linear gradient layers

HSB (also known as HSV)

  • Hue
  • Saturation = (from left) WhiteTransparent
  • Brightness (Value) = (from bottom) BlackTransparent

HSL

  • Hue
  • Saturation = (from left) Gray50%(#808080, RGB128,128,128) → Transparent
  • Lightness = (from bottom) BlackTransparentWhite

Let's see how to do the SB > SL > SB having:

var H  = 360,        // Values 0-360 but we'll use red by default
    SB = {s:0, b:0}, // Values 0-1
    SL = {s:0, l:0}; // Values 0-1

Conversion

function sb2sl() {
  SL.l = (2 - SB.s) * SB.b / 2;
  SL.s = SL.l&&SL.l<1 ? SB.s*SB.b/(SL.l<0.5 ? SL.l*2 : 2-SL.l*2) : SL.s;
}
function sl2sb() {
  var t = SL.s * (SL.l<0.5 ? SL.l : 1-SL.l);
  SB.b = SL.l+t;
  SB.s = SL.l>0 ? 2*t/SB.b : SB.s ;
}

To convert to non-floated %percent values do like:

(SB.s * 100 |0) // |0 removes floats

Here's a practical example:

var $SB = $("#SB"), $SBdot = $SB.find("span"), $SBres = $("#SBres"),
    $SL = $("#SL"), $SLdot = $SL.find("span"), $SLres = $("#SLres"),
    size = $SB.width(), // the area W,H size
    SB = {s:0, b:0}, // Values 0-1
    SL = {s:0, l:0}; // Values 0-1

function sb2sl() {
  SL.l = (2 - SB.s) * SB.b / 2;
  SL.s = SL.l&&SL.l<1 ? SB.s*SB.b/(SL.l<0.5 ? SL.l*2 : 2-SL.l*2) : SL.s;
}
function sl2sb() {
  var t = SL.s * (SL.l<0.5 ? SL.l : 1-SL.l);
  SB.b = SL.l+t;
  SB.s = SL.l>0 ? 2*t/SB.b : SB.s ;
}

$SB.add( $SL ).on("mousemove", function(e){

  var cr = this.getBoundingClientRect();
  var x  = e.clientX - cr.left |0;
  var y  = e.clientY - cr.top  |0;

  if(this.id==="SB") { // Mouse over #SB ?

    // Mouse position to 0-1 SB values
    SB.s =    x / (size-1);
    SB.b = 1- y / (size-1);
    // Convert inally SB to SL
    sb2sl();
    // Move dots
    $SBdot.css({left:x, top:y});
    $SLdot.css({left: SL.s*size, top:size-(SL.l*size)});

  }else{

    // Mouse position to SL 0-1 values
    SL.s =    x / (size-1);
    SL.l = 1- y / (size-1);
    // Convert finally SL to SB
    sl2sb();
    // Move dots
    $SLdot.css({left:x, top:y});
    $SBdot.css({left: SB.s*size, top:size-(SB.b*size)});

  }

  // Write textual results
  $SBres.html("S:"+ (SB.s*100|0) +"%<br> B:"+ (SB.b*100|0)+"%");
  $SLres.html("S:"+ (SL.s*100|0) +"%<br> L:"+ (SL.l*100|0)+"%");

});
body{margin:0 20px;font:12px/1.2 sans-serif;}
body>div{display:inline-block;margin: 20px;}
#SL,
#SB{
  position:relative;
  width:120px; height:120px;
  cursor:crosshair;
}
#SB{
  background:
    linear-gradient(to bottom, transparent, #000),
    linear-gradient(to right, #fff, transparent),
    red;
}
#SL{
  background:
    linear-gradient(to bottom, #fff, transparent, #000),
    linear-gradient(to right, #808080, transparent),
    red
}
#SL span,
#SB span{
  position:absolute;
  width:9px; height:9px;
  margin:-4px;
  border-radius:50%;
  box-shadow:0 0 0 1px #fff, 0 0 0 2px #000;
  pointer-events:none;
}
#SB span{left:100%; top:0;}
#SL span{left:100%; top:50%;}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<div>
  <b>HSB(HSV)</b>
  <div id="SB"><span></span></div>
  <p id="SBres">S:100%<br>B:100%</p>
</div>

<div>
  <b>HSL</b>
  <div id="SL"><span></span></div>
  <p id="SLres">S:100%<br>L:50%</p>
</div>

查看更多
三岁会撩人
3楼-- · 2019-01-18 14:19

Stephen Morley seems to have nailed it here.

Specifically:

/* Calculates and stores the HSL components of this HSVColour so that they can
 * be returned be the getHSL function.
 */
function calculateHSL(){
  // determine the lightness in the range [0,100]
  var l = (2 - hsv.s / 100) * hsv.v / 2;

  // store the HSL components
  hsl =
    {
      'h' : hsv.h,
      's' : hsv.s * hsv.v / (l < 50 ? l * 2 : 200 - l * 2),
      'l' : l
    };

  // correct a division-by-zero error
  if (isNaN(hsl.s)) hsl.s = 0;
}

He uses [0-360] for hue and [0-100] for the other values.

查看更多
登录 后发表回答