0

Does anyone know how to convert a Hex color to HSL in PHP? I've searched but the functions that I’ve found don’t convert precisely the color.

Marc Duluc
  • 51
  • 2
  • 5
  • Does this answer your question? [PHP function to convert HSL to RGB or Hex](https://stackoverflow.com/questions/20423641/php-function-to-convert-hsl-to-rgb-or-hex) – abc Nov 19 '19 at 10:37
  • Thanks for the reply. Unfortunately no, I want to convert Hex to HSL not HSL to Hex. – Marc Duluc Nov 19 '19 at 10:53

3 Answers3

2

I think the mistake in the second answer is using integer division rather than fmod() when calculating the hue when red is the maximum colour value $hue = (($green - $blue) / $delta) % 6;

I think the mistake in the first answer is in the saturation calculation - for me $s = $l > 0.5 ? $diff / (2 - $max - $min) : $diff / ($max + $min); is a bit confusing to unpick

Since usually when I want to convert RGB to HSL I want to adjust the lightness value to make a lighter or darker version of the same colour, I have built that into the function below by adding an optional $ladj percent value.

The $hex parameter can be either a hex string (with or without the '#') or an array of RGB values (between 0 and 255)

The return value is an HSL string ready to drop straight in to a CSS colour. ie the values are from 0 to 359 for hue and 0 to 100% for saturation and lightness.

I think this works correctly (based on https://gist.github.com/brandonheyer/5254516)

function hex2hsl($RGB, $ladj = 0) {
//have we got an RGB array or a string of hex RGB values (assume it is valid!)
    if (!is_array($RGB)) {
        $hexstr = ltrim($RGB, '#');
        if (strlen($hexstr) == 3) {
            $hexstr = $hexstr[0] . $hexstr[0] . $hexstr[1] . $hexstr[1] . $hexstr[2] . $hexstr[2];
        }
        $R = hexdec($hexstr[0] . $hexstr[1]);
        $G = hexdec($hexstr[2] . $hexstr[3]);
        $B = hexdec($hexstr[4] . $hexstr[5]);
        $RGB = array($R,$G,$B);
    }
// scale the RGB values to 0 to 1 (percentages)
    $r = $RGB[0]/255;
    $g = $RGB[1]/255;
    $b = $RGB[2]/255;
    $max = max( $r, $g, $b );
    $min = min( $r, $g, $b );
// lightness calculation. 0 to 1 value, scale to 0 to 100% at end
    $l = ( $max + $min ) / 2;
        
// saturation calculation. Also 0 to 1, scale to percent at end.
    $d = $max - $min;
    if( $d == 0 ){
// achromatic (grey) so hue and saturation both zero
        $h = $s = 0; 
    } else {
        $s = $d / ( 1 - abs( (2 * $l) - 1 ) );
// hue (if not grey) This is being calculated directly in degrees (0 to 360)
        switch( $max ){
            case $r:
                $h = 60 * fmod( ( ( $g - $b ) / $d ), 6 );
                if ($b > $g) { //will have given a negative value for $h
                    $h += 360;
                }
                break;
            case $g:
                $h = 60 * ( ( $b - $r ) / $d + 2 );
                break;
            case $b:
                $h = 60 * ( ( $r - $g ) / $d + 4 );
                break;
        } //end switch
    } //end else 
// make any lightness adjustment required
    if ($ladj > 0) {
        $l += (1 - $l) * $ladj/100;
    } elseif ($ladj < 0) {
        $l += $l * $ladj/100;
    }
//put the values in an array and scale the saturation and lightness to be percentages
    $hsl = array( round( $h), round( $s*100), round( $l*100) );
//we could return that, but lets build a CSS compatible string and return that instead
    $hslstr = 'hsl('.$hsl[0].','.$hsl[1].'%,'.$hsl[2].'%)';
    return $hslstr;
}

In real life I would break out the hex string to RGB array conversion and the percentage adjustment into separate functions, but have included them here for completeness.

You could also use the percent adjustment to shift the hue or saturation once you've got the colour in HSL format.

RogerCO
  • 21
  • 3
0
function hexToHsl($hex) {
    $hex = array($hex[0].$hex[1], $hex[2].$hex[3], $hex[4].$hex[5]);
    $rgb = array_map(function($part) {
        return hexdec($part) / 255;
    }, $hex);

    $max = max($rgb);
    $min = min($rgb);

    $l = ($max + $min) / 2;

    if ($max == $min) {
        $h = $s = 0;
    } else {
        $diff = $max - $min;
        $s = $l > 0.5 ? $diff / (2 - $max - $min) : $diff / ($max + $min);

        switch($max) {
            case $rgb[0]:
                $h = ($rgb[1] - $rgb[2]) / $diff + ($rgb[1] < $rgb[2] ? 6 : 0);
                break;
            case $rgb[1]:
                $h = ($rgb[2] - $rgb[0]) / $diff + 2;
                break;
            case $rgb[2]:
                $h = ($rgb[0] - $rgb[1]) / $diff + 4;
                break;
        }

        $h /= 6;
    }

    return array($h, $s, $l);
}
Piyush Shukla
  • 244
  • 1
  • 11
  • you might want to show the original [source](https://gist.github.com/bedeabza/10463089) of this script... – lovelace Nov 19 '19 at 09:57
  • I've already tried this one. It's not working properly for some colors. For example for #fbffe0 the HSL should be (68, 100%, 94%) which it isn't the case with the function. – Marc Duluc Nov 19 '19 at 10:27
-1

Rewritten (and adjusted a bit) from javascript from https://css-tricks.com/converting-color-spaces-in-javascript/

<?php

function hexToHsl($hex)
{
    $red = hexdec(substr($hex, 0, 2)) / 255;
    $green = hexdec(substr($hex, 2, 2)) / 255;
    $blue = hexdec(substr($hex, 4, 2)) / 255;

    $cmin = min($red, $green, $blue);
    $cmax = max($red, $green, $blue);
    $delta = $cmax - $cmin;

    if ($delta === 0) {
        $hue = 0;
    } elseif ($cmax === $red) {
        $hue = (($green - $blue) / $delta) % 6;
    } elseif ($cmax === $green) {
        $hue = ($blue - $red) / $delta + 2;
    } else {
        $hue = ($red - $green) / $delta + 4;
    }

    $hue = round($hue * 60);
    if ($hue < 0) {
        $hue += 360;
    }

    $lightness = (($cmax + $cmin) / 2) * 100;
    $saturation = $delta === 0 ? 0 : ($delta / (1 - abs(2 * $lightness - 1))) * 100;
    if ($saturation < 0) {
        $saturation += 100;
    }

    $lightness = round($lightness);
    $saturation = round($saturation);

    return "hsl(${hue}, ${saturation}%, ${lightness}%)";
}

Example:

<?php

echo hexToHsl('fbffe0'); // outputs 'hsl(68, 100%, 94%)'
Rikudou_Sennin
  • 1,357
  • 10
  • 27
  • Thanks for your reply. While it's working for # fbffe0, it's not working properly for some colors. For example for #f5efe1 the HSL should be (42, 50%, 92%) whereas the function returns hsl (0, 100%, 92%). The yellow shade is turned into pink shade. – Marc Duluc Nov 19 '19 at 16:08
  • Not output correct hsl value – Prince Ahmed Jul 04 '22 at 01:28