OwlCyberSecurity - MANAGER
Edit File: color.php
<?php /** * Author: Arlo Carreon <http://arlocarreon.com> * Info: http://mexitek.github.io/phpColors/ * License: http://arlo.mit-license.org/ */ /** * A color utility that helps manipulate HEX colors */ class VamtamColor { private $_hex; private $_hsl; private $_rgb; private $_rgba; private $_alpha; private $constants = [ 'white' => '#fff', 'black' => '#000', ]; /** * 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 ) { if ( isset( $this->constants[ $hex ] ) ) { $hex = $this->constants[ $hex ]; } // Strip # sign is present $color = str_replace( '#', '', $hex ); $alpha = null; // Make sure it's 6 digits if ( strlen( $color ) === 3 ) { $color = $color[0] . $color[0] . $color[1] . $color[1] . $color[2] . $color[2]; } elseif ( strlen( $color ) === 8 ) { $alpha = $color[6] . $color[7]; $color = $color[0] . $color[0] . $color[1] . $color[1] . $color[2] . $color[2]; } elseif ( strlen( $color ) != 6 ) { trigger_error( "HEX color needs to be 8, 6 or 3 digits long, got '$color'", E_USER_WARNING ); } $this->_hsl = self::hexToHsl( $color ); $this->_hex = $color; $this->_rgb = self::hexToRgb( $color ); if ( isset( $alpha ) ) { $this->_alpha = hexdec( $alpha ); $this->_rgba = self::hexToRgba( $color, $this->_alpha ); } } // ==================== // = 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; elseif ($var_G == $var_Max) $H = ( 1 / 3 ) + $del_R - $del_B; elseif ($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 a HEX string and an alpha channel, returns a RGBA array equivalent. * @param string $color, $alpha * @return array RGBA associative array */ public static function hexToRgba( $color, $alpha = 255 ) { // 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] ); $A = round( $alpha / 255, 2 ); $RGBA['R'] = $R; $RGBA['G'] = $G; $RGBA['B'] = $B; $RGBA['A'] = $A; return $RGBA; } /** * 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' ); } // https://github.com/mexitek/phpColors/issues/25#issuecomment-88354815 // Convert RGB to HEX $hex[0] = str_pad( dechex( $rgb['R'] ), 2, '0', STR_PAD_LEFT ); $hex[1] = str_pad( dechex( $rgb['G'] ), 2, '0', STR_PAD_LEFT ); $hex[2] = str_pad( dechex( $rgb['B'] ), 2, '0', STR_PAD_LEFT ); return implode( '', $hex ); } // For a given color, return it's contrast one. public static function get_contrast_color( $hex ) { $color = new self( $hex ); $hc_color = ''; if ( $color->luminance > 0.4 ) { $hc_color = '#000000'; } else { $hc_color = '#FFFFFF'; } return $hc_color; } /** * 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 ) { // Darken $darkerHSL = $this->_darken( $this->_hsl, $amount ); // 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 ) { // Lighten $lighterHSL = $this->_lighten( $this->_hsl, $amount ); // 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 * @param int $lighterThan * @return boolean */ public function isLight( $color = false, $lighterThan = 130 ) { // 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 > $lighterThan); } /** * Returns whether or not a given color is considered "dark" * @param string|Boolean $color * @param int $darkerThan * @return boolean */ public function isDark( $color = false, $darkerThan = 130 ) { // 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 <= $darkerThan); } /** * 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 ) { // Check if we were provided a number if ( $amount ) { $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 ) { // Check if we were provided a number if ( $amount ) { $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, ); } /** * Returns the luminance as defined by WCAG 2.0 * @return float */ private function getLuminance() { // Formula: http://www.w3.org/TR/2008/REC-WCAG20-20081211/#relativeluminancedef $map = array( 'R', 'G', 'B' ); $intermediate = array(); foreach ( $map as $comp ) { $value = $this->_rgb[ $comp ]; $value /= 255; $intermediate[ $comp ] = $value < .03928 ? $value / 12.92 : pow( ( $value + .055 ) / 1.055, 2.4 ); } return .2126 * $intermediate['R'] + .7152 * $intermediate['G'] + 0.0722 * $intermediate['B']; } /** * Returns the contrast ratio between the current color and a given relative luminance * @param float $L2 relative luminance * @return float */ public function getContrastRatio( $L2 ) { // Formula: http://www.w3.org/TR/2008/REC-WCAG20-20081211/#contrast-ratiodef $L1 = $this->getLuminance(); return ( max( $L1, $L2 ) + 0.05 ) / ( min( $L1, $L2 ) + 0.05 ); } /** * 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]; } elseif ( strlen( $color ) != 6 ) { throw new Exception( 'HEX color needs to be 6 or 3 digits long' ); } return $color; } /** * Converts object into its string representation * @return string Color */ public function __toString() { return '#' . $this->getHex(); } public function __get( $name ) { switch ( strtolower( $name ) ) { case 'red': case 'r': return $this->_rgb['R']; case 'green': case 'g': return $this->_rgb['G']; case 'blue': case 'b': return $this->_rgb['B']; case 'hue': case 'h': return $this->_hsl['H']; case 'saturation': case 's': return $this->_hsl['S']; case 'lightness': case 'l': return $this->_hsl['L']; case 'luminance': return $this->getLuminance(); } } public function __set( $name, $value ) { switch ( strtolower( $name ) ) { case 'red': case 'r': $this->_rgb['R'] = $value; $this->_hex = $this->rgbToHex( $this->_rgb ); $this->_hsl = $this->hexToHsl( $this->_hex ); break; case 'green': case 'g': $this->_rgb['G'] = $value; $this->_hex = $this->rgbToHex( $this->_rgb ); $this->_hsl = $this->hexToHsl( $this->_hex ); break; case 'blue': case 'b': $this->_rgb['B'] = $value; $this->_hex = $this->rgbToHex( $this->_rgb ); $this->_hsl = $this->hexToHsl( $this->_hex ); break; case 'hue': case 'h': $this->_hsl['H'] = $value; $this->_hex = $this->hslToHex( $this->_hsl ); $this->_rgb = $this->hexToRgb( $this->_hex ); break; case 'saturation': case 's': $this->_hsl['S'] = $value; $this->_hex = $this->hslToHex( $this->_hsl ); $this->_rgb = $this->hexToRgb( $this->_hex ); break; case 'lightness': case 'light': case 'l': $this->_hsl['L'] = $value; $this->_hex = $this->hslToHex( $this->_hsl ); $this->_rgb = $this->hexToRgb( $this->_hex ); break; } } }