├── 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 [](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 |
--------------------------------------------------------------------------------