├── composer.json ├── LICENSE ├── README.md └── src └── Mexitek └── PHPColors └── Color.php /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "mexitek/phpcolors", 3 | "description": "A series of methods that let you manipulate colors. Just incase you ever need different shades of one color on the fly.", 4 | "type": "library", 5 | "keywords": [ 6 | "color", 7 | "ui", 8 | "css", 9 | "frontend", 10 | "design" 11 | ], 12 | "homepage": "https://github.com/mexitek/phpColors", 13 | "license": "MIT", 14 | "authors": [ 15 | { 16 | "name": "Arlo Carreon", 17 | "homepage": "http://arlocarreon.com", 18 | "role": "creator" 19 | } 20 | ], 21 | "support": { 22 | "issues": "https://github.com/mexitek/phpColors/issues", 23 | "source": "https://github.com/mexitek/phpColors" 24 | }, 25 | "require": { 26 | "php": "^7.2|^8.0" 27 | }, 28 | "require-dev": { 29 | "nette/tester": "^2.3", 30 | "squizlabs/php_codesniffer": "^3.5" 31 | }, 32 | "autoload": { 33 | "classmap": [ 34 | "src" 35 | ] 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Arlo Carreon, http://arlocarreon.com 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PHPColors [![Build Status](https://travis-ci.org/mexitek/phpColors.svg?branch=master)](https://travis-ci.org/mexitek/phpColors) 2 | 3 | > A series of methods that let you manipulate colors. Just incase you ever need different shades of one color on the fly. 4 | 5 | ## Requirements 6 | 7 | PHPColors requires PHP version 7.2.0 or greater. 8 | 9 | ## Installation 10 | 11 | ### Composer 12 | 13 | Simply add `mexitek/phpcolors` to `composer.json` using `dev-master`. 14 | 15 | ``` 16 | composer require mexitek/phpcolors:dev-master 17 | ``` 18 | 19 | ## How it works 20 | Instantiate an object of the color class with a hex color string `$foo = new Color("336699")`. That's it! Now, call the methods you need for different color variants. 21 | 22 | ## Available Methods 23 | - darken( [$amount] ) : Allows you to obtain a darker shade of your color. Optionally you can decide to darken using a desired percentage. 24 | - lighten( [$amount] ) : Allows you to obtain a lighter shade of your color. Optionally you can decide to lighten using a desired percentage. 25 | - mix($hex, [$amount] ) : Allows you to mix another color to your color. Optionally you can decide to set the percent of second color or original color amount is ranged -100...0...100. 26 | - isLight( [$hex] ) : Determins whether your color (or the provide param) is considered a "light" color. Returns `TRUE` if color is light. 27 | - isDark( [$hex] ) : Determins whether your color (or the provide param) is considered a "dark" color. Returns `TRUE` if color is dark. 28 | - makeGradient( [$amount] ) : Returns an array with 2 indices `light` and `dark`, the initial color will either be selected for `light` or `dark` depending on its brightness, then the other color will be generated. The optional param allows for a static lighten or darkened amount. 29 | - complementary() : Returns the color "opposite" or complementary to your color. 30 | - getHex() : Returns the original hex color. 31 | - getHsl() : Returns HSL array for your color. 32 | - getRgb() : Returns RGB array for your color. 33 | 34 | > Auto lightens/darkens by 10% for sexily-subtle gradients 35 | 36 | ```php 37 | /** 38 | * Using The Class 39 | */ 40 | 41 | use Mexitek\PHPColors\Color; 42 | 43 | // Initialize my color 44 | $myBlue = new Color("#336699"); 45 | 46 | echo $myBlue->darken(); 47 | // 1a334d 48 | 49 | echo $myBlue->lighten(); 50 | // 8cb3d9 51 | 52 | echo $myBlue->isLight(); 53 | // false 54 | 55 | echo $myBlue->isDark(); 56 | // true 57 | 58 | echo $myBlue->complementary(); 59 | // 996633 60 | 61 | echo $myBlue->getHex(); 62 | // 336699 63 | 64 | print_r( $myBlue->getHsl() ); 65 | // array( "H"=> 210, "S"=> 0.5, "L"=>0.4 ); 66 | 67 | print_r( $myBlue->getRgb() ); 68 | // array( "R"=> 51, "G"=> 102, "B"=>153 ); 69 | 70 | print_r($myBlue->makeGradient()); 71 | // array( "light"=>"8cb3d9" ,"dark"=>"336699" ) 72 | 73 | ``` 74 | 75 | 76 | ## Static Methods 77 | - hslToHex( $hsl ) : Convert a HSL array to a HEX string. 78 | - hexToHsl( $hex ) : Convert a HEX string into an HSL array. 79 | - hexToRgb( $hex ) : Convert a HEX string into an RGB array. 80 | - rgbToHex( $rgb ) : Convert an RGB array into a HEX string. 81 | 82 | ```php 83 | /** 84 | * On The Fly Custom Calculations 85 | */ 86 | 87 | use Mexitek\PHPColors\Color; 88 | 89 | // Convert my HEX 90 | $myBlue = Color::hexToHsl("#336699"); 91 | 92 | // Get crazy with the HUE 93 | $myBlue["H"] = 295; 94 | 95 | // Gimme my new color!! 96 | echo Color::hslToHex($myBlue); 97 | // 913399 98 | 99 | ``` 100 | 101 | ## CSS Helpers 102 | - getCssGradient( [$amount] [, $vintageBrowsers] ) : Generates the CSS3 gradients for safari, chrome, opera, firefox and IE10. Optional percentage amount for lighter/darker shade. Optional boolean for older gradient CSS support. 103 | 104 | > Would like to add support to custom gradient stops 105 | 106 | ```php 107 | 108 | use Mexitek\PHPColors\Color; 109 | 110 | // Initialize my color 111 | $myBlue = new Color("#336699"); 112 | 113 | // Get CSS 114 | echo $myBlue->getCssGradient(); 115 | /* - Actual output doesn't have comments and is single line 116 | 117 | // fallback background 118 | background: #336699; 119 | 120 | // IE Browsers 121 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#8cb3d9', endColorstr='#336699'); 122 | 123 | // Safari 5.1+, Mobile Safari, Chrome 10+ 124 | background-image: -webkit-linear-gradient(top, #8cb3d9, #336699); 125 | 126 | // Standards 127 | background-image: linear-gradient(to bottom, #8cb3d9, #336699); 128 | 129 | */ 130 | 131 | ``` 132 | 133 | However, if you want to support the ancient browsers (which has negligible market share and almost died out), you can set the second parameter to `TRUE`. This will output: 134 | 135 | ```php 136 | 137 | use Mexitek\PHPColors\Color; 138 | $myBlue = new Color("#336699"); 139 | 140 | // Get CSS 141 | echo $myBlue->getCssGradient(10, TRUE); 142 | /* - Actual output doesn't have comments and is single line 143 | 144 | background: #336699; // fallback background 145 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#8cb3d9', endColorstr='#336699'); // IE Browsers 146 | background-image: -webkit-gradient(linear, 0% 0%, 0% 100%, from(#8cb3d9), to(#336699)); // Safari 4+, Chrome 1-9 147 | background-image: -webkit-linear-gradient(top, #8cb3d9, #336699); // Safari 5.1+, Mobile Safari, Chrome 10+ 148 | background-image: -moz-linear-gradient(top, #8cb3d9, #336699); // Firefox 3.6+ 149 | background-image: -o-linear-gradient(top, #8cb3d9, #336699); // Opera 11.10+ 150 | background-image: linear-gradient(to bottom, #8cb3d9, #336699); // Standards 151 | 152 | */ 153 | 154 | ``` 155 | 156 | ## Github Contributors 157 | - mexitek 158 | - danielpataki 159 | - alexmglover 160 | - intuxicated 161 | - pborreli 162 | - curtisgibby 163 | - matthewpatterson 164 | - there4 165 | - alex-humphreys 166 | - zaher 167 | - primozcigler 168 | - thedavidmeister 169 | - tylercd100 170 | - Braunson 171 | 172 | # License 173 | See LICENSE file or [arlo.mit-license.org](http://arlo.mit-license.org) 174 | -------------------------------------------------------------------------------- /src/Mexitek/PHPColors/Color.php: -------------------------------------------------------------------------------- 1 | 5 | * Info: http://mexitek.github.io/phpColors/ 6 | * License: http://arlo.mit-license.org/ 7 | */ 8 | 9 | namespace Mexitek\PHPColors; 10 | 11 | use Exception; 12 | 13 | /** 14 | * A color utility that helps manipulate HEX colors 15 | */ 16 | class Color 17 | { 18 | /** 19 | * @var string 20 | */ 21 | private $_hex; 22 | 23 | /** 24 | * @var array 25 | */ 26 | private $_hsl; 27 | 28 | /** 29 | * @var array 30 | */ 31 | private $_rgb; 32 | 33 | /** 34 | * Auto darkens/lightens by 10% for sexily-subtle gradients. 35 | * Set this to FALSE to adjust automatic shade to be between given color 36 | * and black (for darken) or white (for lighten) 37 | */ 38 | public const DEFAULT_ADJUST = 10; 39 | 40 | /** 41 | * Instantiates the class with a HEX value 42 | * @param string $hex 43 | * @throws Exception 44 | */ 45 | public function __construct(string $hex) 46 | { 47 | $color = self::sanitizeHex($hex); 48 | $this->_hex = $color; 49 | $this->_hsl = self::hexToHsl($color); 50 | $this->_rgb = self::hexToRgb($color); 51 | } 52 | 53 | /** 54 | * Given a HEX string returns a HSL array equivalent. 55 | * @param string $color 56 | * @return array HSL associative array 57 | * @throws Exception 58 | */ 59 | public static function hexToHsl(string $color): array 60 | { 61 | // Sanity check 62 | $color = self::sanitizeHex($color); 63 | 64 | // Convert HEX to DEC 65 | $R = hexdec($color[0] . $color[1]); 66 | $G = hexdec($color[2] . $color[3]); 67 | $B = hexdec($color[4] . $color[5]); 68 | 69 | $HSL = array(); 70 | 71 | $var_R = ($R / 255); 72 | $var_G = ($G / 255); 73 | $var_B = ($B / 255); 74 | 75 | $var_Min = min($var_R, $var_G, $var_B); 76 | $var_Max = max($var_R, $var_G, $var_B); 77 | $del_Max = $var_Max - $var_Min; 78 | 79 | $L = ($var_Max + $var_Min) / 2; 80 | 81 | if ($del_Max == 0) { 82 | $H = 0; 83 | $S = 0; 84 | } else { 85 | if ($L < 0.5) { 86 | $S = $del_Max / ($var_Max + $var_Min); 87 | } else { 88 | $S = $del_Max / (2 - $var_Max - $var_Min); 89 | } 90 | 91 | $del_R = ((($var_Max - $var_R) / 6) + ($del_Max / 2)) / $del_Max; 92 | $del_G = ((($var_Max - $var_G) / 6) + ($del_Max / 2)) / $del_Max; 93 | $del_B = ((($var_Max - $var_B) / 6) + ($del_Max / 2)) / $del_Max; 94 | 95 | if ($var_R == $var_Max) { 96 | $H = $del_B - $del_G; 97 | } elseif ($var_G == $var_Max) { 98 | $H = (1 / 3) + $del_R - $del_B; 99 | } elseif ($var_B == $var_Max) { 100 | $H = (2 / 3) + $del_G - $del_R; 101 | } 102 | 103 | if ($H < 0) { 104 | $H++; 105 | } 106 | if ($H > 1) { 107 | $H--; 108 | } 109 | } 110 | 111 | $HSL['H'] = ($H * 360); 112 | $HSL['S'] = $S; 113 | $HSL['L'] = $L; 114 | 115 | return $HSL; 116 | } 117 | 118 | /** 119 | * Given a HSL associative array returns the equivalent HEX string 120 | * @param array $hsl 121 | * @return string HEX string 122 | * @throws Exception "Bad HSL Array" 123 | */ 124 | public static function hslToHex(array $hsl = array()): string 125 | { 126 | // Make sure it's HSL 127 | if (empty($hsl) || !isset($hsl["H"], $hsl["S"], $hsl["L"])) { 128 | throw new Exception("Param was not an HSL array"); 129 | } 130 | 131 | list($H, $S, $L) = array($hsl['H'] / 360, $hsl['S'], $hsl['L']); 132 | 133 | if ($S == 0) { 134 | $r = $L * 255; 135 | $g = $L * 255; 136 | $b = $L * 255; 137 | } else { 138 | if ($L < 0.5) { 139 | $var_2 = $L * (1 + $S); 140 | } else { 141 | $var_2 = ($L + $S) - ($S * $L); 142 | } 143 | 144 | $var_1 = 2 * $L - $var_2; 145 | 146 | $r = 255 * self::hueToRgb($var_1, $var_2, $H + (1 / 3)); 147 | $g = 255 * self::hueToRgb($var_1, $var_2, $H); 148 | $b = 255 * self::hueToRgb($var_1, $var_2, $H - (1 / 3)); 149 | } 150 | 151 | // Convert to hex 152 | $r = dechex(round($r)); 153 | $g = dechex(round($g)); 154 | $b = dechex(round($b)); 155 | 156 | // Make sure we get 2 digits for decimals 157 | $r = (strlen("" . $r) === 1) ? "0" . $r : $r; 158 | $g = (strlen("" . $g) === 1) ? "0" . $g : $g; 159 | $b = (strlen("" . $b) === 1) ? "0" . $b : $b; 160 | 161 | return $r . $g . $b; 162 | } 163 | 164 | 165 | /** 166 | * Given a HEX string returns a RGB array equivalent. 167 | * @param string $color 168 | * @return array RGB associative array 169 | * @throws Exception 170 | */ 171 | public static function hexToRgb(string $color): array 172 | { 173 | // Sanity check 174 | $color = self::sanitizeHex($color); 175 | 176 | // Convert HEX to DEC 177 | $R = hexdec($color[0] . $color[1]); 178 | $G = hexdec($color[2] . $color[3]); 179 | $B = hexdec($color[4] . $color[5]); 180 | 181 | $RGB['R'] = $R; 182 | $RGB['G'] = $G; 183 | $RGB['B'] = $B; 184 | 185 | return $RGB; 186 | } 187 | 188 | 189 | /** 190 | * Given an RGB associative array returns the equivalent HEX string 191 | * @param array $rgb 192 | * @return string Hex string 193 | * @throws Exception "Bad RGB Array" 194 | */ 195 | public static function rgbToHex(array $rgb = array()): string 196 | { 197 | // Make sure it's RGB 198 | if (empty($rgb) || !isset($rgb["R"], $rgb["G"], $rgb["B"])) { 199 | throw new Exception("Param was not an RGB array"); 200 | } 201 | 202 | // https://github.com/mexitek/phpColors/issues/25#issuecomment-88354815 203 | // Convert RGB to HEX 204 | $hex[0] = str_pad(dechex((int)$rgb['R']), 2, '0', STR_PAD_LEFT); 205 | $hex[1] = str_pad(dechex((int)$rgb['G']), 2, '0', STR_PAD_LEFT); 206 | $hex[2] = str_pad(dechex((int)$rgb['B']), 2, '0', STR_PAD_LEFT); 207 | 208 | // Make sure that 2 digits are allocated to each color. 209 | $hex[0] = (strlen($hex[0]) === 1) ? '0' . $hex[0] : $hex[0]; 210 | $hex[1] = (strlen($hex[1]) === 1) ? '0' . $hex[1] : $hex[1]; 211 | $hex[2] = (strlen($hex[2]) === 1) ? '0' . $hex[2] : $hex[2]; 212 | 213 | return implode('', $hex); 214 | } 215 | 216 | /** 217 | * Given an RGB associative array, returns CSS string output. 218 | * @param array $rgb 219 | * @return string rgb(r,g,b) string 220 | * @throws Exception "Bad RGB Array" 221 | */ 222 | public static function rgbToString(array $rgb = array()): string 223 | { 224 | // Make sure it's RGB 225 | if (empty($rgb) || !isset($rgb["R"], $rgb["G"], $rgb["B"])) { 226 | throw new Exception("Param was not an RGB array"); 227 | } 228 | 229 | return 'rgb(' . 230 | $rgb['R'] . ', ' . 231 | $rgb['G'] . ', ' . 232 | $rgb['B'] . ')'; 233 | } 234 | 235 | /** 236 | * Given a standard color name, return hex code 237 | * 238 | * @param string $color_name 239 | * @return string 240 | */ 241 | public static function nameToHex(string $color_name): string 242 | { 243 | $colors = array( 244 | 'aliceblue' => 'F0F8FF', 245 | 'antiquewhite' => 'FAEBD7', 246 | 'aqua' => '00FFFF', 247 | 'aquamarine' => '7FFFD4', 248 | 'azure' => 'F0FFFF', 249 | 'beige' => 'F5F5DC', 250 | 'bisque' => 'FFE4C4', 251 | 'black' => '000000', 252 | 'blanchedalmond' => 'FFEBCD', 253 | 'blue' => '0000FF', 254 | 'blueviolet' => '8A2BE2', 255 | 'brown' => 'A52A2A', 256 | 'burlywood' => 'DEB887', 257 | 'cadetblue' => '5F9EA0', 258 | 'chartreuse' => '7FFF00', 259 | 'chocolate' => 'D2691E', 260 | 'coral' => 'FF7F50', 261 | 'cornflowerblue' => '6495ED', 262 | 'cornsilk' => 'FFF8DC', 263 | 'crimson' => 'DC143C', 264 | 'cyan' => '00FFFF', 265 | 'darkblue' => '00008B', 266 | 'darkcyan' => '008B8B', 267 | 'darkgoldenrod' => 'B8860B', 268 | 'darkgray' => 'A9A9A9', 269 | 'darkgreen' => '006400', 270 | 'darkgrey' => 'A9A9A9', 271 | 'darkkhaki' => 'BDB76B', 272 | 'darkmagenta' => '8B008B', 273 | 'darkolivegreen' => '556B2F', 274 | 'darkorange' => 'FF8C00', 275 | 'darkorchid' => '9932CC', 276 | 'darkred' => '8B0000', 277 | 'darksalmon' => 'E9967A', 278 | 'darkseagreen' => '8FBC8F', 279 | 'darkslateblue' => '483D8B', 280 | 'darkslategray' => '2F4F4F', 281 | 'darkslategrey' => '2F4F4F', 282 | 'darkturquoise' => '00CED1', 283 | 'darkviolet' => '9400D3', 284 | 'deeppink' => 'FF1493', 285 | 'deepskyblue' => '00BFFF', 286 | 'dimgray' => '696969', 287 | 'dimgrey' => '696969', 288 | 'dodgerblue' => '1E90FF', 289 | 'firebrick' => 'B22222', 290 | 'floralwhite' => 'FFFAF0', 291 | 'forestgreen' => '228B22', 292 | 'fuchsia' => 'FF00FF', 293 | 'gainsboro' => 'DCDCDC', 294 | 'ghostwhite' => 'F8F8FF', 295 | 'gold' => 'FFD700', 296 | 'goldenrod' => 'DAA520', 297 | 'gray' => '808080', 298 | 'green' => '008000', 299 | 'greenyellow' => 'ADFF2F', 300 | 'grey' => '808080', 301 | 'honeydew' => 'F0FFF0', 302 | 'hotpink' => 'FF69B4', 303 | 'indianred' => 'CD5C5C', 304 | 'indigo' => '4B0082', 305 | 'ivory' => 'FFFFF0', 306 | 'khaki' => 'F0E68C', 307 | 'lavender' => 'E6E6FA', 308 | 'lavenderblush' => 'FFF0F5', 309 | 'lawngreen' => '7CFC00', 310 | 'lemonchiffon' => 'FFFACD', 311 | 'lightblue' => 'ADD8E6', 312 | 'lightcoral' => 'F08080', 313 | 'lightcyan' => 'E0FFFF', 314 | 'lightgoldenrodyellow' => 'FAFAD2', 315 | 'lightgray' => 'D3D3D3', 316 | 'lightgreen' => '90EE90', 317 | 'lightgrey' => 'D3D3D3', 318 | 'lightpink' => 'FFB6C1', 319 | 'lightsalmon' => 'FFA07A', 320 | 'lightseagreen' => '20B2AA', 321 | 'lightskyblue' => '87CEFA', 322 | 'lightslategray' => '778899', 323 | 'lightslategrey' => '778899', 324 | 'lightsteelblue' => 'B0C4DE', 325 | 'lightyellow' => 'FFFFE0', 326 | 'lime' => '00FF00', 327 | 'limegreen' => '32CD32', 328 | 'linen' => 'FAF0E6', 329 | 'magenta' => 'FF00FF', 330 | 'maroon' => '800000', 331 | 'mediumaquamarine' => '66CDAA', 332 | 'mediumblue' => '0000CD', 333 | 'mediumorchid' => 'BA55D3', 334 | 'mediumpurple' => '9370D0', 335 | 'mediumseagreen' => '3CB371', 336 | 'mediumslateblue' => '7B68EE', 337 | 'mediumspringgreen' => '00FA9A', 338 | 'mediumturquoise' => '48D1CC', 339 | 'mediumvioletred' => 'C71585', 340 | 'midnightblue' => '191970', 341 | 'mintcream' => 'F5FFFA', 342 | 'mistyrose' => 'FFE4E1', 343 | 'moccasin' => 'FFE4B5', 344 | 'navajowhite' => 'FFDEAD', 345 | 'navy' => '000080', 346 | 'oldlace' => 'FDF5E6', 347 | 'olive' => '808000', 348 | 'olivedrab' => '6B8E23', 349 | 'orange' => 'FFA500', 350 | 'orangered' => 'FF4500', 351 | 'orchid' => 'DA70D6', 352 | 'palegoldenrod' => 'EEE8AA', 353 | 'palegreen' => '98FB98', 354 | 'paleturquoise' => 'AFEEEE', 355 | 'palevioletred' => 'DB7093', 356 | 'papayawhip' => 'FFEFD5', 357 | 'peachpuff' => 'FFDAB9', 358 | 'peru' => 'CD853F', 359 | 'pink' => 'FFC0CB', 360 | 'plum' => 'DDA0DD', 361 | 'powderblue' => 'B0E0E6', 362 | 'purple' => '800080', 363 | 'red' => 'FF0000', 364 | 'rosybrown' => 'BC8F8F', 365 | 'royalblue' => '4169E1', 366 | 'saddlebrown' => '8B4513', 367 | 'salmon' => 'FA8072', 368 | 'sandybrown' => 'F4A460', 369 | 'seagreen' => '2E8B57', 370 | 'seashell' => 'FFF5EE', 371 | 'sienna' => 'A0522D', 372 | 'silver' => 'C0C0C0', 373 | 'skyblue' => '87CEEB', 374 | 'slateblue' => '6A5ACD', 375 | 'slategray' => '708090', 376 | 'slategrey' => '708090', 377 | 'snow' => 'FFFAFA', 378 | 'springgreen' => '00FF7F', 379 | 'steelblue' => '4682B4', 380 | 'tan' => 'D2B48C', 381 | 'teal' => '008080', 382 | 'thistle' => 'D8BFD8', 383 | 'tomato' => 'FF6347', 384 | 'turquoise' => '40E0D0', 385 | 'violet' => 'EE82EE', 386 | 'wheat' => 'F5DEB3', 387 | 'white' => 'FFFFFF', 388 | 'whitesmoke' => 'F5F5F5', 389 | 'yellow' => 'FFFF00', 390 | 'yellowgreen' => '9ACD32' 391 | ); 392 | 393 | $color_name = strtolower($color_name); 394 | if (isset($colors[$color_name])) { 395 | return '#' . $colors[$color_name]; 396 | } 397 | 398 | return $color_name; 399 | } 400 | 401 | /** 402 | * Given a HEX value, returns a darker color. If no desired amount provided, then the color halfway between 403 | * given HEX and black will be returned. 404 | * @param int $amount 405 | * @return string Darker HEX value 406 | * @throws Exception 407 | */ 408 | public function darken(int $amount = self::DEFAULT_ADJUST): string 409 | { 410 | // Darken 411 | $darkerHSL = $this->darkenHsl($this->_hsl, $amount); 412 | // Return as HEX 413 | return self::hslToHex($darkerHSL); 414 | } 415 | 416 | /** 417 | * Given a HEX value, returns a lighter color. If no desired amount provided, then the color halfway between 418 | * given HEX and white will be returned. 419 | * @param int $amount 420 | * @return string Lighter HEX value 421 | * @throws Exception 422 | */ 423 | public function lighten(int $amount = self::DEFAULT_ADJUST): string 424 | { 425 | // Lighten 426 | $lighterHSL = $this->lightenHsl($this->_hsl, $amount); 427 | // Return as HEX 428 | return self::hslToHex($lighterHSL); 429 | } 430 | 431 | /** 432 | * Given a HEX value, returns a mixed color. If no desired amount provided, then the color mixed by this ratio 433 | * @param string $hex2 Secondary HEX value to mix with 434 | * @param int $amount = -100..0..+100 435 | * @return string mixed HEX value 436 | * @throws Exception 437 | */ 438 | public function mix(string $hex2, int $amount = 0): string 439 | { 440 | $rgb2 = self::hexToRgb($hex2); 441 | $mixed = $this->mixRgb($this->_rgb, $rgb2, $amount); 442 | // Return as HEX 443 | return self::rgbToHex($mixed); 444 | } 445 | 446 | /** 447 | * Creates an array with two shades that can be used to make a gradient 448 | * @param int $amount Optional percentage amount you want your contrast color 449 | * @return array An array with a 'light' and 'dark' index 450 | * @throws Exception 451 | */ 452 | public function makeGradient(int $amount = self::DEFAULT_ADJUST): array 453 | { 454 | // Decide which color needs to be made 455 | if ($this->isLight()) { 456 | $lightColor = $this->_hex; 457 | $darkColor = $this->darken($amount); 458 | } else { 459 | $lightColor = $this->lighten($amount); 460 | $darkColor = $this->_hex; 461 | } 462 | 463 | // Return our gradient array 464 | return array("light" => $lightColor, "dark" => $darkColor); 465 | } 466 | 467 | 468 | /** 469 | * Returns whether or not given color is considered "light" 470 | * @param string|bool $color 471 | * @param int $lighterThan 472 | * @return boolean 473 | */ 474 | public function isLight($color = false, int $lighterThan = 130): bool 475 | { 476 | // Get our color 477 | $color = ($color) ? $color : $this->_hex; 478 | 479 | // Calculate straight from rbg 480 | $r = hexdec($color[0] . $color[1]); 481 | $g = hexdec($color[2] . $color[3]); 482 | $b = hexdec($color[4] . $color[5]); 483 | 484 | return (($r * 299 + $g * 587 + $b * 114) / 1000 > $lighterThan); 485 | } 486 | 487 | /** 488 | * Returns whether or not a given color is considered "dark" 489 | * @param string|bool $color 490 | * @param int $darkerThan 491 | * @return boolean 492 | */ 493 | public function isDark($color = false, int $darkerThan = 130): bool 494 | { 495 | // Get our color 496 | $color = ($color) ? $color : $this->_hex; 497 | 498 | // Calculate straight from rbg 499 | $r = hexdec($color[0] . $color[1]); 500 | $g = hexdec($color[2] . $color[3]); 501 | $b = hexdec($color[4] . $color[5]); 502 | 503 | return (($r * 299 + $g * 587 + $b * 114) / 1000 <= $darkerThan); 504 | } 505 | 506 | /** 507 | * Returns the complimentary color 508 | * @return string Complementary hex color 509 | * @throws Exception 510 | */ 511 | public function complementary(): string 512 | { 513 | // Get our HSL 514 | $hsl = $this->_hsl; 515 | 516 | // Adjust Hue 180 degrees 517 | $hsl['H'] += ($hsl['H'] > 180) ? -180 : 180; 518 | 519 | // Return the new value in HEX 520 | return self::hslToHex($hsl); 521 | } 522 | 523 | /** 524 | * Returns the HSL array of your color 525 | */ 526 | public function getHsl(): array 527 | { 528 | return $this->_hsl; 529 | } 530 | 531 | /** 532 | * Returns your original color 533 | */ 534 | public function getHex(): string 535 | { 536 | return $this->_hex; 537 | } 538 | 539 | /** 540 | * Returns the RGB array of your color 541 | */ 542 | public function getRgb(): array 543 | { 544 | return $this->_rgb; 545 | } 546 | 547 | /** 548 | * Returns the cross browser CSS3 gradient 549 | * @param int $amount Optional: percentage amount to light/darken the gradient 550 | * @param boolean $vintageBrowsers Optional: include vendor prefixes for browsers that almost died out already 551 | * @param string $prefix Optional: prefix for every lines 552 | * @param string $suffix Optional: suffix for every lines 553 | * @return string CSS3 gradient for chrome, safari, firefox, opera and IE10 554 | * @throws Exception 555 | * @link http://caniuse.com/css-gradients Resource for the browser support 556 | */ 557 | public function getCssGradient($amount = self::DEFAULT_ADJUST, $vintageBrowsers = false, $suffix = "", $prefix = ""): string 558 | { 559 | // Get the recommended gradient 560 | $g = $this->makeGradient($amount); 561 | 562 | $css = ""; 563 | /* fallback/image non-cover color */ 564 | $css .= "{$prefix}background-color: #" . $this->_hex . ";{$suffix}"; 565 | 566 | /* IE Browsers */ 567 | $css .= "{$prefix}filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#" . $g['light'] . "', endColorstr='#" . $g['dark'] . "');{$suffix}"; 568 | 569 | /* Safari 4+, Chrome 1-9 */ 570 | if ($vintageBrowsers) { 571 | $css .= "{$prefix}background-image: -webkit-gradient(linear, 0% 0%, 0% 100%, from(#" . $g['light'] . "), to(#" . $g['dark'] . "));{$suffix}"; 572 | } 573 | 574 | /* Safari 5.1+, Mobile Safari, Chrome 10+ */ 575 | $css .= "{$prefix}background-image: -webkit-linear-gradient(top, #" . $g['light'] . ", #" . $g['dark'] . ");{$suffix}"; 576 | 577 | if ($vintageBrowsers) { 578 | /* Firefox 3.6+ */ 579 | $css .= "{$prefix}background-image: -moz-linear-gradient(top, #" . $g['light'] . ", #" . $g['dark'] . ");{$suffix}"; 580 | 581 | /* Opera 11.10+ */ 582 | $css .= "{$prefix}background-image: -o-linear-gradient(top, #" . $g['light'] . ", #" . $g['dark'] . ");{$suffix}"; 583 | } 584 | 585 | /* Unprefixed version (standards): FF 16+, IE10+, Chrome 26+, Safari 7+, Opera 12.1+ */ 586 | $css .= "{$prefix}background-image: linear-gradient(to bottom, #" . $g['light'] . ", #" . $g['dark'] . ");{$suffix}"; 587 | 588 | // Return our CSS 589 | return $css; 590 | } 591 | 592 | /** 593 | * Darkens a given HSL array 594 | * @param array $hsl 595 | * @param int $amount 596 | * @return array $hsl 597 | */ 598 | private function darkenHsl(array $hsl, int $amount = self::DEFAULT_ADJUST): array 599 | { 600 | // Check if we were provided a number 601 | if ($amount) { 602 | $hsl['L'] = ($hsl['L'] * 100) - $amount; 603 | $hsl['L'] = ($hsl['L'] < 0) ? 0 : $hsl['L'] / 100; 604 | } else { 605 | // We need to find out how much to darken 606 | $hsl['L'] /= 2; 607 | } 608 | 609 | return $hsl; 610 | } 611 | 612 | /** 613 | * Lightens a given HSL array 614 | * @param array $hsl 615 | * @param int $amount 616 | * @return array 617 | */ 618 | private function lightenHsl(array $hsl, int $amount = self::DEFAULT_ADJUST): array 619 | { 620 | // Check if we were provided a number 621 | if ($amount) { 622 | $hsl['L'] = ($hsl['L'] * 100) + $amount; 623 | $hsl['L'] = ($hsl['L'] > 100) ? 1 : $hsl['L'] / 100; 624 | } else { 625 | // We need to find out how much to lighten 626 | $hsl['L'] += (1 - $hsl['L']) / 2; 627 | } 628 | 629 | return $hsl; 630 | } 631 | 632 | /** 633 | * Mix two RGB colors and return the resulting RGB color 634 | * ported from http://phpxref.pagelines.com/nav.html?includes/class.colors.php.source.html 635 | * @param array $rgb1 636 | * @param array $rgb2 637 | * @param int $amount ranged -100..0..+100 638 | * @return array 639 | */ 640 | private function mixRgb(array $rgb1, array $rgb2, int $amount = 0): array 641 | { 642 | $r1 = ($amount + 100) / 100; 643 | $r2 = 2 - $r1; 644 | 645 | $rmix = (($rgb1['R'] * $r1) + ($rgb2['R'] * $r2)) / 2; 646 | $gmix = (($rgb1['G'] * $r1) + ($rgb2['G'] * $r2)) / 2; 647 | $bmix = (($rgb1['B'] * $r1) + ($rgb2['B'] * $r2)) / 2; 648 | 649 | return array('R' => $rmix, 'G' => $gmix, 'B' => $bmix); 650 | } 651 | 652 | /** 653 | * Given a Hue, returns corresponding RGB value 654 | * @param float $v1 655 | * @param float $v2 656 | * @param float $vH 657 | * @return float 658 | */ 659 | private static function hueToRgb(float $v1, float $v2, float $vH): float 660 | { 661 | if ($vH < 0) { 662 | ++$vH; 663 | } 664 | 665 | if ($vH > 1) { 666 | --$vH; 667 | } 668 | 669 | if ((6 * $vH) < 1) { 670 | return ($v1 + ($v2 - $v1) * 6 * $vH); 671 | } 672 | 673 | if ((2 * $vH) < 1) { 674 | return $v2; 675 | } 676 | 677 | if ((3 * $vH) < 2) { 678 | return ($v1 + ($v2 - $v1) * ((2 / 3) - $vH) * 6); 679 | } 680 | 681 | return $v1; 682 | } 683 | 684 | /** 685 | * Checks the HEX string for correct formatting and converts short format to long 686 | * @param string $hex 687 | * @return string 688 | * @throws Exception 689 | */ 690 | private static function sanitizeHex(string $hex): string 691 | { 692 | // Strip # sign if it is present 693 | $color = str_replace("#", "", $hex); 694 | 695 | // Validate hex string 696 | if (!preg_match('/^[a-fA-F0-9]+$/', $color)) { 697 | throw new Exception("HEX color does not match format"); 698 | } 699 | 700 | // Make sure it's 6 digits 701 | if (strlen($color) === 3) { 702 | $color = $color[0] . $color[0] . $color[1] . $color[1] . $color[2] . $color[2]; 703 | } elseif (strlen($color) !== 6) { 704 | throw new Exception("HEX color needs to be 6 or 3 digits long"); 705 | } 706 | 707 | return $color; 708 | } 709 | 710 | /** 711 | * Converts object into its string representation 712 | * @return string 713 | */ 714 | public function __toString() 715 | { 716 | return "#" . $this->getHex(); 717 | } 718 | 719 | /** 720 | * @param string $name 721 | * @return mixed|null 722 | */ 723 | public function __get(string $name) 724 | { 725 | switch (strtolower($name)) { 726 | case 'red': 727 | case 'r': 728 | return $this->_rgb["R"]; 729 | case 'green': 730 | case 'g': 731 | return $this->_rgb["G"]; 732 | case 'blue': 733 | case 'b': 734 | return $this->_rgb["B"]; 735 | case 'hue': 736 | case 'h': 737 | return $this->_hsl["H"]; 738 | case 'saturation': 739 | case 's': 740 | return $this->_hsl["S"]; 741 | case 'lightness': 742 | case 'l': 743 | return $this->_hsl["L"]; 744 | } 745 | 746 | $trace = debug_backtrace(); 747 | trigger_error( 748 | 'Undefined property via __get(): ' . $name . ' in ' . $trace[0]['file'] . ' on line ' . $trace[0]['line'], 749 | E_USER_NOTICE 750 | ); 751 | return null; 752 | } 753 | 754 | /** 755 | * @param string $name 756 | * @param mixed $value 757 | * @throws Exception 758 | */ 759 | public function __set(string $name, $value) 760 | { 761 | switch (strtolower($name)) { 762 | case 'red': 763 | case 'r': 764 | $this->_rgb["R"] = $value; 765 | $this->_hex = self::rgbToHex($this->_rgb); 766 | $this->_hsl = self::hexToHsl($this->_hex); 767 | break; 768 | case 'green': 769 | case 'g': 770 | $this->_rgb["G"] = $value; 771 | $this->_hex = self::rgbToHex($this->_rgb); 772 | $this->_hsl = self::hexToHsl($this->_hex); 773 | break; 774 | case 'blue': 775 | case 'b': 776 | $this->_rgb["B"] = $value; 777 | $this->_hex = self::rgbToHex($this->_rgb); 778 | $this->_hsl = self::hexToHsl($this->_hex); 779 | break; 780 | case 'hue': 781 | case 'h': 782 | $this->_hsl["H"] = $value; 783 | $this->_hex = self::hslToHex($this->_hsl); 784 | $this->_rgb = self::hexToRgb($this->_hex); 785 | break; 786 | case 'saturation': 787 | case 's': 788 | $this->_hsl["S"] = $value; 789 | $this->_hex = self::hslToHex($this->_hsl); 790 | $this->_rgb = self::hexToRgb($this->_hex); 791 | break; 792 | case 'lightness': 793 | case 'light': 794 | case 'l': 795 | $this->_hsl["L"] = $value; 796 | $this->_hex = self::hslToHex($this->_hsl); 797 | $this->_rgb = self::hexToRgb($this->_hex); 798 | break; 799 | } 800 | } 801 | } 802 | --------------------------------------------------------------------------------