(NFC) (dev/core#878) Simplify copyright header (CRM/*)
[civicrm-core.git] / CRM / Utils / Color.php
1 <?php
2 /*
3 +--------------------------------------------------------------------+
4 | Copyright CiviCRM LLC. All rights reserved. |
5 | |
6 | This work is published under the GNU AGPLv3 license with some |
7 | permitted exceptions and without any warranty. For full license |
8 | and copyright information, see https://civicrm.org/licensing |
9 +--------------------------------------------------------------------+
10 */
11
12 /**
13 *
14 * @package CRM
15 * @copyright CiviCRM LLC https://civicrm.org/licensing
16 */
17
18 /**
19 * Static utility functions for working with colors
20 */
21 class CRM_Utils_Color {
22
23 const COLOR_FILE = '[civicrm.root]/bower_components/css-color-names/css-color-names.json';
24
25 /**
26 * Determine the appropriate text color for a given background.
27 *
28 * Based on YIQ value.
29 *
30 * @param string $color
31 * @param string $black
32 * @param string $white
33 * @return string
34 */
35 public static function getContrast($color, $black = 'black', $white = 'white') {
36 list($r, $g, $b) = self::getRgb($color);
37 $yiq = (($r * 299) + ($g * 587) + ($b * 114)) / 1000;
38 return ($yiq >= 128) ? $black : $white;
39 }
40
41 /**
42 * Parse any color string into rgb decimal values
43 *
44 * Accepted formats:
45 * Full hex: "#ffffff"
46 * Short hex: "#fff"
47 * Color name "white"
48 * RGB notation: "rgb(255, 255, 255)"
49 *
50 * @param string $color
51 * @return int[]|null
52 * [red, green, blue]
53 */
54 public static function getRgb($color) {
55 $color = str_replace(' ', '', $color);
56 $color = self::nameToHex($color) ?? $color;
57 if (strpos($color, 'rgb(') === 0) {
58 return explode(',', substr($color, 4, strpos($color, ')') - 4));
59 }
60 $color = ltrim($color, '#');
61 if (strlen($color) === 3) {
62 $color = $color[0] . $color[0] . $color[1] . $color[1] . $color[2] . $color[2];
63 }
64 if (!CRM_Utils_Rule::color('#' . $color)) {
65 return NULL;
66 }
67 return [
68 hexdec(substr($color, 0, 2)),
69 hexdec(substr($color, 2, 2)),
70 hexdec(substr($color, 4, 2)),
71 ];
72 }
73
74 /**
75 * Calculate a highlight color from a base color
76 *
77 * @param $color
78 * @return string
79 */
80 public static function getHighlight($color) {
81 $rgb = self::getRgb($color);
82 $avg = array_sum($rgb) / 3;
83 foreach ($rgb as &$v) {
84 if ($avg > 242) {
85 // For very bright values, lower the brightness
86 $v -= 50;
87 }
88 else {
89 // Bump up brightness on a nonlinear curve - darker colors get more of a boost
90 $v = min(255, intval((-.0035 * ($v - 242) ** 2) + 260));
91 }
92 }
93 return self::rgbToHex($rgb);
94 }
95
96 /**
97 * Convert named color (e.g. springgreen) to hex
98 *
99 * @param $colorName
100 * @return string|null
101 */
102 public static function nameToHex($colorName) {
103 if (strpos($colorName, '#') !== FALSE || strpos($colorName, '(') !== FALSE) {
104 return NULL;
105 }
106 if (empty(Civi::$statics[__CLASS__]['names'])) {
107 Civi::$statics[__CLASS__]['names'] = json_decode(file_get_contents(Civi::paths()->getPath(self::COLOR_FILE)), TRUE);
108 }
109 return Civi::$statics[__CLASS__]['names'][strtolower($colorName)] ?? NULL;
110 }
111
112 /**
113 * Converts rgb array to hex string
114 *
115 * @param int[] $rgb
116 * @return string
117 */
118 public static function rgbToHex($rgb) {
119 $ret = '#';
120 foreach ($rgb as $dec) {
121 $ret .= str_pad(dechex($dec), 2, '0', STR_PAD_LEFT);
122 }
123 return $ret;
124 }
125
126 /**
127 * Validate color input and convert it to standard hex notation
128 *
129 * @param string $color
130 * @return bool
131 */
132 public static function normalize(&$color) {
133 $rgb = self::getRgb($color);
134 if ($rgb) {
135 $color = self::rgbToHex($rgb);
136 return TRUE;
137 }
138 return FALSE;
139 }
140
141 }