Variables

$hex
'#face75'
$rgb
hex2rgb($hex) 'rgb( 250, 206, 117 )'
$hsl
rgb2hsl($rgb) 'hsl( 40, 93.006993006993%, 71.960784313725% )'
$shsl
spin($hsl,180) 'hsl( 220, 93.006993006993%, 71.960784313725% )'
$srgb
hsl2rgb($shsl) 'rgb( 117, 161, 250 )'
$shex
rgb2hex($srgb) '#75a1fa'

Functions

Modifiers

Spin
function spin($hslarr, $degrees) {
   if (is_string($hslarr)) { $hslarr = rgbarr($hslarr); }

   $h = ($hslarr[0] + $degrees) % 360;
   $s = $hslarr[1];
   $l = $hslarr[2];

   return array($h,$s,$l);
}

Converters

Hex to RGB
function hex2rgb($hexstr) {
   $hexstr = str_replace('#', '', $hexstr);

   if (strlen($hexstr) == 3) {
      $r = hexdec(substr($hexstr,0,1) . substr($hexstr,0,1));
      $g = hexdec(substr($hexstr,1,1) . substr($hexstr,1,1));
      $b = hexdec(substr($hexstr,2,1) . substr($hexstr,2,1));
   } else {
      $r = hexdec(substr($hexstr,0,2));
      $g = hexdec(substr($hexstr,2,2));
      $b = hexdec(substr($hexstr,4,2));
   }

   return array($r,$g,$b); // returns an array with the rgb values
}
RGB to Hex
function rgb2hex($rgbarr) {
   if (is_string($rgbarr)) { $rgbarr = rgbarr($rgbarr); }

   $hexstr = '#';

   foreach ($rgbarr as $v) {
      $v = dechex($v);
      $hexstr .= $v;
   } unset($v);

   return $hexstr;
}
RGB to HSL
function rgb2hsl($rgbarr) {
   if (is_string($rgbarr)) { $rgbarr = rgbarr($rgbarr); }

   $r = $rgbarr[0] / 255; // convert to percentage
   $g = $rgbarr[1] / 255;
   $b = $rgbarr[2] / 255;
   $max = max($r,$g,$b);
   $min = min($r,$g,$b);
   $h = 0;
   $s = 0;
   $l = ($max + $min) / 2;
   $d = $max - $min;

   if ($d !== 0) {
      if ($l > .5) {
         $s = $d / (2 - $max - $min);
      } else {
         $s = $d / ($max + $min);
      }
      switch ($max) {
         case $r:
            //$h = 60 * fmod((($g - $b) / $d), 6);
            $h = 60 * (($g - $b) / $d + ($g < $b ? 6 : 0)); 
         break;
         case $g:
            $h = 60 * (($b - $r) / $d + 2); 
         break;
         case $b:
            $h = 60 * (($r - $g) / $d + 4);
         break;
      }
   }

   $h = round($h);

   return array($h,$s,$l);
}
HSL to RGB
function hsl2rgb($hslarr) {
   if (is_string($hslarr)) { $hslarr = hslarr($hslarr); }

   $h = abs($hslarr[0]);
   $s = $hslarr[1];
   $l = $hslarr[2];

   $c = ( 1 - abs( 2 * $l - 1 ) ) * $s;
   $x = $c * ( 1 - abs( fmod( ( $h / 60 ), 2 ) - 1 ) );
   $m = $l - ( $c / 2 );

   // I really think these can be made ternary as `$r = …;`, `$g = …;`, and `$b = …;` 
   if ($h < 60) {
      $r = round(($c + $m) * 255);
      $g = round(($x + $m) * 255);
      $b = round((0 + $m) * 255);
   } else if ($h < 120) {
      $r = round(($x + $m) * 255);
      $g = round(($c + $m) * 255);
      $b = round((0 + $m) * 255);
   } else if ($h < 180) {
      $r = round((0 + $m) * 255);
      $g = round(($c + $m) * 255);
      $b = round(($x + $m) * 255);
   } else if ($h < 240) {
      $r = round((0 + $m) * 255);
      $g = round(($x + $m) * 255);
      $b = round(($c + $m) * 255);
   } else if ($h < 300) {
      $r = round(($x + $m) * 255);
      $g = round((0 + $m) * 255);
      $b = round(($c + $m) * 255);
   } else {
      $r = round(($c + $m) * 255);
      $g = round((0 + $m) * 255);
      $b = round(($x + $m) * 255);
   }

   return array($r,$g,$b);
}

Utilities

Print RGB
function rgb($rgbarr) { return 'rgb( ' . implode(', ', $rgbarr) . ' )'; }
Print HSL
function hsl($hslarr) {
   $hslarr[1] *= 100; $hslarr[1] .= '%';
   $hslarr[2] *= 100; $hslarr[2] .= '%';
   return 'hsl( ' . implode(', ', $hslarr) . ' )';
}
Parse RGB
function rgbarr($rgbstr) {
   $rgbstr = str_replace(array('rgb(',')',' '), '', $rgbstr);
   $rgbarr = explode(',', $rgbstr);
   return $rgbarr;
}
Parse HSL
function hslarr($hslstr) {
   $hslstr = str_replace(array('hsl(',')','%',' '), '', $hslstr);
   $hslarr = explode(',', $hslstr);
   $hslarr[1] /= 100; $hslarr[2] /= 100;
   return $hslarr;
}

List of Functions

  • spin($hslarr, $degrees)
  • hex2rgb($hexstr)
  • rgb2hex($rgbarr)
  • rgb2hsl($rgbarr)
  • hsl2rgb($hslarr)
  • rgb($rgbarr)
  • hsl($hslarr)
  • rgbarr($rgbstr)
  • hslarr($hslstr)

The Color Class

Usage Example

$color = new Color ('#6c2c3a');
echo $color->hex; // #6c2c3a
echo $color->rgb; // rgb( 108, 44, 58 )
echo $color->hsl; // hsl( 347, 42.105263157895%, 29.803921568627% )

echo $color->spin(180)->hex; // #2c6c5e
echo $color->rgb; // rgb( 44, 108, 94 )
echo $color->hsl; // hsl( 167, 42.105263157895%, 29.803921568627% )

echo $color->spin(180)->darken(10)->hex; // #481d26
echo $color->rgb; // rgb( 72, 29, 38 )
echo $color->hsl; // hsl( 347, 42.105263157895%, 19.803921568627% )

$new = new Color ('#e55');
echo $new->hex;   // #e55
echo $new->rgb;   // rgb( 238, 85, 85 )
echo $new->hsl;   // hsl( 0, 81.818181818182%, 63.333333333333% )

$mixed = $color->mix($new,60);
echo $mixed;      // #8a3338

$mixed = new Color ($mixed);
echo $mixed->hex; // #8a3338
echo $mixed->rgb; // rgb( 138, 51, 56 )
echo $mixed->hsl; // hsl( 357, 46.031746031746%, 37.058823529412% )

Note: Comments show the results of the co-linear code.

Definition

View Docs Color Class Definition
class Color {

   /*! properties */

   public  $hex = '#000';
   public  $rgb = 'rgb( 0, 0, 0 )';
   public  $hsl = 'hsl( 0, 0%, 0% )';

   private $_rgb = array(0,0,0);
   private $_hsl = array(0,0,0);
   
   // uncomment when implementing alpha support
/*
   private $alpha = 1;
   private $ahex  = '#ff000000';
   private $rgba  = 'rgba( 0, 0, 0, 1 )';
   private $hsla  = 'hsla( 0, 0, 0, 1 )';
*/

   /*! init */

   public function __construct($input = '#000') {
      if (is_string($input)) {
         if (strpos($input, '#') === 0) {
            $this->hex = $input;
            $this->update('hex');
         } else if (strpos($input, 'rgb') === 0) {
            $this->rgb = $input;
            $this->update('rgb');
         } else if (strpos($input, 'hsl') === 0) {
            $this->hsl = $input;
            $this->update('hsl');
         } else { error_log('Color Object sez: I need a valid hex, rgb, or hsl color string.'); }
      }
      return $this;
   }
   public function __clone() {
      return new Color ($this->hex);
   }

   /*! color methods returning new colors */

   public function mix($color2, $weight = 50) {
      if (is_string($color2)) {
         if (strpos($color2, '#') === 0) {
            $color2 = hex2rgb($color2);
         } else if (strpos($color2, 'rgb') === 0) {
            $color2 = explode(',',str_replace(array('rgb(',')',' '),'',$color2));
         } else if (strpos($color2, 'hsl') === 0) {
            $color2 = hsl2rgb(explode(',',str_replace(array('hsl(',')',' ','%'),'',$color2)));
         } else {
            error_log(
               'Mix Method sez: I need a valid hex, rgb, or hsl ' .
               'string or a Color object in order to mix.');
            return false;
         }
      } else if (is_object($color2) && get_class($color2) === 'Color') {
         $color2 = explode(',',str_replace(array('rgb(',')',' '),'',$color2->rgb));
      } else {
         error_log(
            'Mix Method sez: I need a valid hex, rgb, or hsl ' .
            'string or a Color object in order to mix.');
         return false;
      }
      // validate `$weight`
      $weight = $weight * 1;
      if (! is_numeric($weight)) {
         error_log(
            'Mix Method sez: If you pass me a `$weight`, it\'s ' .
            'gotta be a number or percentage string.');
         return false;
      }
      // convert `$weight` from percentage to decimal
      $w1 = ($weight * 1) / 100;
      
      // uncomment when implementing alpha support
/*
      // factor in the alpha channels
      $w = $w1 * 2 - 1;
      $a = $this->alpha - $colorObject2->alpha;
      $w = ($w * $a === -1) ? $w : ($w + $a) / (1 + $w * $a);
      // set new `$w1`, weighted with alpha channels
      $w1 = ($w + 1) / 2;
*/
      $w2 = 1 - $w1;

      $mixr = $this->_rgb[0] * $w1 + $color2[0] * $w2;
      $mixg = $this->_rgb[1] * $w1 + $color2[1] * $w2;
      $mixb = $this->_rgb[2] * $w1 + $color2[2] * $w2;
      
      // uncomment when implementing alpha support
/*
      $mixa = $this->_rgb[3] * $w1 + $color2[3] * $w2;
      if ($mixa < 1) {
         // return rgba() if alpha isn't 1
         return $this->rgb(array($mixr,$mixg,$mixb,$mixa));
      } else {
         // otherwise, return hex
         return $this->rgb2hex(array($mixr,$mixg,$mixb));
      }
*/

      // return hex string
      return $this->rgb2hex(array($mixr,$mixg,$mixb));
   }

   /*! color methods returning this color */

   public function spin($degrees) {
      // check if `$degrees` is valid
      if (is_string($degrees)) { floatval(ereg_replace("[^-0-9\.]","",$degrees)); }

      // modulus (`%`) keeps the hue between -360 and 360
      $h = ($this->_hsl[0] + $degrees) % 360;
      $s = $this->_hsl[1];
      $l = $this->_hsl[2];

      $this->_hsl = array($h,$s,$l);
      $this->update('_hsl');
      // allows chainability
      return $this;
   }
   public function lighten($percent) {
      // check if `$percent` is valid
      if (is_string($percent)) { floatval(ereg_replace("[^-0-9\.]","",$percent)); }

      $h = $this->_hsl[0];
      $s = $this->_hsl[1];
      // ensure `$l` is no lower than 0% and no higher than 100%
      $l = min(1, max(0, $this->_hsl[2] + $percent / 100));

      $this->_hsl = array($h,$s,$l);
      $this->update('_hsl');
      return $this;
   }
   public function darken($percent) {
      if (is_string($percent)) { floatval(ereg_replace("[^-0-9\.]","",$percent)); }

      $h = $this->_hsl[0];
      $s = $this->_hsl[1];
      $l = min(1, max(0, $this->_hsl[2] - $percent / 100));

      $this->_hsl = array($h,$s,$l);
      $this->update('_hsl');
      return $this;
   }
   public function saturate($percent) {
      if (is_string($percent)) { floatval(ereg_replace("[^-0-9\.]","",$percent)); }

      $h = $this->_hsl[0];
      $s = min(1, max(0, $this->_hsl[1] + $percent / 100));
      $l = $this->_hsl[2];

      $this->_hsl = array($h,$s,$l);
      $this->update('_hsl');
      return $this;
   }
   public function desaturate($percent) {
      if (is_string($percent)) { floatval(ereg_replace("[^-0-9\.]","",$percent)); }

      $h = $this->_hsl[0];
      $s = min(1, max(0, $this->_hsl[1] - $percent / 100));
      $l = $this->_hsl[2];

      $this->_hsl = array($h,$s,$l);
      $this->update('_hsl');
      return $this;
   }

   /*! color format converters */

   private function hex2rgb($strhex) {
      $strhex = str_replace('#', '', $strhex);

      if (strlen($strhex) == 3) {
         $r = hexdec(substr($strhex,0,1) . substr($strhex,0,1));
         $g = hexdec(substr($strhex,1,1) . substr($strhex,1,1));
         $b = hexdec(substr($strhex,2,1) . substr($strhex,2,1));
      } else {
         $r = hexdec(substr($strhex,0,2));
         $g = hexdec(substr($strhex,2,2));
         $b = hexdec(substr($strhex,4,2));
      }

      return array($r,$g,$b);
   }
   private function rgb2hex($rgbarr) {
      $hexstr = '#';
      
      foreach ($rgbarr as $v) {
         $v = dechex($v);
         if (strlen($v) < 2) { $v = '0' . $v; } // zero fill
         if (strlen($v) < 2) { $v = '0' . $v; } // double check
         $hexstr .= $v;
      } unset($v);
      
      return $hexstr;
   }
   private function rgb2hsl($rgbarr) {
      $r = $rgbarr[0] / 255;
      $g = $rgbarr[1] / 255;
      $b = $rgbarr[2] / 255;
      $max = max($r,$g,$b);
      $min = min($r,$g,$b);
      $h = 0;
      $s = 0;
      $l = ($max + $min) / 2;
      $d = $max - $min;

      if ($d !== 0) {
         if ($l > .5) {
            $s = $d / (2 - $max - $min);
         } else {
            $s = $d / ($max + $min);
         }
         switch ($max) {
            case $r:
               $h = 60 * (($g - $b) / $d + ($g < $b ? 6 : 0)); 
            break;
            case $g:
               $h = 60 * (($b - $r) / $d + 2); 
            break;
            case $b:
               $h = 60 * (($r - $g) / $d + 4);
            break;
         }
      }

      $h = round($h);

      return array($h,$s,$l);
   }
   private function hsl2rgb($hslarr) {
      $h = abs($hslarr[0]);
      $s = $hslarr[1];
      $l = $hslarr[2];

      $c = ( 1 - abs( 2 * $l - 1 ) ) * $s;
      $x = $c * ( 1 - abs( fmod( ( $h / 60 ), 2 ) - 1 ) );
      $m = $l - ( $c / 2 );
      if ($h < 60) {
         $r = round(($c + $m) * 255);
         $g = round(($x + $m) * 255);
         $b = round((0 + $m) * 255);
      } else if ($h < 120) {
         $r = round(($x + $m) * 255);
         $g = round(($c + $m) * 255);
         $b = round((0 + $m) * 255);
      } else if ($h < 180) {
         $r = round((0 + $m) * 255);
         $g = round(($c + $m) * 255);
         $b = round(($x + $m) * 255);
      } else if ($h < 240) {
         $r = round((0 + $m) * 255);
         $g = round(($x + $m) * 255);
         $b = round(($c + $m) * 255);
      } else if ($h < 300) {
         $r = round(($x + $m) * 255);
         $g = round((0 + $m) * 255);
         $b = round(($c + $m) * 255);
      } else {
         $r = round(($c + $m) * 255);
         $g = round((0 + $m) * 255);
         $b = round(($x + $m) * 255);
      }

      return array($r,$g,$b);
   }

   /*! array & string converters */

   private function rgb($rgbarr) { return 'rgb( ' . implode(', ', $rgbarr) . ' )'; }
   private function hsl($hslarr) {
      $hslarr[1] *= 100; $hslarr[1] .= '%';
      $hslarr[2] *= 100; $hslarr[2] .= '%';
      return 'hsl( ' . implode(', ', $hslarr) . ' )';
   }
   private function rgbExplode($rgbstr) {
      $_rgb = explode(',',str_replace(array('rgb(',')',' '),'',$rgbstr));
      $_rgb[0] /= 1;
      $_rgb[1] /= 1;
      $_rgb[2] /= 1;
      return $_rgb;
   }
   private function hslExplode($hslstr) {
      $_hsl = explode(',',str_replace(array('hsl(',')',' ','%'),'',$hslstr));
      $_hsl[1] /= 100;
      $_hsl[2] /= 100;
      return $_hsl;
   }

   /*! update */
   
   private function update($fromThis = '_hsl') { // default, 'cause methods use hsl
      switch ($fromThis) {
         case 'hex':
            $this->_rgb = $this->hex2rgb($this->hex);
            $this->rgb  = $this->rgb($this->_rgb);
            $this->_hsl = $this->rgb2hsl($this->_rgb);
            $this->hsl  = $this->hsl($this->_hsl);
         break;
         case 'rgb':
            $this->_rgb = $this->rgbExplode($this->rgb);
            $this->_hsl = $this->rgb2hsl($this->_rgb);
            $this->hsl  = $this->hsl($this->_hsl);
            $this->hex  = $this->rgb2hex($this->_rgb);
         break;
         case 'hsl':
            $this->_hsl = $this->hslExplode($this->hsl);
            $this->_rgb = $this->hsl2rgb($this->_hsl);
            $this->rgb  = $this->rgb($this->_rgb);
            $this->hex  = $this->rgb2hex($this->_rgb);
         break;
         case '_rgb':
         case 'rgbarr':
            $this->rgb  = $this->rgb($this->_rgb);
            $this->_hsl = $this->rgb2hsl($this->_rgb);
            $this->hsl  = $this->hsl($this->_hsl);
            $this->hex  = $this->rgb2hex($this->_rgb);
         break;
         case '_hsl':
         case 'hslarr':
            $this->hsl  = $this->hsl($this->_hsl);
            $this->_rgb = $this->hsl2rgb($this->_hsl);
            $this->rgb  = $this->rgb($this->_rgb);
            $this->hex  = $this->rgb2hex($this->_rgb);
         break;
         // throws an error if `$fromThis` doesn't match any of the above cases
         default:
            error_log('Update sez: Bad argument ("' . $fromThis . '").');
         break;
      }
   }
}

Tests & Debugging

$a = new Color ('#5ad');
hex: '#5ad'
rgb: 'rgb( 85, 170, 221 )'
hsl: 'hsl( 203, 66.666666666667%, 60% )'

$a->darken(10)->spin(5);
hex: '#2b85d5'
rgb: 'rgb( 43, 133, 213 )'
hsl: 'hsl( 208, 66.666666666667%, 50% )'

$b = new Color ('#6c2c3a');
hex: '#6c2c3a'
rgb: 'rgb( 108, 44, 58 )'
hsl: 'hsl( 347, 42.105263157895%, 29.803921568627% )'

$b->darken(10)->spin(5);
hex: '#481d23'
rgb: 'rgb( 72, 29, 35 )'
hsl: 'hsl( 352, 42.105263157895%, 19.803921568627% )'

$c = new Color ('#1ff');
hex: '#1ff'
rgb: 'rgb( 17, 255, 255 )'
hsl: 'hsl( 180, 100%, 53.333333333333% )'

$c->darken(10)->spin(5);
hex: '#00cbdd'
rgb: 'rgb( 0, 203, 221 )'
hsl: 'hsl( 185, 100%, 43.333333333333% )'