Skip to content

Instantly share code, notes, and snippets.

@Davidlab
Created September 15, 2015 13:42
Show Gist options
  • Save Davidlab/b40641fba36cd14504fd to your computer and use it in GitHub Desktop.
Save Davidlab/b40641fba36cd14504fd to your computer and use it in GitHub Desktop.
phpColors w/percent to white or black
<?php
/**
* Author: Arlo Carreon <http://arlocarreon.com>
* Info: http://mexitek.github.io/phpColors/
* License: http://arlo.mit-license.org/
*/
namespace Mexitek\PHPColors;
use \Exception;
/**
* A color utility that helps manipulate HEX colors
*/
class Color{
private $_hex;
private $_hsl;
private $_rgb;
/**
* Auto darkens/lightens by 10% for sexily-subtle gradients.
* Set this to FALSE to adjust automatic shade to be between given color
* and black (for darken) or white (for lighten)
*/
const DEFAULT_ADJUST = 10;
/**
* Instantiates the class with a HEX value
*
* @param string $hex
*
* @throws Exception "Bad color format"
*/
function __construct($hex){
// Strip # sign is present
$color = str_replace("#", "", $hex);
// Make sure it's 6 digits
if(strlen($color) === 3){
$color = $color[0] . $color[0] . $color[1] . $color[1] . $color[2] . $color[2];
}else if(strlen($color) != 6){
throw new Exception("HEX color needs to be 6 or 3 digits long");
}
$this->_hsl = self::hexToHsl($color);
$this->_hex = $color;
$this->_rgb = self::hexToRgb($color);
}
// ====================
// = Public Interface =
// ====================
/**
* Given a HEX string returns a HSL array equivalent.
*
* @param string $color
*
* @return array HSL associative array
*/
public static function hexToHsl($color){
// Sanity check
$color = self::_checkHex($color);
// Convert HEX to DEC
$R = hexdec($color[0] . $color[1]);
$G = hexdec($color[2] . $color[3]);
$B = hexdec($color[4] . $color[5]);
$HSL = array();
$var_R = ($R / 255);
$var_G = ($G / 255);
$var_B = ($B / 255);
$var_Min = min($var_R, $var_G, $var_B);
$var_Max = max($var_R, $var_G, $var_B);
$del_Max = $var_Max - $var_Min;
$L = ($var_Max + $var_Min) / 2;
if($del_Max == 0){
$H = 0;
$S = 0;
}else{
if($L < 0.5){
$S = $del_Max / ($var_Max + $var_Min);
}else{
$S = $del_Max / (2 - $var_Max - $var_Min);
}
$del_R = ((($var_Max - $var_R) / 6) + ($del_Max / 2)) / $del_Max;
$del_G = ((($var_Max - $var_G) / 6) + ($del_Max / 2)) / $del_Max;
$del_B = ((($var_Max - $var_B) / 6) + ($del_Max / 2)) / $del_Max;
if($var_R == $var_Max){
$H = $del_B - $del_G;
}else if($var_G == $var_Max){
$H = (1 / 3) + $del_R - $del_B;
}else if($var_B == $var_Max){
$H = (2 / 3) + $del_G - $del_R;
}
if($H < 0){
$H ++;
}
if($H > 1){
$H --;
}
}
$HSL['H'] = ($H * 360);
$HSL['S'] = $S;
$HSL['L'] = $L;
return $HSL;
}
/**
* Given a HSL associative array returns the equivalent HEX string
*
* @param array $hsl
*
* @return string HEX string
* @throws Exception "Bad HSL Array"
*/
public static function hslToHex($hsl = array()){
// Make sure it's HSL
if(empty($hsl) || !isset($hsl["H"]) || !isset($hsl["S"]) || !isset($hsl["L"])){
throw new Exception("Param was not an HSL array");
}
list($H, $S, $L) = array($hsl['H'] / 360, $hsl['S'], $hsl['L']);
if($S == 0){
$r = $L * 255;
$g = $L * 255;
$b = $L * 255;
}else{
if($L < 0.5){
$var_2 = $L * (1 + $S);
}else{
$var_2 = ($L + $S) - ($S * $L);
}
$var_1 = 2 * $L - $var_2;
$r = round(255 * self::_huetorgb($var_1, $var_2, $H + (1 / 3)));
$g = round(255 * self::_huetorgb($var_1, $var_2, $H));
$b = round(255 * self::_huetorgb($var_1, $var_2, $H - (1 / 3)));
}
// Convert to hex
$r = dechex($r);
$g = dechex($g);
$b = dechex($b);
// Make sure we get 2 digits for decimals
$r = (strlen("" . $r) === 1) ? "0" . $r : $r;
$g = (strlen("" . $g) === 1) ? "0" . $g : $g;
$b = (strlen("" . $b) === 1) ? "0" . $b : $b;
return $r . $g . $b;
}
/**
* Given a HEX string returns a RGB array equivalent.
*
* @param string $color
*
* @return array RGB associative array
*/
public static function hexToRgb($color){
// Sanity check
$color = self::_checkHex($color);
// Convert HEX to DEC
$R = hexdec($color[0] . $color[1]);
$G = hexdec($color[2] . $color[3]);
$B = hexdec($color[4] . $color[5]);
$RGB['R'] = $R;
$RGB['G'] = $G;
$RGB['B'] = $B;
return $RGB;
}
/**
* Given an RGB associative array returns the equivalent HEX string
*
* @param array $rgb
*
* @return string RGB string
* @throws Exception "Bad RGB Array"
*/
public static function rgbToHex($rgb = array()){
// Make sure it's RGB
if(empty($rgb) || !isset($rgb["R"]) || !isset($rgb["G"]) || !isset($rgb["B"])){
throw new Exception("Param was not an RGB array");
}
// Convert RGB to HEX
$hex[0] = dechex($rgb['R']);
$hex[1] = dechex($rgb['G']);
$hex[2] = dechex($rgb['B']);
return implode('', $hex);
}
/**
* Given a HEX value, returns a darker color. If no desired amount provided, then the color halfway between
* given HEX and black will be returned.
*
* @param int $amount
*
* @return string Darker HEX value
*/
public function darken($amount = self::DEFAULT_ADJUST, $percent_to_black = true){
// Darken
$darkerHSL = $this->_darken($this->_hsl, $amount, $percent_to_black);
// Return as HEX
return self::hslToHex($darkerHSL);
}
/**
* Given a HEX value, returns a lighter color. If no desired amount provided, then the color halfway between
* given HEX and white will be returned.
*
* @param int $amount
*
* @return string Lighter HEX value
*/
public function lighten($amount = self::DEFAULT_ADJUST, $percent_to_white = true){
// Lighten
$lighterHSL = $this->_lighten($this->_hsl, $amount, $percent_to_white);
// Return as HEX
return self::hslToHex($lighterHSL);
}
/**
* Given a HEX value, returns a mixed color. If no desired amount provided, then the color mixed by this ratio
*
* @param string $hex2 Secondary HEX value to mix with
* @param int $amount = -100..0..+100
*
* @return string mixed HEX value
*/
public function mix($hex2, $amount = 0){
$rgb2 = self::hexToRgb($hex2);
$mixed = $this->_mix($this->_rgb, $rgb2, $amount);
// Return as HEX
return self::rgbToHex($mixed);
}
/**
* Creates an array with two shades that can be used to make a gradient
*
* @param int $amount Optional percentage amount you want your contrast color
*
* @return array An array with a 'light' and 'dark' index
*/
public function makeGradient($amount = self::DEFAULT_ADJUST){
// Decide which color needs to be made
if($this->isLight()){
$lightColor = $this->_hex;
$darkColor = $this->darken($amount);
}else{
$lightColor = $this->lighten($amount);
$darkColor = $this->_hex;
}
// Return our gradient array
return array("light" => $lightColor, "dark" => $darkColor);
}
/**
* Returns whether or not given color is considered "light"
*
* @param string|Boolean $color
*
* @return boolean
*/
public function isLight($color = false){
// Get our color
$color = ($color) ? $color : $this->_hex;
// Calculate straight from rbg
$r = hexdec($color[0] . $color[1]);
$g = hexdec($color[2] . $color[3]);
$b = hexdec($color[4] . $color[5]);
return (($r * 299 + $g * 587 + $b * 114) / 1000 > 130);
}
/**
* Returns whether or not a given color is considered "dark"
*
* @param string|Boolean $color
*
* @return boolean
*/
public function isDark($color = false){
// Get our color
$color = ($color) ? $color : $this->_hex;
// Calculate straight from rbg
$r = hexdec($color[0] . $color[1]);
$g = hexdec($color[2] . $color[3]);
$b = hexdec($color[4] . $color[5]);
return (($r * 299 + $g * 587 + $b * 114) / 1000 <= 130);
}
/**
* Returns the complimentary color
*
* @return string Complementary hex color
*
*/
public function complementary(){
// Get our HSL
$hsl = $this->_hsl;
// Adjust Hue 180 degrees
$hsl['H'] += ($hsl['H'] > 180) ? - 180 : 180;
// Return the new value in HEX
return self::hslToHex($hsl);
}
/**
* Returns your color's HSL array
*/
public function getHsl(){
return $this->_hsl;
}
/**
* Returns your original color
*/
public function getHex(){
return $this->_hex;
}
/**
* Returns your color's RGB array
*/
public function getRgb(){
return $this->_rgb;
}
/**
* Returns the cross browser CSS3 gradient
*
* @param int $amount Optional: percentage amount to light/darken the gradient
* @param boolean $vintageBrowsers Optional: include vendor prefixes for browsers that almost died out already
* @param string $prefix Optional: prefix for every lines
* @param string $suffix Optional: suffix for every lines
*
* @link http://caniuse.com/css-gradients Resource for the browser support
* @return string CSS3 gradient for chrome, safari, firefox, opera and IE10
*/
public function getCssGradient($amount = self::DEFAULT_ADJUST, $vintageBrowsers = false, $suffix = "", $prefix = ""){
// Get the recommended gradient
$g = $this->makeGradient($amount);
$css = "";
/* fallback/image non-cover color */
$css .= "{$prefix}background-color: #" . $this->_hex . ";{$suffix}";
/* IE Browsers */
$css .= "{$prefix}filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#" . $g['light'] . "', endColorstr='#" . $g['dark'] . "');{$suffix}";
/* Safari 4+, Chrome 1-9 */
if($vintageBrowsers){
$css .= "{$prefix}background-image: -webkit-gradient(linear, 0% 0%, 0% 100%, from(#" . $g['light'] . "), to(#" . $g['dark'] . "));{$suffix}";
}
/* Safari 5.1+, Mobile Safari, Chrome 10+ */
$css .= "{$prefix}background-image: -webkit-linear-gradient(top, #" . $g['light'] . ", #" . $g['dark'] . ");{$suffix}";
/* Firefox 3.6+ */
if($vintageBrowsers){
$css .= "{$prefix}background-image: -moz-linear-gradient(top, #" . $g['light'] . ", #" . $g['dark'] . ");{$suffix}";
}
/* Opera 11.10+ */
if($vintageBrowsers){
$css .= "{$prefix}background-image: -o-linear-gradient(top, #" . $g['light'] . ", #" . $g['dark'] . ");{$suffix}";
}
/* Unprefixed version (standards): FF 16+, IE10+, Chrome 26+, Safari 7+, Opera 12.1+ */
$css .= "{$prefix}background-image: linear-gradient(to bottom, #" . $g['light'] . ", #" . $g['dark'] . ");{$suffix}";
// Return our CSS
return $css;
}
// ===========================
// = Private Functions Below =
// ===========================
/**
* Darkens a given HSL array
*
* @param array $hsl
* @param int $amount
*
* @return array $hsl
*/
private function _darken($hsl, $amount = self::DEFAULT_ADJUST, $percent_to_black){
// Check if we were provided a number and want to adjust by percentage to complete black (100%).
// 0 being original color and 100 being black.
if($amount || $amount === 0 && $percent_to_black){
$hsl['L'] -= $hsl['L'] / 100 * max(min($amount, 100), 0);//make sure amount is set between 0-100
}elseif($amount){
//$amount is percent lighter then its color with no relation to black.
$hsl['L'] = ($hsl['L'] * 100) - $amount;
$hsl['L'] = ($hsl['L'] < 0) ? 0 : $hsl['L'] / 100;
}else{
// We need to find out how much to darken
$hsl['L'] = $hsl['L'] / 2;
}
return $hsl;
}
/**
* Lightens a given HSL array
*
* @param array $hsl
* @param int $amount
*
* @return array $hsl
*/
private function _lighten($hsl, $amount = self::DEFAULT_ADJUST, $percent_to_white){
// Check if we were provided a number and want to adjust by percentage to complete white (100%).
// 0 being original color and 100 being white.
if($amount || $amount === 0 && $percent_to_white){
$hsl['L'] += (1 - $hsl['L']) / 100 * max(min($amount, 100), 0);//make sure amount is set between 0-100
}elseif($amount){
//$amount is percent lighter then its color with no relation to white.
$hsl['L'] = ($hsl['L'] * 100) + $amount;
$hsl['L'] = ($hsl['L'] > 100) ? 1 : $hsl['L'] / 100;
}else{
// We need to find out how much to lighten
$hsl['L'] += (1 - $hsl['L']) / 2;
}
return $hsl;
}
/**
* Mix 2 rgb colors and return an rgb color
*
* @param array $rgb1
* @param array $rgb2
* @param int $amount ranged -100..0..+100
*
* @return array $rgb
*
* ported from http://phpxref.pagelines.com/nav.html?includes/class.colors.php.source.html
*/
private function _mix($rgb1, $rgb2, $amount = 0){
$r1 = ($amount + 100) / 100;
$r2 = 2 - $r1;
$rmix = (($rgb1['R'] * $r1) + ($rgb2['R'] * $r2)) / 2;
$gmix = (($rgb1['G'] * $r1) + ($rgb2['G'] * $r2)) / 2;
$bmix = (($rgb1['B'] * $r1) + ($rgb2['B'] * $r2)) / 2;
return array('R' => $rmix, 'G' => $gmix, 'B' => $bmix);
}
/**
* Given a Hue, returns corresponding RGB value
*
* @param int $v1
* @param int $v2
* @param int $vH
*
* @return int
*/
private static function _huetorgb($v1, $v2, $vH){
if($vH < 0){
$vH += 1;
}
if($vH > 1){
$vH -= 1;
}
if((6 * $vH) < 1){
return ($v1 + ($v2 - $v1) * 6 * $vH);
}
if((2 * $vH) < 1){
return $v2;
}
if((3 * $vH) < 2){
return ($v1 + ($v2 - $v1) * ((2 / 3) - $vH) * 6);
}
return $v1;
}
/**
* You need to check if you were given a good hex string
*
* @param string $hex
*
* @return string Color
* @throws Exception "Bad color format"
*/
private static function _checkHex($hex){
// Strip # sign is present
$color = str_replace("#", "", $hex);
// Make sure it's 6 digits
if(strlen($color) == 3){
$color = $color[0] . $color[0] . $color[1] . $color[1] . $color[2] . $color[2];
}else if(strlen($color) != 6){
throw new Exception("HEX color needs to be 6 or 3 digits long");
}
return $color;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment