]> git.mxchange.org Git - friendica.git/blob - view/theme/frio/php/PHPColors/Color.php
Merge pull request #3112 from Quix0r/rewrites/coding-convention
[friendica.git] / view / theme / frio / php / PHPColors / Color.php
1 <?php
2
3 /**
4  * Author: Arlo Carreon <http://arlocarreon.com>
5  * Info: http://mexitek.github.io/phpColors/
6  * License: http://arlo.mit-license.org/
7  */
8
9
10 /**
11  * A color utility that helps manipulate HEX colors
12  * @todo convert space -> tab
13  */
14 class Color {
15
16     private $_hex;
17     private $_hsl;
18     private $_rgb;
19
20     /**
21      * Auto darkens/lightens by 10% for sexily-subtle gradients.
22      * Set this to FALSE to adjust automatic shade to be between given color
23      * and black (for darken) or white (for lighten)
24      */
25     const DEFAULT_ADJUST = 10;
26
27     /**
28      * Instantiates the class with a HEX value
29      * @param string $hex
30      * @throws Exception "Bad color format"
31      */
32     function __construct( $hex ) {
33         // Strip # sign is present
34         $color = str_replace("#", "", $hex);
35
36         // Make sure it's 6 digits
37         if ( strlen($color) === 3 ) {
38             $color = $color[0].$color[0].$color[1].$color[1].$color[2].$color[2];
39         } elseif ( strlen($color) != 6 ) {
40             throw new Exception("HEX color needs to be 6 or 3 digits long");
41         }
42
43         $this->_hsl = self::hexToHsl( $color );
44         $this->_hex = $color;
45         $this->_rgb = self::hexToRgb( $color );
46     }
47
48     // ====================
49     // = Public Interface =
50     // ====================
51
52     /**
53      * Given a HEX string returns a HSL array equivalent.
54      * @param string $color
55      * @return array HSL associative array
56      */
57     public static function hexToHsl( $color ){
58
59         // Sanity check
60         $color = self::_checkHex($color);
61
62         // Convert HEX to DEC
63         $R = hexdec($color[0].$color[1]);
64         $G = hexdec($color[2].$color[3]);
65         $B = hexdec($color[4].$color[5]);
66
67         $HSL = array();
68
69         $var_R = ($R / 255);
70         $var_G = ($G / 255);
71         $var_B = ($B / 255);
72
73         $var_Min = min($var_R, $var_G, $var_B);
74         $var_Max = max($var_R, $var_G, $var_B);
75         $del_Max = $var_Max - $var_Min;
76
77         $L = ($var_Max + $var_Min)/2;
78
79         if ($del_Max == 0)
80         {
81             $H = 0;
82             $S = 0;
83         }
84         else
85         {
86             if ( $L < 0.5 ) $S = $del_Max / ( $var_Max + $var_Min );
87             else            $S = $del_Max / ( 2 - $var_Max - $var_Min );
88
89             $del_R = ( ( ( $var_Max - $var_R ) / 6 ) + ( $del_Max / 2 ) ) / $del_Max;
90             $del_G = ( ( ( $var_Max - $var_G ) / 6 ) + ( $del_Max / 2 ) ) / $del_Max;
91             $del_B = ( ( ( $var_Max - $var_B ) / 6 ) + ( $del_Max / 2 ) ) / $del_Max;
92
93             if      ($var_R == $var_Max) $H = $del_B - $del_G;
94             else if ($var_G == $var_Max) $H = ( 1 / 3 ) + $del_R - $del_B;
95             else if ($var_B == $var_Max) $H = ( 2 / 3 ) + $del_G - $del_R;
96
97             if ($H<0) $H++;
98             if ($H>1) $H--;
99         }
100
101         $HSL['H'] = ($H*360);
102         $HSL['S'] = $S;
103         $HSL['L'] = $L;
104
105         return $HSL;
106     }
107
108     /**
109      *  Given a HSL associative array returns the equivalent HEX string
110      * @param array $hsl
111      * @return string HEX string
112      * @throws Exception "Bad HSL Array"
113      */
114     public static function hslToHex( $hsl = array() ){
115          // Make sure it's HSL
116         if (empty($hsl) || !isset($hsl["H"]) || !isset($hsl["S"]) || !isset($hsl["L"]) ) {
117             throw new Exception("Param was not an HSL array");
118         }
119
120         list($H,$S,$L) = array( $hsl['H']/360,$hsl['S'],$hsl['L'] );
121
122         if ( $S == 0 ) {
123             $r = $L * 255;
124             $g = $L * 255;
125             $b = $L * 255;
126         } else {
127
128             if ($L<0.5) {
129                 $var_2 = $L*(1+$S);
130             } else {
131                 $var_2 = ($L+$S) - ($S*$L);
132             }
133
134             $var_1 = 2 * $L - $var_2;
135
136             $r = round(255 * self::_huetorgb( $var_1, $var_2, $H + (1/3) ));
137             $g = round(255 * self::_huetorgb( $var_1, $var_2, $H ));
138             $b = round(255 * self::_huetorgb( $var_1, $var_2, $H - (1/3) ));
139
140         }
141
142         // Convert to hex
143         $r = dechex($r);
144         $g = dechex($g);
145         $b = dechex($b);
146
147         // Make sure we get 2 digits for decimals
148         $r = (strlen("".$r)===1) ? "0".$r:$r;
149         $g = (strlen("".$g)===1) ? "0".$g:$g;
150         $b = (strlen("".$b)===1) ? "0".$b:$b;
151
152         return $r.$g.$b;
153     }
154
155
156     /**
157      * Given a HEX string returns a RGB array equivalent.
158      * @param string $color
159      * @return array RGB associative array
160      */
161     public static function hexToRgb( $color ){
162
163         // Sanity check
164         $color = self::_checkHex($color);
165
166         // Convert HEX to DEC
167         $R = hexdec($color[0].$color[1]);
168         $G = hexdec($color[2].$color[3]);
169         $B = hexdec($color[4].$color[5]);
170
171         $RGB['R'] = $R;
172         $RGB['G'] = $G;
173         $RGB['B'] = $B;
174
175         return $RGB;
176     }
177
178
179     /**
180      *  Given an RGB associative array returns the equivalent HEX string
181      * @param array $rgb
182      * @return string RGB string
183      * @throws Exception "Bad RGB Array"
184      */
185     public static function rgbToHex( $rgb = array() ){
186          // Make sure it's RGB
187         if (empty($rgb) || !isset($rgb["R"]) || !isset($rgb["G"]) || !isset($rgb["B"]) ) {
188             throw new Exception("Param was not an RGB array");
189         }
190
191         // https://github.com/mexitek/phpColors/issues/25#issuecomment-88354815
192         // Convert RGB to HEX
193         $hex[0] = str_pad(dechex($rgb['R']), 2, '0', STR_PAD_LEFT);
194         $hex[1] = str_pad(dechex($rgb['G']), 2, '0', STR_PAD_LEFT);
195         $hex[2] = str_pad(dechex($rgb['B']), 2, '0', STR_PAD_LEFT);
196
197         return implode( '', $hex );
198
199   }
200
201
202     /**
203      * Given a HEX value, returns a darker color. If no desired amount provided, then the color halfway between
204      * given HEX and black will be returned.
205      * @param int $amount
206      * @return string Darker HEX value
207      */
208     public function darken( $amount = self::DEFAULT_ADJUST ){
209         // Darken
210         $darkerHSL = $this->_darken($this->_hsl, $amount);
211         // Return as HEX
212         return self::hslToHex($darkerHSL);
213     }
214
215     /**
216      * Given a HEX value, returns a lighter color. If no desired amount provided, then the color halfway between
217      * given HEX and white will be returned.
218      * @param int $amount
219      * @return string Lighter HEX value
220      */
221     public function lighten( $amount = self::DEFAULT_ADJUST ){
222         // Lighten
223         $lighterHSL = $this->_lighten($this->_hsl, $amount);
224         // Return as HEX
225         return self::hslToHex($lighterHSL);
226     }
227
228     /**
229      * Given a HEX value, returns a mixed color. If no desired amount provided, then the color mixed by this ratio
230      * @param string $hex2 Secondary HEX value to mix with
231      * @param int $amount = -100..0..+100
232      * @return string mixed HEX value
233      */
234     public function mix($hex2, $amount = 0){
235         $rgb2 = self::hexToRgb($hex2);
236         $mixed = $this->_mix($this->_rgb, $rgb2, $amount);
237         // Return as HEX
238         return self::rgbToHex($mixed);
239     }
240
241     /**
242      * Creates an array with two shades that can be used to make a gradient
243      * @param int $amount Optional percentage amount you want your contrast color
244      * @return array An array with a 'light' and 'dark' index
245      */
246     public function makeGradient( $amount = self::DEFAULT_ADJUST ) {
247         // Decide which color needs to be made
248         if ( $this->isLight() ) {
249             $lightColor = $this->_hex;
250             $darkColor = $this->darken($amount);
251         } else {
252             $lightColor = $this->lighten($amount);
253             $darkColor = $this->_hex;
254         }
255
256         // Return our gradient array
257         return array( "light" => $lightColor, "dark" => $darkColor );
258     }
259
260
261     /**
262      * Returns whether or not given color is considered "light"
263      * @param string|Boolean $color
264      * @param int $lighterThan
265      * @return boolean
266      */
267     public function isLight( $color = FALSE, $lighterThan = 130 ){
268         // Get our color
269         $color = ($color) ? $color : $this->_hex;
270
271         // Calculate straight from rbg
272         $r = hexdec($color[0].$color[1]);
273         $g = hexdec($color[2].$color[3]);
274         $b = hexdec($color[4].$color[5]);
275
276         return (( $r*299 + $g*587 + $b*114 )/1000 > $lighterThan);
277     }
278
279     /**
280      * Returns whether or not a given color is considered "dark"
281      * @param string|Boolean $color
282      * @param int $darkerThan
283      * @return boolean
284      */
285     public function isDark( $color = FALSE, $darkerThan = 130 ){
286         // Get our color
287         $color = ($color) ? $color:$this->_hex;
288
289         // Calculate straight from rbg
290         $r = hexdec($color[0].$color[1]);
291         $g = hexdec($color[2].$color[3]);
292         $b = hexdec($color[4].$color[5]);
293
294         return (( $r*299 + $g*587 + $b*114 )/1000 <= $darkerThan);
295     }
296
297     /**
298      * Returns the complimentary color
299      * @return string Complementary hex color
300      *
301      */
302     public function complementary() {
303         // Get our HSL
304         $hsl = $this->_hsl;
305
306         // Adjust Hue 180 degrees
307         $hsl['H'] += ($hsl['H']>180) ? -180:180;
308
309         // Return the new value in HEX
310         return self::hslToHex($hsl);
311     }
312     
313     /**
314      * Returns your color's HSL array
315      */
316     public function getHsl() {
317         return $this->_hsl;
318     }
319     /**
320      * Returns your original color
321      */
322     public function getHex() {
323         return $this->_hex;
324     }
325     /**
326      * Returns your color's RGB array
327      */
328     public function getRgb() {
329         return $this->_rgb;
330     }
331     
332     /**
333      * Returns the cross browser CSS3 gradient
334      * @param int $amount Optional: percentage amount to light/darken the gradient
335      * @param boolean $vintageBrowsers Optional: include vendor prefixes for browsers that almost died out already
336      * @param string $prefix Optional: prefix for every lines
337      * @param string $suffix Optional: suffix for every lines
338      * @link  http://caniuse.com/css-gradients Resource for the browser support
339      * @return string CSS3 gradient for chrome, safari, firefox, opera and IE10
340      */
341     public function getCssGradient( $amount = self::DEFAULT_ADJUST, $vintageBrowsers = FALSE, $suffix = "" , $prefix = "" ) {
342
343         // Get the recommended gradient
344         $g = $this->makeGradient($amount);
345
346         $css = "";
347         /* fallback/image non-cover color */
348         $css .= "{$prefix}background-color: #".$this->_hex.";{$suffix}";
349
350         /* IE Browsers */
351         $css .= "{$prefix}filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#".$g['light']."', endColorstr='#".$g['dark']."');{$suffix}";
352
353         /* Safari 4+, Chrome 1-9 */
354         if ( $vintageBrowsers ) {
355             $css .= "{$prefix}background-image: -webkit-gradient(linear, 0% 0%, 0% 100%, from(#".$g['light']."), to(#".$g['dark']."));{$suffix}";
356         }
357
358         /* Safari 5.1+, Mobile Safari, Chrome 10+ */
359         $css .= "{$prefix}background-image: -webkit-linear-gradient(top, #".$g['light'].", #".$g['dark'].");{$suffix}";
360
361         /* Firefox 3.6+ */
362         if ( $vintageBrowsers ) {
363             $css .= "{$prefix}background-image: -moz-linear-gradient(top, #".$g['light'].", #".$g['dark'].");{$suffix}";
364         }
365
366         /* Opera 11.10+ */
367         if ( $vintageBrowsers ) {
368             $css .= "{$prefix}background-image: -o-linear-gradient(top, #".$g['light'].", #".$g['dark'].");{$suffix}";
369         }
370
371         /* Unprefixed version (standards): FF 16+, IE10+, Chrome 26+, Safari 7+, Opera 12.1+ */
372         $css .= "{$prefix}background-image: linear-gradient(to bottom, #".$g['light'].", #".$g['dark'].");{$suffix}";
373
374         // Return our CSS
375         return $css;
376     }
377
378     // ===========================
379     // = Private Functions Below =
380     // ===========================
381
382
383     /**
384      * Darkens a given HSL array
385      * @param array $hsl
386      * @param int $amount
387      * @return array $hsl
388      */
389     private function _darken( $hsl, $amount = self::DEFAULT_ADJUST){
390         // Check if we were provided a number
391         if ( $amount ) {
392             $hsl['L'] = ($hsl['L'] * 100) - $amount;
393             $hsl['L'] = ($hsl['L'] < 0) ? 0:$hsl['L']/100;
394         } else {
395             // We need to find out how much to darken
396             $hsl['L'] = $hsl['L']/2 ;
397         }
398
399         return $hsl;
400     }
401
402     /**
403      * Lightens a given HSL array
404      * @param array $hsl
405      * @param int $amount
406      * @return array $hsl
407      */
408     private function _lighten( $hsl, $amount = self::DEFAULT_ADJUST){
409         // Check if we were provided a number
410         if ( $amount ) {
411             $hsl['L'] = ($hsl['L'] * 100) + $amount;
412             $hsl['L'] = ($hsl['L'] > 100) ? 1:$hsl['L']/100;
413         } else {
414             // We need to find out how much to lighten
415             $hsl['L'] += (1-$hsl['L'])/2;
416         }
417
418         return $hsl;
419     }
420
421     /**
422      * Mix 2 rgb colors and return an rgb color
423      * @param array $rgb1
424      * @param array $rgb2
425      * @param int $amount ranged -100..0..+100
426      * @return array $rgb
427      *
428      *  ported from http://phpxref.pagelines.com/nav.html?includes/class.colors.php.source.html
429      */
430     private function _mix($rgb1, $rgb2, $amount = 0) {
431
432          $r1 = ($amount + 100) / 100;
433          $r2 = 2 - $r1;
434
435          $rmix = (($rgb1['R'] * $r1) + ($rgb2['R'] * $r2)) / 2;
436          $gmix = (($rgb1['G'] * $r1) + ($rgb2['G'] * $r2)) / 2;
437          $bmix = (($rgb1['B'] * $r1) + ($rgb2['B'] * $r2)) / 2;
438
439          return array('R' => $rmix, 'G' => $gmix, 'B' => $bmix);
440      }
441
442     /**
443      * Given a Hue, returns corresponding RGB value
444      * @param int $v1
445      * @param int $v2
446      * @param int $vH
447      * @return int
448      */
449     private static function _huetorgb( $v1,$v2,$vH ) {
450         if ( $vH < 0 ) {
451             $vH += 1;
452         }
453
454         if ( $vH > 1 ) {
455             $vH -= 1;
456         }
457
458         if ( (6*$vH) < 1 ) {
459                return ($v1 + ($v2 - $v1) * 6 * $vH);
460         }
461
462         if ( (2*$vH) < 1 ) {
463             return $v2;
464         }
465
466         if ( (3*$vH) < 2 ) {
467             return ($v1 + ($v2-$v1) * ( (2/3)-$vH ) * 6);
468         }
469
470         return $v1;
471
472     }
473
474     /**
475      * You need to check if you were given a good hex string
476      * @param string $hex
477      * @return string Color
478      * @throws Exception "Bad color format"
479      */
480     private static function _checkHex( $hex ) {
481         // Strip # sign is present
482         $color = str_replace("#", "", $hex);
483
484         // Make sure it's 6 digits
485         if ( strlen($color) == 3 ) {
486             $color = $color[0].$color[0].$color[1].$color[1].$color[2].$color[2];
487         } elseif ( strlen($color) != 6 ) {
488             throw new Exception("HEX color needs to be 6 or 3 digits long");
489         }
490
491         return $color;
492     }
493
494 }