1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
|
4
|
|
|
namespace projectcleverweb\color; |
5
|
|
|
|
6
|
|
|
|
7
|
|
|
class generate { |
8
|
|
|
|
9
|
|
|
/** |
10
|
|
|
* Convert a hex string (no #) to a RGB array |
11
|
|
|
* |
12
|
|
|
* @param string $hex The hex string to convert (no #) |
13
|
|
|
* @return array The RGB array |
14
|
|
|
*/ |
15
|
1 |
|
public static function hex_to_rgb(string $hex) :array { |
16
|
|
|
return [ |
17
|
1 |
|
'r' => hexdec(substr($hex, 0, 2)), |
18
|
1 |
|
'g' => hexdec(substr($hex, 2, 2)), |
19
|
1 |
|
'b' => hexdec(substr($hex, 4, 2)) |
20
|
|
|
]; |
21
|
|
|
} |
22
|
|
|
|
23
|
1 |
|
public static function rgb_to_hex(int $r, int $g, int $b) :string { |
24
|
1 |
|
return strtoupper( |
25
|
1 |
|
str_pad(dechex($r), 2, '0', STR_PAD_LEFT) |
26
|
1 |
|
.str_pad(dechex($g), 2, '0', STR_PAD_LEFT) |
27
|
1 |
|
.str_pad(dechex($b), 2, '0', STR_PAD_LEFT) |
28
|
|
|
); |
29
|
|
|
} |
30
|
|
|
|
31
|
1 |
|
public static function rgb_to_cmyk(float $r, float $g, float $b) :array { |
32
|
1 |
|
$c = (255 - $r) / 255 * 100; |
33
|
1 |
|
$m = (255 - $g) / 255 * 100; |
34
|
1 |
|
$y = (255 - $b) / 255 * 100; |
35
|
1 |
|
$k = min(array($c,$m,$y)); |
36
|
1 |
|
$c -= $k; |
37
|
1 |
|
$m -= $k; |
38
|
1 |
|
$y -= $k; |
39
|
|
|
return [ |
40
|
1 |
|
'c' => round($c), |
41
|
1 |
|
'm' => round($m), |
42
|
1 |
|
'y' => round($y), |
43
|
1 |
|
'k' => round($k) |
44
|
|
|
]; |
45
|
|
|
} |
46
|
|
|
|
47
|
1 |
|
public static function cmyk_to_rgb(float $c, float $m, float $y, float $k) :array { |
48
|
1 |
|
$c /= 100; |
49
|
1 |
|
$m /= 100; |
50
|
1 |
|
$y /= 100; |
51
|
1 |
|
$k /= 100; |
52
|
1 |
|
$r = 1 - min(1, $c * (1 - $k) + $k); |
53
|
1 |
|
$g = 1 - min(1, $m * (1 - $k) + $k); |
54
|
1 |
|
$b = 1 - min(1, $y * (1 - $k) + $k); |
55
|
|
|
return [ |
56
|
1 |
|
'r' => round($r * 255), |
57
|
1 |
|
'g' => round($g * 255), |
58
|
1 |
|
'b' => round($b * 255) |
59
|
|
|
]; |
60
|
|
|
} |
61
|
|
|
|
62
|
1 |
|
public static function rgb_contrast(int $r = 0, int $g = 0, int $b = 0) :array { |
63
|
|
|
return [ |
64
|
1 |
|
'r' => ($r < 128) ? 255 : 0, |
65
|
1 |
|
'g' => ($g < 128) ? 255 : 0, |
66
|
1 |
|
'b' => ($b < 128) ? 255 : 0 |
67
|
|
|
]; |
68
|
|
|
} |
69
|
|
|
|
70
|
1 |
|
public static function rgb_invert(int $r = 0, int $g = 0, int $b = 0) :array { |
71
|
|
|
return [ |
72
|
1 |
|
'r' => 255 - $r, |
73
|
1 |
|
'g' => 255 - $g, |
74
|
1 |
|
'b' => 255 - $b |
75
|
|
|
]; |
76
|
|
|
} |
77
|
|
|
|
78
|
2 |
|
public static function yiq_score(int $r = 0, int $g = 0, int $b = 0) :float { |
79
|
2 |
|
return (($r * 299) + ($g * 587) + ($b * 114)) / 1000; |
80
|
|
|
} |
81
|
|
|
|
82
|
1 |
|
public static function rand(int $min_r = 0, int $max_r = 255, int $min_g = 0, int $max_g = 255, int $min_b = 0, int $max_b = 255) :array { |
83
|
|
|
return [ |
84
|
1 |
|
'r' => rand(abs((int) $min_r) % 256, abs((int) $max_r) % 256), |
85
|
1 |
|
'g' => rand(abs((int) $min_g) % 256, abs((int) $max_g) % 256), |
86
|
1 |
|
'b' => rand(abs((int) $min_b) % 256, abs((int) $max_b) % 256) |
87
|
|
|
]; |
88
|
|
|
} |
89
|
|
|
|
90
|
|
|
|
91
|
2 |
|
public static function rgb_to_hsl(int $r = 0, int $g = 0, int $b = 0, $accuracy = 2) :array { |
92
|
2 |
|
$r /= 255; |
93
|
2 |
|
$g /= 255; |
94
|
2 |
|
$b /= 255; |
95
|
2 |
|
$min = min($r, $g, $b); |
96
|
2 |
|
$max = max($r, $g, $b); |
97
|
2 |
|
$delta = $max - $min; |
98
|
2 |
|
$h = 0; |
99
|
2 |
|
$s = 0; |
100
|
2 |
|
$l = ($max + $min) / 2; |
101
|
|
|
|
102
|
2 |
|
if ($max != $min) { |
103
|
2 |
|
$s = $delta / ($max + $min); |
104
|
2 |
|
if ($l >= 0.5) { |
105
|
2 |
|
$s = $delta / (2 - $max - $min); |
106
|
|
|
} |
107
|
2 |
|
static::_rgbhsl_hue($h, $r, $g, $b, $max, $delta); |
108
|
|
|
} |
109
|
|
|
|
110
|
|
|
return [ |
111
|
2 |
|
'h' => round($h * 360, $accuracy), |
112
|
2 |
|
's' => round($s * 100, $accuracy), |
113
|
2 |
|
'l' => round($l * 100, $accuracy) |
114
|
|
|
]; |
115
|
|
|
} |
116
|
|
|
|
117
|
3 |
|
protected static function _rgbhsl_delta_rgb(float $rgb, float $max, float $delta) { |
118
|
3 |
|
return ((($max - $rgb) / 6) + ($delta / 2)) / $delta; |
119
|
|
|
} |
120
|
|
|
|
121
|
3 |
|
protected static function _rgbhsl_hue(float &$h, float $r, float $g, float $b, float $max, float $delta) { |
122
|
3 |
|
$delta_r = static::_rgbhsl_delta_rgb($r, $max, $delta); |
123
|
3 |
|
$delta_g = static::_rgbhsl_delta_rgb($g, $max, $delta); |
124
|
3 |
|
$delta_b = static::_rgbhsl_delta_rgb($b, $max, $delta); |
125
|
|
|
|
126
|
3 |
|
$h = (2 / 3) + $delta_g - $delta_r; |
127
|
3 |
|
if ($r == $max) { |
128
|
3 |
|
$h = $delta_b - $delta_g; |
129
|
3 |
|
} elseif ($g == $max) { |
130
|
3 |
|
$h = (1 / 3) + $delta_r - $delta_b; |
131
|
|
|
} |
132
|
3 |
|
if ($h < 0) { |
133
|
3 |
|
$h++; |
134
|
|
|
} |
135
|
3 |
|
} |
136
|
|
|
|
137
|
2 |
|
public static function hsl_to_rgb(float $h = 0, float $s = 0, float $l = 0) :array { |
138
|
2 |
|
$s /= 100; |
139
|
2 |
|
$l /= 100; |
140
|
2 |
|
$c = (1 - abs((2 * $l) - 1)) * $s; |
141
|
2 |
|
$x = $c * (1 - abs(fmod(($h / 60), 2) - 1)); |
142
|
2 |
|
$m = $l - ($c / 2); |
143
|
2 |
|
$r = $c; |
144
|
2 |
|
$g = 0; |
145
|
2 |
|
$b = $x; |
146
|
|
|
|
147
|
2 |
|
if ($h < 180) { |
148
|
2 |
|
self::_hslrgb_low($r, $g, $b, $c, $x, $h); |
149
|
2 |
|
} elseif ($h < 300) { |
150
|
2 |
|
self::_hslrgb_high($r, $g, $b, $c, $x, $h); |
151
|
|
|
} |
152
|
|
|
|
153
|
|
|
return [ |
154
|
2 |
|
'r' => (int) round(($r + $m) * 255), |
155
|
2 |
|
'g' => (int) round(($g + $m) * 255), |
156
|
2 |
|
'b' => (int) round(($b + $m) * 255) |
157
|
|
|
]; |
158
|
|
|
} |
159
|
|
|
|
160
|
2 |
|
private static function _hslrgb_low(float &$r, float &$g, float &$b, float $c, float $x, float $h) { |
161
|
2 |
|
if ($h < 60) { |
162
|
2 |
|
$r = $c; |
163
|
2 |
|
$g = $x; |
164
|
2 |
|
$b = 0; |
165
|
2 |
|
} elseif ($h < 120) { |
166
|
2 |
|
$r = $x; |
167
|
2 |
|
$g = $c; |
168
|
2 |
|
$b = 0; |
169
|
2 |
|
} elseif ($h < 180) { |
170
|
2 |
|
$r = 0; |
171
|
2 |
|
$g = $c; |
172
|
2 |
|
$b = $x; |
173
|
|
|
} |
174
|
2 |
|
} |
175
|
|
|
|
176
|
2 |
|
private static function _hslrgb_high(float &$r, float &$g, float &$b, float $c, float $x, float $h) { |
177
|
2 |
|
if ($h < 240) { |
178
|
2 |
|
$r = 0; |
179
|
2 |
|
$g = $x; |
180
|
2 |
|
$b = $c; |
181
|
2 |
|
} elseif ($h < 300) { |
182
|
2 |
|
$r = $x; |
183
|
2 |
|
$g = 0; |
184
|
2 |
|
$b = $c; |
185
|
|
|
} |
186
|
2 |
|
} |
187
|
|
|
|
188
|
1 |
|
public static function rgb_to_hsb(float $r, float $g, float $b, int $accuracy = 3) :array { |
189
|
1 |
|
$r /= 255; |
190
|
1 |
|
$g /= 255; |
191
|
1 |
|
$b /= 255; |
192
|
|
|
|
193
|
1 |
|
$max = max($r, $g, $b); |
194
|
1 |
|
$min = min($r, $g, $b); |
195
|
1 |
|
$v = $max; |
196
|
1 |
|
$d = $max - $min; |
197
|
1 |
|
$s = static::_div($d, $max); |
198
|
1 |
|
$h = 0; // achromatic |
199
|
1 |
|
if ($max != $min) { |
200
|
1 |
|
static::_rgbhsl_hue($h, $r, $g, $b, $max, $d); |
201
|
|
|
} |
202
|
|
|
|
203
|
1 |
|
$h = round($h * 360, $accuracy); |
204
|
1 |
|
$s = round($s * 100, $accuracy); |
205
|
1 |
|
$v = round($v * 100, $accuracy); |
206
|
|
|
|
207
|
1 |
|
return ['h' => $h, 's' => $s, 'b' => $v]; |
208
|
|
|
} |
209
|
|
|
|
210
|
1 |
|
public static function hsb_to_rgb(float $h, float $s, float $v, int $accuracy = 3) :array { |
211
|
1 |
|
if ($v == 0) { |
212
|
1 |
|
return ['r' => 0, 'g' => 0, 'b' => 0]; |
213
|
|
|
} |
214
|
|
|
|
215
|
1 |
|
$s /= 100; |
216
|
1 |
|
$v /= 100; |
217
|
1 |
|
$h /= 60; |
218
|
1 |
|
$i = floor($h); |
219
|
1 |
|
$f = $h - $i; |
220
|
1 |
|
$p = $v * (1 - $s); |
221
|
1 |
|
$q = $v * (1 - ($s * $f)); |
222
|
1 |
|
$t = $v * (1 - ($s * (1 - $f))); |
223
|
|
|
$calc = [ |
224
|
1 |
|
[$v, $t, $p], |
225
|
1 |
|
[$q, $v, $p], |
226
|
1 |
|
[$p, $v, $t], |
227
|
1 |
|
[$p, $q, $v], |
228
|
1 |
|
[$t, $p, $v], |
229
|
1 |
|
[$v, $p, $q] |
230
|
|
|
]; |
231
|
|
|
|
232
|
1 |
|
$r = round($calc[$i][0] * 255, $accuracy); |
233
|
1 |
|
$g = round($calc[$i][1] * 255, $accuracy); |
234
|
1 |
|
$b = round($calc[$i][2] * 255, $accuracy); |
235
|
|
|
|
236
|
1 |
|
return ['r' => $r, 'g' => $g, 'b' => $b]; |
237
|
|
|
} |
238
|
|
|
|
239
|
|
|
public static function blend(float $r1, float $g1, float $b1, float $a1, float $r2, float $g2, float $b2, float $a2, float $amount = 50.0) :array { |
240
|
|
|
$x1 = static::_div(100 - $amount, 100); |
241
|
|
|
$x2 = static::_div($amount, 100); |
242
|
|
|
return [ |
243
|
|
|
'r' => round(($r1 * $x1) + ($r2 * $x2), 0), |
244
|
|
|
'g' => round(($g1 * $x1) + ($g2 * $x2), 0), |
245
|
|
|
'b' => round(($b1 * $x1) + ($b2 * $x2), 0), |
246
|
|
|
'a' => ($a1 * $x1) + ($a2 * $x2) |
247
|
|
|
]; |
248
|
|
|
} |
249
|
|
|
|
250
|
1 |
|
public static function _div(float $number, float $divisor) { |
251
|
1 |
|
if ($divisor == 0) { |
252
|
1 |
|
return 0; |
253
|
|
|
} |
254
|
1 |
|
return $number / $divisor; |
255
|
|
|
} |
256
|
|
|
} |
257
|
|
|
|