xref: /template/strap/ComboStrap/ColorRgb.php (revision 4cadd4f8c541149bdda95f080e38a6d4e3a640ca)
1*4cadd4f8SNickeau<?php
2*4cadd4f8SNickeau/**
3*4cadd4f8SNickeau * Copyright (c) 2020. ComboStrap, Inc. and its affiliates. All Rights Reserved.
4*4cadd4f8SNickeau *
5*4cadd4f8SNickeau * This source code is licensed under the GPL license found in the
6*4cadd4f8SNickeau * COPYING  file in the root directory of this source tree.
7*4cadd4f8SNickeau *
8*4cadd4f8SNickeau * @license  GPL 3 (https://www.gnu.org/licenses/gpl-3.0.en.html)
9*4cadd4f8SNickeau * @author   ComboStrap <support@combostrap.com>
10*4cadd4f8SNickeau *
11*4cadd4f8SNickeau */
12*4cadd4f8SNickeau
13*4cadd4f8SNickeaunamespace ComboStrap;
14*4cadd4f8SNickeau
15*4cadd4f8SNickeau
16*4cadd4f8SNickeauuse dokuwiki\StyleUtils;
17*4cadd4f8SNickeau
18*4cadd4f8SNickeauclass ColorRgb
19*4cadd4f8SNickeau{
20*4cadd4f8SNickeau
21*4cadd4f8SNickeau    const COLOR = "color";
22*4cadd4f8SNickeau
23*4cadd4f8SNickeau    const BORDER_COLOR = "border-color";
24*4cadd4f8SNickeau
25*4cadd4f8SNickeau    const BOOTSTRAP_COLORS = array(
26*4cadd4f8SNickeau        'blue',
27*4cadd4f8SNickeau        'indigo',
28*4cadd4f8SNickeau        'purple',
29*4cadd4f8SNickeau        'pink',
30*4cadd4f8SNickeau        'red',
31*4cadd4f8SNickeau        'orange',
32*4cadd4f8SNickeau        'yellow',
33*4cadd4f8SNickeau        'green',
34*4cadd4f8SNickeau        'teal',
35*4cadd4f8SNickeau        'cyan',
36*4cadd4f8SNickeau        //'white', css value for now otherwise we don't know the value when tinting
37*4cadd4f8SNickeau        //'gray', css value for now otherwise we don't know the value when tinting
38*4cadd4f8SNickeau        'gray-dark',
39*4cadd4f8SNickeau        self::PRIMARY_VALUE,
40*4cadd4f8SNickeau        self::SECONDARY_VALUE,
41*4cadd4f8SNickeau        'success',
42*4cadd4f8SNickeau        'info',
43*4cadd4f8SNickeau        'warning',
44*4cadd4f8SNickeau        'danger',
45*4cadd4f8SNickeau        'light',
46*4cadd4f8SNickeau        'dark'
47*4cadd4f8SNickeau    );
48*4cadd4f8SNickeau    /**
49*4cadd4f8SNickeau     * https://drafts.csswg.org/css-color/#color-keywords
50*4cadd4f8SNickeau     */
51*4cadd4f8SNickeau    const CSS_COLOR_NAMES = array(
52*4cadd4f8SNickeau        'aliceblue' => '#F0F8FF',
53*4cadd4f8SNickeau        'antiquewhite' => '#FAEBD7',
54*4cadd4f8SNickeau        'aqua' => '#00FFFF',
55*4cadd4f8SNickeau        'aquamarine' => '#7FFFD4',
56*4cadd4f8SNickeau        'azure' => '#F0FFFF',
57*4cadd4f8SNickeau        'beige' => '#F5F5DC',
58*4cadd4f8SNickeau        'bisque' => '#FFE4C4',
59*4cadd4f8SNickeau        'black' => '#000000',
60*4cadd4f8SNickeau        'blanchedalmond' => '#FFEBCD',
61*4cadd4f8SNickeau        'blue' => '#0000FF',
62*4cadd4f8SNickeau        'blueviolet' => '#8A2BE2',
63*4cadd4f8SNickeau        'brown' => '#A52A2A',
64*4cadd4f8SNickeau        'burlywood' => '#DEB887',
65*4cadd4f8SNickeau        'cadetblue' => '#5F9EA0',
66*4cadd4f8SNickeau        'chartreuse' => '#7FFF00',
67*4cadd4f8SNickeau        'chocolate' => '#D2691E',
68*4cadd4f8SNickeau        'coral' => '#FF7F50',
69*4cadd4f8SNickeau        'cornflowerblue' => '#6495ED',
70*4cadd4f8SNickeau        'cornsilk' => '#FFF8DC',
71*4cadd4f8SNickeau        'crimson' => '#DC143C',
72*4cadd4f8SNickeau        'cyan' => '#00FFFF',
73*4cadd4f8SNickeau        'darkblue' => '#00008B',
74*4cadd4f8SNickeau        'darkcyan' => '#008B8B',
75*4cadd4f8SNickeau        'darkgoldenrod' => '#B8860B',
76*4cadd4f8SNickeau        'darkgray' => '#A9A9A9',
77*4cadd4f8SNickeau        'darkgreen' => '#006400',
78*4cadd4f8SNickeau        'darkgrey' => '#A9A9A9',
79*4cadd4f8SNickeau        'darkkhaki' => '#BDB76B',
80*4cadd4f8SNickeau        'darkmagenta' => '#8B008B',
81*4cadd4f8SNickeau        'darkolivegreen' => '#556B2F',
82*4cadd4f8SNickeau        'darkorange' => '#FF8C00',
83*4cadd4f8SNickeau        'darkorchid' => '#9932CC',
84*4cadd4f8SNickeau        'darkred' => '#8B0000',
85*4cadd4f8SNickeau        'darksalmon' => '#E9967A',
86*4cadd4f8SNickeau        'darkseagreen' => '#8FBC8F',
87*4cadd4f8SNickeau        'darkslateblue' => '#483D8B',
88*4cadd4f8SNickeau        'darkslategray' => '#2F4F4F',
89*4cadd4f8SNickeau        'darkslategrey' => '#2F4F4F',
90*4cadd4f8SNickeau        'darkturquoise' => '#00CED1',
91*4cadd4f8SNickeau        'darkviolet' => '#9400D3',
92*4cadd4f8SNickeau        'deeppink' => '#FF1493',
93*4cadd4f8SNickeau        'deepskyblue' => '#00BFFF',
94*4cadd4f8SNickeau        'dimgray' => '#696969',
95*4cadd4f8SNickeau        'dimgrey' => '#696969',
96*4cadd4f8SNickeau        'dodgerblue' => '#1E90FF',
97*4cadd4f8SNickeau        'firebrick' => '#B22222',
98*4cadd4f8SNickeau        'floralwhite' => '#FFFAF0',
99*4cadd4f8SNickeau        'forestgreen' => '#228B22',
100*4cadd4f8SNickeau        'fuchsia' => '#FF00FF',
101*4cadd4f8SNickeau        'gainsboro' => '#DCDCDC',
102*4cadd4f8SNickeau        'ghostwhite' => '#F8F8FF',
103*4cadd4f8SNickeau        'gold' => '#FFD700',
104*4cadd4f8SNickeau        'goldenrod' => '#DAA520',
105*4cadd4f8SNickeau        'gray' => '#808080',
106*4cadd4f8SNickeau        'green' => '#008000',
107*4cadd4f8SNickeau        'greenyellow' => '#ADFF2F',
108*4cadd4f8SNickeau        'grey' => '#808080',
109*4cadd4f8SNickeau        'honeydew' => '#F0FFF0',
110*4cadd4f8SNickeau        'hotpink' => '#FF69B4',
111*4cadd4f8SNickeau        'indianred' => '#CD5C5C',
112*4cadd4f8SNickeau        'indigo' => '#4B0082',
113*4cadd4f8SNickeau        'ivory' => '#FFFFF0',
114*4cadd4f8SNickeau        'khaki' => '#F0E68C',
115*4cadd4f8SNickeau        'lavender' => '#E6E6FA',
116*4cadd4f8SNickeau        'lavenderblush' => '#FFF0F5',
117*4cadd4f8SNickeau        'lawngreen' => '#7CFC00',
118*4cadd4f8SNickeau        'lemonchiffon' => '#FFFACD',
119*4cadd4f8SNickeau        'lightblue' => '#ADD8E6',
120*4cadd4f8SNickeau        'lightcoral' => '#F08080',
121*4cadd4f8SNickeau        'lightcyan' => '#E0FFFF',
122*4cadd4f8SNickeau        'lightgoldenrodyellow' => '#FAFAD2',
123*4cadd4f8SNickeau        'lightgray' => '#D3D3D3',
124*4cadd4f8SNickeau        'lightgreen' => '#90EE90',
125*4cadd4f8SNickeau        'lightgrey' => '#D3D3D3',
126*4cadd4f8SNickeau        'lightpink' => '#FFB6C1',
127*4cadd4f8SNickeau        'lightsalmon' => '#FFA07A',
128*4cadd4f8SNickeau        'lightseagreen' => '#20B2AA',
129*4cadd4f8SNickeau        'lightskyblue' => '#87CEFA',
130*4cadd4f8SNickeau        'lightslategray' => '#778899',
131*4cadd4f8SNickeau        'lightslategrey' => '#778899',
132*4cadd4f8SNickeau        'lightsteelblue' => '#B0C4DE',
133*4cadd4f8SNickeau        'lightyellow' => '#FFFFE0',
134*4cadd4f8SNickeau        'lime' => '#00FF00',
135*4cadd4f8SNickeau        'limegreen' => '#32CD32',
136*4cadd4f8SNickeau        'linen' => '#FAF0E6',
137*4cadd4f8SNickeau        'magenta' => '#FF00FF',
138*4cadd4f8SNickeau        'maroon' => '#800000',
139*4cadd4f8SNickeau        'mediumaquamarine' => '#66CDAA',
140*4cadd4f8SNickeau        'mediumblue' => '#0000CD',
141*4cadd4f8SNickeau        'mediumorchid' => '#BA55D3',
142*4cadd4f8SNickeau        'mediumpurple' => '#9370DB',
143*4cadd4f8SNickeau        'mediumseagreen' => '#3CB371',
144*4cadd4f8SNickeau        'mediumslateblue' => '#7B68EE',
145*4cadd4f8SNickeau        'mediumspringgreen' => '#00FA9A',
146*4cadd4f8SNickeau        'mediumturquoise' => '#48D1CC',
147*4cadd4f8SNickeau        'mediumvioletred' => '#C71585',
148*4cadd4f8SNickeau        'midnightblue' => '#191970',
149*4cadd4f8SNickeau        'mintcream' => '#F5FFFA',
150*4cadd4f8SNickeau        'mistyrose' => '#FFE4E1',
151*4cadd4f8SNickeau        'moccasin' => '#FFE4B5',
152*4cadd4f8SNickeau        'navajowhite' => '#FFDEAD',
153*4cadd4f8SNickeau        'navy' => '#000080',
154*4cadd4f8SNickeau        'oldlace' => '#FDF5E6',
155*4cadd4f8SNickeau        'olive' => '#808000',
156*4cadd4f8SNickeau        'olivedrab' => '#6B8E23',
157*4cadd4f8SNickeau        'orange' => '#FFA500',
158*4cadd4f8SNickeau        'orangered' => '#FF4500',
159*4cadd4f8SNickeau        'orchid' => '#DA70D6',
160*4cadd4f8SNickeau        'palegoldenrod' => '#EEE8AA',
161*4cadd4f8SNickeau        'palegreen' => '#98FB98',
162*4cadd4f8SNickeau        'paleturquoise' => '#AFEEEE',
163*4cadd4f8SNickeau        'palevioletred' => '#DB7093',
164*4cadd4f8SNickeau        'papayawhip' => '#FFEFD5',
165*4cadd4f8SNickeau        'peachpuff' => '#FFDAB9',
166*4cadd4f8SNickeau        'peru' => '#CD853F',
167*4cadd4f8SNickeau        'pink' => '#FFC0CB',
168*4cadd4f8SNickeau        'plum' => '#DDA0DD',
169*4cadd4f8SNickeau        'powderblue' => '#B0E0E6',
170*4cadd4f8SNickeau        'purple' => '#800080',
171*4cadd4f8SNickeau        'rebeccapurple' => '#663399',
172*4cadd4f8SNickeau        'red' => '#FF0000',
173*4cadd4f8SNickeau        'rosybrown' => '#BC8F8F',
174*4cadd4f8SNickeau        'royalblue' => '#4169E1',
175*4cadd4f8SNickeau        'saddlebrown' => '#8B4513',
176*4cadd4f8SNickeau        'salmon' => '#FA8072',
177*4cadd4f8SNickeau        'sandybrown' => '#F4A460',
178*4cadd4f8SNickeau        'seagreen' => '#2E8B57',
179*4cadd4f8SNickeau        'seashell' => '#FFF5EE',
180*4cadd4f8SNickeau        'sienna' => '#A0522D',
181*4cadd4f8SNickeau        'silver' => '#C0C0C0',
182*4cadd4f8SNickeau        'skyblue' => '#87CEEB',
183*4cadd4f8SNickeau        'slateblue' => '#6A5ACD',
184*4cadd4f8SNickeau        'slategray' => '#708090',
185*4cadd4f8SNickeau        'slategrey' => '#708090',
186*4cadd4f8SNickeau        'snow' => '#FFFAFA',
187*4cadd4f8SNickeau        'springgreen' => '#00FF7F',
188*4cadd4f8SNickeau        'steelblue' => '#4682B4',
189*4cadd4f8SNickeau        'tan' => '#D2B48C',
190*4cadd4f8SNickeau        'teal' => '#008080',
191*4cadd4f8SNickeau        'tip' => self::TIP_COLOR,
192*4cadd4f8SNickeau        'thistle' => '#D8BFD8',
193*4cadd4f8SNickeau        'tomato' => '#FF6347',
194*4cadd4f8SNickeau        'turquoise' => '#40E0D0',
195*4cadd4f8SNickeau        'violet' => '#EE82EE',
196*4cadd4f8SNickeau        'wheat' => '#F5DEB3',
197*4cadd4f8SNickeau        'white' => '#FFFFFF',
198*4cadd4f8SNickeau        'whitesmoke' => '#F5F5F5',
199*4cadd4f8SNickeau        'yellow' => '#FFFF00',
200*4cadd4f8SNickeau        'yellowgreen' => '#9ACD32'
201*4cadd4f8SNickeau    );
202*4cadd4f8SNickeau
203*4cadd4f8SNickeau    /**
204*4cadd4f8SNickeau     * Branding colors
205*4cadd4f8SNickeau     */
206*4cadd4f8SNickeau    const PRIMARY_VALUE = "primary";
207*4cadd4f8SNickeau    const SECONDARY_VALUE = "secondary";
208*4cadd4f8SNickeau
209*4cadd4f8SNickeau    const PRIMARY_COLOR_CONF = "primaryColor";
210*4cadd4f8SNickeau    const SECONDARY_COLOR_CONF = "secondaryColor";
211*4cadd4f8SNickeau    const BRANDING_COLOR_CANONICAL = "branding-colors";
212*4cadd4f8SNickeau    public const BACKGROUND_COLOR = "background-color";
213*4cadd4f8SNickeau
214*4cadd4f8SNickeau    // the value is a bootstrap name
215*4cadd4f8SNickeau    const VALUE_TYPE_BOOTSTRAP_NAME = "bootstrap";
216*4cadd4f8SNickeau    const VALUE_TYPE_RGB_HEX = "rgb-hex";
217*4cadd4f8SNickeau    const VALUE_TYPE_RGB_ARRAY = "rgb-array";
218*4cadd4f8SNickeau    const VALUE_TYPE_RESET = "reset";
219*4cadd4f8SNickeau    const VALUE_TYPE_CSS_NAME = "css-name";
220*4cadd4f8SNickeau    const VALUE_TYPE_UNKNOWN_NAME = "unknown-name";
221*4cadd4f8SNickeau
222*4cadd4f8SNickeau    /**
223*4cadd4f8SNickeau     * Do we set also the branding color on
224*4cadd4f8SNickeau     * other elements ?
225*4cadd4f8SNickeau     */
226*4cadd4f8SNickeau    const BRANDING_COLOR_INHERITANCE_ENABLE_CONF = "brandingColorInheritanceEnable";
227*4cadd4f8SNickeau    const BRANDING_COLOR_INHERITANCE_ENABLE_CONF_DEFAULT = 1;
228*4cadd4f8SNickeau
229*4cadd4f8SNickeau    /**
230*4cadd4f8SNickeau     * Minimum recommended ratio by the w3c
231*4cadd4f8SNickeau     */
232*4cadd4f8SNickeau    const MINIMUM_CONTRAST_RATIO = 5;
233*4cadd4f8SNickeau    const WHITE = "white";
234*4cadd4f8SNickeau    const TIP_COLOR = "#ffee33";
235*4cadd4f8SNickeau    const CURRENT_COLOR = "currentColor";
236*4cadd4f8SNickeau
237*4cadd4f8SNickeau    /**
238*4cadd4f8SNickeau     * @var array
239*4cadd4f8SNickeau     */
240*4cadd4f8SNickeau    private static $dokuWikiStyles;
241*4cadd4f8SNickeau
242*4cadd4f8SNickeau    /**
243*4cadd4f8SNickeau     * @var int
244*4cadd4f8SNickeau     */
245*4cadd4f8SNickeau    private $red;
246*4cadd4f8SNickeau    /**
247*4cadd4f8SNickeau     * @var mixed
248*4cadd4f8SNickeau     */
249*4cadd4f8SNickeau    private $green;
250*4cadd4f8SNickeau    /**
251*4cadd4f8SNickeau     * @var mixed
252*4cadd4f8SNickeau     */
253*4cadd4f8SNickeau    private $blue;
254*4cadd4f8SNickeau    /**
255*4cadd4f8SNickeau     * @var string
256*4cadd4f8SNickeau     */
257*4cadd4f8SNickeau    private $nameType = self::VALUE_TYPE_UNKNOWN_NAME;
258*4cadd4f8SNickeau    /**
259*4cadd4f8SNickeau     * The color name
260*4cadd4f8SNickeau     * It can be:
261*4cadd4f8SNickeau     *   * a bootstrap
262*4cadd4f8SNickeau     *   * a css name
263*4cadd4f8SNickeau     *   * or `reset`
264*4cadd4f8SNickeau     * @var null|string
265*4cadd4f8SNickeau     */
266*4cadd4f8SNickeau    private $name;
267*4cadd4f8SNickeau    private $transparency;
268*4cadd4f8SNickeau
269*4cadd4f8SNickeau
270*4cadd4f8SNickeau    /**
271*4cadd4f8SNickeau     * The styles of the dokuwiki systems
272*4cadd4f8SNickeau     * @return array
273*4cadd4f8SNickeau     */
274*4cadd4f8SNickeau    public static function getDokuWikiStyles(): array
275*4cadd4f8SNickeau    {
276*4cadd4f8SNickeau        if (self::$dokuWikiStyles === null) {
277*4cadd4f8SNickeau            self::$dokuWikiStyles = (new StyleUtils())->cssStyleini();
278*4cadd4f8SNickeau        }
279*4cadd4f8SNickeau        return self::$dokuWikiStyles;
280*4cadd4f8SNickeau
281*4cadd4f8SNickeau    }
282*4cadd4f8SNickeau
283*4cadd4f8SNickeau    /**
284*4cadd4f8SNickeau     * Same round instructions than SCSS to be able to do the test
285*4cadd4f8SNickeau     * have value as bootstrap
286*4cadd4f8SNickeau     * @param float $value
287*4cadd4f8SNickeau     * @return float
288*4cadd4f8SNickeau     */
289*4cadd4f8SNickeau    private static function round(float $value): float
290*4cadd4f8SNickeau    {
291*4cadd4f8SNickeau        $rest = fmod($value, 1);
292*4cadd4f8SNickeau        if ($rest < 0.5) {
293*4cadd4f8SNickeau            return round($value, 0, PHP_ROUND_HALF_DOWN);
294*4cadd4f8SNickeau        } else {
295*4cadd4f8SNickeau            return round($value, 0, PHP_ROUND_HALF_UP);
296*4cadd4f8SNickeau        }
297*4cadd4f8SNickeau    }
298*4cadd4f8SNickeau
299*4cadd4f8SNickeau    /**
300*4cadd4f8SNickeau     * @throws ExceptionCombo
301*4cadd4f8SNickeau     */
302*4cadd4f8SNickeau    public static function createFromRgbChannels(int $red, int $green, int $blue): ColorRgb
303*4cadd4f8SNickeau    {
304*4cadd4f8SNickeau        return (new ColorRgb())
305*4cadd4f8SNickeau            ->setRgbChannels([$red, $green, $blue]);
306*4cadd4f8SNickeau    }
307*4cadd4f8SNickeau
308*4cadd4f8SNickeau    /**
309*4cadd4f8SNickeau     * Utility function to get white
310*4cadd4f8SNickeau     * @throws ExceptionCombo
311*4cadd4f8SNickeau     */
312*4cadd4f8SNickeau    public static function getWhite(): ColorRgb
313*4cadd4f8SNickeau    {
314*4cadd4f8SNickeau
315*4cadd4f8SNickeau        return (new ColorRgb())
316*4cadd4f8SNickeau            ->setName("white")
317*4cadd4f8SNickeau            ->setRgbChannels([255, 255, 255])
318*4cadd4f8SNickeau            ->setNameType(self::VALUE_TYPE_CSS_NAME);
319*4cadd4f8SNickeau
320*4cadd4f8SNickeau    }
321*4cadd4f8SNickeau
322*4cadd4f8SNickeau    /**
323*4cadd4f8SNickeau     * Utility function to get black
324*4cadd4f8SNickeau     * @throws ExceptionCombo
325*4cadd4f8SNickeau     */
326*4cadd4f8SNickeau    public static function getBlack(): ColorRgb
327*4cadd4f8SNickeau    {
328*4cadd4f8SNickeau
329*4cadd4f8SNickeau        return (new ColorRgb())
330*4cadd4f8SNickeau            ->setName("black")
331*4cadd4f8SNickeau            ->setRgbChannels([0, 0, 0])
332*4cadd4f8SNickeau            ->setNameType(self::VALUE_TYPE_CSS_NAME);
333*4cadd4f8SNickeau
334*4cadd4f8SNickeau    }
335*4cadd4f8SNickeau
336*4cadd4f8SNickeau    /**
337*4cadd4f8SNickeau     * @throws ExceptionCombo
338*4cadd4f8SNickeau     */
339*4cadd4f8SNickeau    public static function createFromHex(string $color)
340*4cadd4f8SNickeau    {
341*4cadd4f8SNickeau
342*4cadd4f8SNickeau        return (new ColorRgb())
343*4cadd4f8SNickeau            ->setHex($color);
344*4cadd4f8SNickeau
345*4cadd4f8SNickeau
346*4cadd4f8SNickeau    }
347*4cadd4f8SNickeau
348*4cadd4f8SNickeau
349*4cadd4f8SNickeau    /**
350*4cadd4f8SNickeau     * @return ColorHsl
351*4cadd4f8SNickeau     * @throws ExceptionCombo
352*4cadd4f8SNickeau     */
353*4cadd4f8SNickeau    public function toHsl(): ColorHsl
354*4cadd4f8SNickeau    {
355*4cadd4f8SNickeau
356*4cadd4f8SNickeau        if ($this->red === null) {
357*4cadd4f8SNickeau            throw new ExceptionCombo("This color ($this) does not have any channel known, we can't transform it to hsl");
358*4cadd4f8SNickeau        }
359*4cadd4f8SNickeau        $red = $this->red / 255;
360*4cadd4f8SNickeau        $green = $this->green / 255;
361*4cadd4f8SNickeau        $blue = $this->blue / 255;
362*4cadd4f8SNickeau
363*4cadd4f8SNickeau        $max = max($red, $green, $blue);
364*4cadd4f8SNickeau        $min = min($red, $green, $blue);
365*4cadd4f8SNickeau
366*4cadd4f8SNickeau
367*4cadd4f8SNickeau        $lightness = ($max + $min) / 2;
368*4cadd4f8SNickeau        $d = $max - $min;
369*4cadd4f8SNickeau
370*4cadd4f8SNickeau        if ($d == 0) {
371*4cadd4f8SNickeau            $hue = $saturation = 0; // achromatic
372*4cadd4f8SNickeau        } else {
373*4cadd4f8SNickeau            $saturation = $d / (1 - abs(2 * $lightness - 1));
374*4cadd4f8SNickeau
375*4cadd4f8SNickeau            switch ($max) {
376*4cadd4f8SNickeau                case $red:
377*4cadd4f8SNickeau                    $hue = 60 * fmod((($green - $blue) / $d), 6);
378*4cadd4f8SNickeau                    if ($blue > $green) {
379*4cadd4f8SNickeau                        $hue += 360;
380*4cadd4f8SNickeau                    }
381*4cadd4f8SNickeau                    break;
382*4cadd4f8SNickeau
383*4cadd4f8SNickeau                case $green:
384*4cadd4f8SNickeau                    $hue = 60 * (($blue - $red) / $d + 2);
385*4cadd4f8SNickeau                    break;
386*4cadd4f8SNickeau
387*4cadd4f8SNickeau                default:
388*4cadd4f8SNickeau                case $blue:
389*4cadd4f8SNickeau                    $hue = 60 * (($red - $green) / $d + 4);
390*4cadd4f8SNickeau                    break;
391*4cadd4f8SNickeau
392*4cadd4f8SNickeau            }
393*4cadd4f8SNickeau        }
394*4cadd4f8SNickeau
395*4cadd4f8SNickeau        /**
396*4cadd4f8SNickeau         * No round to get a neat inverse
397*4cadd4f8SNickeau         */
398*4cadd4f8SNickeau
399*4cadd4f8SNickeau        return ColorHsl::createFromChannels($hue, $saturation * 100, $lightness * 100);
400*4cadd4f8SNickeau
401*4cadd4f8SNickeau
402*4cadd4f8SNickeau    }
403*4cadd4f8SNickeau
404*4cadd4f8SNickeau
405*4cadd4f8SNickeau    /**
406*4cadd4f8SNickeau     * @param array|string|ColorRgb $color
407*4cadd4f8SNickeau     * @param int|null $weight
408*4cadd4f8SNickeau     * @return ColorRgb
409*4cadd4f8SNickeau     *
410*4cadd4f8SNickeau     *
411*4cadd4f8SNickeau     * Because Bootstrap uses the mix function of SCSS
412*4cadd4f8SNickeau     * https://sass-lang.com/documentation/modules/color#mix
413*4cadd4f8SNickeau     * We try to be as clause as possible
414*4cadd4f8SNickeau     *
415*4cadd4f8SNickeau     * https://gist.github.com/jedfoster/7939513
416*4cadd4f8SNickeau     *
417*4cadd4f8SNickeau     * This is a linear extrapolation along the segment
418*4cadd4f8SNickeau     * @throws ExceptionCombo
419*4cadd4f8SNickeau     */
420*4cadd4f8SNickeau    function mix($color, ?int $weight = 50): ColorRgb
421*4cadd4f8SNickeau    {
422*4cadd4f8SNickeau        if ($weight === null) {
423*4cadd4f8SNickeau            $weight = 50;
424*4cadd4f8SNickeau        }
425*4cadd4f8SNickeau
426*4cadd4f8SNickeau        $color2 = ColorRgb::createFromString($color);
427*4cadd4f8SNickeau        $targetRed = self::round(Math::lerp($color2->getRed(), $this->getRed(), $weight));
428*4cadd4f8SNickeau        $targetGreen = self::round(Math::lerp($color2->getGreen(), $this->getGreen(), $weight));
429*4cadd4f8SNickeau        $targetBlue = self::round(Math::lerp($color2->getBlue(), $this->getBlue(), $weight));
430*4cadd4f8SNickeau        return ColorRgb::createFromRgbChannels($targetRed, $targetGreen, $targetBlue);
431*4cadd4f8SNickeau
432*4cadd4f8SNickeau    }
433*4cadd4f8SNickeau
434*4cadd4f8SNickeau    /**
435*4cadd4f8SNickeau     * @throws ExceptionCombo
436*4cadd4f8SNickeau     */
437*4cadd4f8SNickeau    function unmix($color, ?int $weight = 50): ColorRgb
438*4cadd4f8SNickeau    {
439*4cadd4f8SNickeau        if ($weight === null) {
440*4cadd4f8SNickeau            $weight = 50;
441*4cadd4f8SNickeau        }
442*4cadd4f8SNickeau
443*4cadd4f8SNickeau        $color2 = ColorRgb::createFromString($color);
444*4cadd4f8SNickeau        $targetRed = self::round(Math::unlerp($color2->getRed(), $this->getRed(), $weight));
445*4cadd4f8SNickeau        if ($targetRed < 0) {
446*4cadd4f8SNickeau            throw new ExceptionCombo("This is not possible, the red value ({$color2->getBlue()}) with the percentage $weight could not be unmixed. They were not calculated with color mixing.");
447*4cadd4f8SNickeau        }
448*4cadd4f8SNickeau        $targetGreen = self::round(Math::unlerp($color2->getGreen(), $this->getGreen(), $weight));
449*4cadd4f8SNickeau        if ($targetGreen < 0) {
450*4cadd4f8SNickeau            throw new ExceptionCombo("This is not possible, the green value ({$color2->getGreen()}) with the percentage $weight could not be unmixed. They were not calculated with color mixing.");
451*4cadd4f8SNickeau        }
452*4cadd4f8SNickeau        $targetBlue = self::round(Math::unlerp($color2->getBlue(), $this->getBlue(), $weight));
453*4cadd4f8SNickeau        if ($targetBlue < 0) {
454*4cadd4f8SNickeau            throw new ExceptionCombo("This is not possible, the blue value ({$color2->getBlue()}) with the percentage $weight could not be unmixed. They were not calculated with color mixing.");
455*4cadd4f8SNickeau        }
456*4cadd4f8SNickeau        return ColorRgb::createFromRgbChannels($targetRed, $targetGreen, $targetBlue);
457*4cadd4f8SNickeau
458*4cadd4f8SNickeau    }
459*4cadd4f8SNickeau
460*4cadd4f8SNickeau    /**
461*4cadd4f8SNickeau     * Takes an hexadecimal color and returns the rgb channels
462*4cadd4f8SNickeau     *
463*4cadd4f8SNickeau     * @param mixed $hex
464*4cadd4f8SNickeau     *
465*4cadd4f8SNickeau     * @throws ExceptionCombo
466*4cadd4f8SNickeau     */
467*4cadd4f8SNickeau    function hex2rgb($hex = '#000000'): array
468*4cadd4f8SNickeau    {
469*4cadd4f8SNickeau        if ($hex[0] !== "#") {
470*4cadd4f8SNickeau            throw new ExceptionCombo("The color value ($hex) does not start with a #, this is not valid CSS hexadecimal color value");
471*4cadd4f8SNickeau        }
472*4cadd4f8SNickeau        $digits = str_replace("#", "", $hex);
473*4cadd4f8SNickeau        $hexLen = strlen($digits);
474*4cadd4f8SNickeau        $transparency = false;
475*4cadd4f8SNickeau        switch ($hexLen) {
476*4cadd4f8SNickeau            case 3:
477*4cadd4f8SNickeau                $lengthColorHex = 1;
478*4cadd4f8SNickeau                break;
479*4cadd4f8SNickeau            case 6:
480*4cadd4f8SNickeau                $lengthColorHex = 2;
481*4cadd4f8SNickeau                break;
482*4cadd4f8SNickeau            case 8:
483*4cadd4f8SNickeau                $lengthColorHex = 2;
484*4cadd4f8SNickeau                $transparency = true;
485*4cadd4f8SNickeau                break;
486*4cadd4f8SNickeau            default:
487*4cadd4f8SNickeau                throw new ExceptionCombo("The digit color value ($hex) is not 3 or 6 in length, this is not a valid CSS hexadecimal color value");
488*4cadd4f8SNickeau        }
489*4cadd4f8SNickeau        $result = preg_match("/[0-9a-f]{3,8}/i", $digits);
490*4cadd4f8SNickeau        if ($result !== 1) {
491*4cadd4f8SNickeau            throw new ExceptionCombo("The digit color value ($hex) is not a hexadecimal value, this is not a valid CSS hexadecimal color value");
492*4cadd4f8SNickeau        }
493*4cadd4f8SNickeau        $channelHexs = str_split($digits, $lengthColorHex);
494*4cadd4f8SNickeau        $rgbDec = [];
495*4cadd4f8SNickeau        foreach ($channelHexs as $channelHex) {
496*4cadd4f8SNickeau            if ($lengthColorHex === 1) {
497*4cadd4f8SNickeau                $channelHex .= $channelHex;
498*4cadd4f8SNickeau            }
499*4cadd4f8SNickeau            $rgbDec[] = hexdec($channelHex);
500*4cadd4f8SNickeau        }
501*4cadd4f8SNickeau        if (!$transparency) {
502*4cadd4f8SNickeau            $rgbDec[] = null;
503*4cadd4f8SNickeau        }
504*4cadd4f8SNickeau        return $rgbDec;
505*4cadd4f8SNickeau    }
506*4cadd4f8SNickeau
507*4cadd4f8SNickeau    /**
508*4cadd4f8SNickeau     * rgb2hex
509*4cadd4f8SNickeau     *
510*4cadd4f8SNickeau     * @return string
511*4cadd4f8SNickeau     */
512*4cadd4f8SNickeau    function toRgbHex(): string
513*4cadd4f8SNickeau    {
514*4cadd4f8SNickeau
515*4cadd4f8SNickeau        switch ($this->nameType) {
516*4cadd4f8SNickeau            case self::VALUE_TYPE_CSS_NAME:
517*4cadd4f8SNickeau                return strtolower(self::CSS_COLOR_NAMES[$this->name]);
518*4cadd4f8SNickeau            default:
519*4cadd4f8SNickeau                $toCssHex = function ($x) {
520*4cadd4f8SNickeau                    return str_pad(dechex($x), 2, "0", STR_PAD_LEFT);
521*4cadd4f8SNickeau                };
522*4cadd4f8SNickeau                $redHex = $toCssHex($this->getRed());
523*4cadd4f8SNickeau                $greenHex = $toCssHex($this->getGreen());
524*4cadd4f8SNickeau                $blueHex = $toCssHex($this->getBlue());
525*4cadd4f8SNickeau                $withoutAlpha = "#" . $redHex . $greenHex . $blueHex;
526*4cadd4f8SNickeau                if ($this->transparency === null) {
527*4cadd4f8SNickeau                    return $withoutAlpha;
528*4cadd4f8SNickeau                }
529*4cadd4f8SNickeau                return $withoutAlpha . $toCssHex($this->getTransparency());
530*4cadd4f8SNickeau        }
531*4cadd4f8SNickeau
532*4cadd4f8SNickeau    }
533*4cadd4f8SNickeau
534*4cadd4f8SNickeau    /**
535*4cadd4f8SNickeau     * @throws ExceptionCombo
536*4cadd4f8SNickeau     */
537*4cadd4f8SNickeau    public
538*4cadd4f8SNickeau    static function createFromString(string $color): ColorRgb
539*4cadd4f8SNickeau    {
540*4cadd4f8SNickeau        if ($color[0] === "#") {
541*4cadd4f8SNickeau            return self::createFromHex($color);
542*4cadd4f8SNickeau        } else {
543*4cadd4f8SNickeau            return self::createFromName($color);
544*4cadd4f8SNickeau        }
545*4cadd4f8SNickeau    }
546*4cadd4f8SNickeau
547*4cadd4f8SNickeau    /**
548*4cadd4f8SNickeau     * @throws ExceptionCombo
549*4cadd4f8SNickeau     */
550*4cadd4f8SNickeau    public
551*4cadd4f8SNickeau    static function createFromName(string $color): ColorRgb
552*4cadd4f8SNickeau    {
553*4cadd4f8SNickeau        return (new ColorRgb())
554*4cadd4f8SNickeau            ->setName($color);
555*4cadd4f8SNickeau    }
556*4cadd4f8SNickeau
557*4cadd4f8SNickeau
558*4cadd4f8SNickeau    public
559*4cadd4f8SNickeau    function toCssValue(): string
560*4cadd4f8SNickeau    {
561*4cadd4f8SNickeau
562*4cadd4f8SNickeau        switch ($this->nameType) {
563*4cadd4f8SNickeau            case self::VALUE_TYPE_RGB_ARRAY:
564*4cadd4f8SNickeau                return $this->toRgbHex();
565*4cadd4f8SNickeau            case self::VALUE_TYPE_CSS_NAME:
566*4cadd4f8SNickeau            case self::VALUE_TYPE_RGB_HEX;
567*4cadd4f8SNickeau                return $this->name;
568*4cadd4f8SNickeau            case self::VALUE_TYPE_BOOTSTRAP_NAME:
569*4cadd4f8SNickeau                $bootstrapVersion = Bootstrap::getBootStrapMajorVersion();
570*4cadd4f8SNickeau                switch ($bootstrapVersion) {
571*4cadd4f8SNickeau                    case Bootstrap::BootStrapFiveMajorVersion:
572*4cadd4f8SNickeau                        $colorValue = "bs-" . $this->name;
573*4cadd4f8SNickeau                        break;
574*4cadd4f8SNickeau                    default:
575*4cadd4f8SNickeau                        $colorValue = $this->name;
576*4cadd4f8SNickeau                        break;
577*4cadd4f8SNickeau                }
578*4cadd4f8SNickeau                return "var(--" . $colorValue . ")";
579*4cadd4f8SNickeau            case self::VALUE_TYPE_RESET:
580*4cadd4f8SNickeau                return "inherit!important";
581*4cadd4f8SNickeau            default:
582*4cadd4f8SNickeau                // unknown color name
583*4cadd4f8SNickeau                if ($this->name === null) {
584*4cadd4f8SNickeau                    LogUtility::msg("The name should not be null");
585*4cadd4f8SNickeau                    return "black";
586*4cadd4f8SNickeau                }
587*4cadd4f8SNickeau                return $this->name;
588*4cadd4f8SNickeau        }
589*4cadd4f8SNickeau
590*4cadd4f8SNickeau
591*4cadd4f8SNickeau    }
592*4cadd4f8SNickeau
593*4cadd4f8SNickeau    public
594*4cadd4f8SNickeau    function getRed()
595*4cadd4f8SNickeau    {
596*4cadd4f8SNickeau        return $this->red;
597*4cadd4f8SNickeau    }
598*4cadd4f8SNickeau
599*4cadd4f8SNickeau    public
600*4cadd4f8SNickeau    function getGreen()
601*4cadd4f8SNickeau    {
602*4cadd4f8SNickeau        return $this->green;
603*4cadd4f8SNickeau    }
604*4cadd4f8SNickeau
605*4cadd4f8SNickeau    public
606*4cadd4f8SNickeau    function getBlue()
607*4cadd4f8SNickeau    {
608*4cadd4f8SNickeau        return $this->blue;
609*4cadd4f8SNickeau    }
610*4cadd4f8SNickeau
611*4cadd4f8SNickeau    /**
612*4cadd4f8SNickeau     * Mix with black
613*4cadd4f8SNickeau     * @var int $percentage between 0 and 100
614*4cadd4f8SNickeau     */
615*4cadd4f8SNickeau    public
616*4cadd4f8SNickeau    function shade(int $percentage): ColorRgb
617*4cadd4f8SNickeau    {
618*4cadd4f8SNickeau        try {
619*4cadd4f8SNickeau            return $this->mix('black', $percentage);
620*4cadd4f8SNickeau        } catch (ExceptionCombo $e) {
621*4cadd4f8SNickeau            // should not happen
622*4cadd4f8SNickeau            LogUtility::msg("Error while shading. Error: {$e->getMessage()}");
623*4cadd4f8SNickeau            return $this;
624*4cadd4f8SNickeau        }
625*4cadd4f8SNickeau    }
626*4cadd4f8SNickeau
627*4cadd4f8SNickeau    public
628*4cadd4f8SNickeau    function getNameType(): string
629*4cadd4f8SNickeau    {
630*4cadd4f8SNickeau        return $this->nameType;
631*4cadd4f8SNickeau    }
632*4cadd4f8SNickeau
633*4cadd4f8SNickeau    /**
634*4cadd4f8SNickeau     * @param int $percentage between -100 and 100
635*4cadd4f8SNickeau     * @return $this
636*4cadd4f8SNickeau     */
637*4cadd4f8SNickeau    public
638*4cadd4f8SNickeau    function scale(int $percentage): ColorRgb
639*4cadd4f8SNickeau    {
640*4cadd4f8SNickeau        if ($percentage === 0) {
641*4cadd4f8SNickeau            return $this;
642*4cadd4f8SNickeau        }
643*4cadd4f8SNickeau        if ($percentage > 0) {
644*4cadd4f8SNickeau            return $this->shade($percentage);
645*4cadd4f8SNickeau        } else {
646*4cadd4f8SNickeau            return $this->tint(abs($percentage));
647*4cadd4f8SNickeau        }
648*4cadd4f8SNickeau
649*4cadd4f8SNickeau    }
650*4cadd4f8SNickeau
651*4cadd4f8SNickeau
652*4cadd4f8SNickeau    public
653*4cadd4f8SNickeau    function toRgbChannels(): array
654*4cadd4f8SNickeau    {
655*4cadd4f8SNickeau        return [$this->getRed(), $this->getGreen(), $this->getBlue()];
656*4cadd4f8SNickeau    }
657*4cadd4f8SNickeau
658*4cadd4f8SNickeau    /**
659*4cadd4f8SNickeau     * @param int $percentage between 0 and 100
660*4cadd4f8SNickeau     * @return $this
661*4cadd4f8SNickeau     */
662*4cadd4f8SNickeau    public
663*4cadd4f8SNickeau    function tint(int $percentage): ColorRgb
664*4cadd4f8SNickeau    {
665*4cadd4f8SNickeau        try {
666*4cadd4f8SNickeau            return $this->mix("white", $percentage);
667*4cadd4f8SNickeau        } catch (ExceptionCombo $e) {
668*4cadd4f8SNickeau            // should not happen
669*4cadd4f8SNickeau            LogUtility::msg("Error while tinting ($this) with a percentage ($percentage. Error: {$e->getMessage()}");
670*4cadd4f8SNickeau            return $this;
671*4cadd4f8SNickeau        }
672*4cadd4f8SNickeau    }
673*4cadd4f8SNickeau
674*4cadd4f8SNickeau    public
675*4cadd4f8SNickeau    function __toString()
676*4cadd4f8SNickeau    {
677*4cadd4f8SNickeau        return $this->toCssValue();
678*4cadd4f8SNickeau    }
679*4cadd4f8SNickeau
680*4cadd4f8SNickeau    public
681*4cadd4f8SNickeau    function getLuminance(): float
682*4cadd4f8SNickeau    {
683*4cadd4f8SNickeau        $toLuminanceFactor = function ($channel) {
684*4cadd4f8SNickeau            $pigmentRatio = $channel / 255;
685*4cadd4f8SNickeau            return $pigmentRatio <= 0.03928 ? $pigmentRatio / 12.92 : pow(($pigmentRatio + 0.055) / 1.055, 2.4);
686*4cadd4f8SNickeau        };
687*4cadd4f8SNickeau        $R = $toLuminanceFactor($this->getRed());
688*4cadd4f8SNickeau        $G = $toLuminanceFactor($this->getGreen());
689*4cadd4f8SNickeau        $B = $toLuminanceFactor($this->getBlue());
690*4cadd4f8SNickeau        return $R * 0.2126 + $G * 0.7152 + $B * 0.0722;
691*4cadd4f8SNickeau
692*4cadd4f8SNickeau    }
693*4cadd4f8SNickeau
694*4cadd4f8SNickeau    /**
695*4cadd4f8SNickeau     * The ratio that returns the chrome browser
696*4cadd4f8SNickeau     * @param ColorRgb $colorRgb
697*4cadd4f8SNickeau     * @return float
698*4cadd4f8SNickeau     * @throws ExceptionCombo
699*4cadd4f8SNickeau     */
700*4cadd4f8SNickeau    public
701*4cadd4f8SNickeau    function getContrastRatio(ColorRgb $colorRgb): float
702*4cadd4f8SNickeau    {
703*4cadd4f8SNickeau        $actualColorHsl = $this->toHsl();
704*4cadd4f8SNickeau        $actualLightness = $actualColorHsl->getLightness();
705*4cadd4f8SNickeau        $targetColorHsl = $colorRgb->toHsl();
706*4cadd4f8SNickeau        $targetLightNess = $targetColorHsl->getLightness();
707*4cadd4f8SNickeau        if ($actualLightness > $targetLightNess) {
708*4cadd4f8SNickeau            $lighter = $this;
709*4cadd4f8SNickeau            $darker = $colorRgb;
710*4cadd4f8SNickeau        } else {
711*4cadd4f8SNickeau            $lighter = $colorRgb;
712*4cadd4f8SNickeau            $darker = $this;
713*4cadd4f8SNickeau        }
714*4cadd4f8SNickeau        $ratio = ($lighter->getLuminance() + 0.05) / ($darker->getLuminance() + 0.05);
715*4cadd4f8SNickeau        return floor($ratio * 100) / 100;
716*4cadd4f8SNickeau    }
717*4cadd4f8SNickeau
718*4cadd4f8SNickeau    /**
719*4cadd4f8SNickeau     * @throws ExceptionCombo
720*4cadd4f8SNickeau     */
721*4cadd4f8SNickeau    public
722*4cadd4f8SNickeau    function toMinimumContrastRatio(string $color, float $minimum = self::MINIMUM_CONTRAST_RATIO, $darknessIncrement = 5): ColorRgb
723*4cadd4f8SNickeau    {
724*4cadd4f8SNickeau        $targetColor = ColorRgb::createFromString($color);
725*4cadd4f8SNickeau        $ratio = $this->getContrastRatio($targetColor);
726*4cadd4f8SNickeau        $newColorRgb = $this;
727*4cadd4f8SNickeau        $newColorHsl = $this->toHsl();
728*4cadd4f8SNickeau        while ($ratio < $minimum) {
729*4cadd4f8SNickeau            $newColorHsl = $newColorHsl->darken($darknessIncrement);
730*4cadd4f8SNickeau            $newColorRgb = $newColorHsl->toRgb();
731*4cadd4f8SNickeau            if ($newColorHsl->getLightness() === 0) {
732*4cadd4f8SNickeau                break;
733*4cadd4f8SNickeau            }
734*4cadd4f8SNickeau            $ratio = $newColorRgb->getContrastRatio($targetColor);
735*4cadd4f8SNickeau        }
736*4cadd4f8SNickeau        return $newColorRgb;
737*4cadd4f8SNickeau    }
738*4cadd4f8SNickeau
739*4cadd4f8SNickeau    /**
740*4cadd4f8SNickeau     * Returns the complimentary color
741*4cadd4f8SNickeau     */
742*4cadd4f8SNickeau    public
743*4cadd4f8SNickeau    function complementary(): ColorRgb
744*4cadd4f8SNickeau    {
745*4cadd4f8SNickeau        try {
746*4cadd4f8SNickeau            return $this
747*4cadd4f8SNickeau                ->toHsl()
748*4cadd4f8SNickeau                ->toComplement()
749*4cadd4f8SNickeau                ->toRgb();
750*4cadd4f8SNickeau        } catch (ExceptionCombo $e) {
751*4cadd4f8SNickeau            LogUtility::msg("Error while getting the complementary color of ($this). Error: {$e->getMessage()}");
752*4cadd4f8SNickeau            return $this;
753*4cadd4f8SNickeau        }
754*4cadd4f8SNickeau
755*4cadd4f8SNickeau    }
756*4cadd4f8SNickeau
757*4cadd4f8SNickeau    public
758*4cadd4f8SNickeau    function getName(): string
759*4cadd4f8SNickeau    {
760*4cadd4f8SNickeau        $hexColor = $this->toRgbHex();
761*4cadd4f8SNickeau        if (in_array($hexColor, self::CSS_COLOR_NAMES)) {
762*4cadd4f8SNickeau            return self::CSS_COLOR_NAMES[$hexColor];
763*4cadd4f8SNickeau        }
764*4cadd4f8SNickeau        return $hexColor;
765*4cadd4f8SNickeau    }
766*4cadd4f8SNickeau
767*4cadd4f8SNickeau    /**
768*4cadd4f8SNickeau     * @throws ExceptionCombo
769*4cadd4f8SNickeau     */
770*4cadd4f8SNickeau    public
771*4cadd4f8SNickeau    function toMinimumContrastRatioAgainstWhite(float $minimumContrastRatio = self::MINIMUM_CONTRAST_RATIO, int $darknessIncrement = 5): ColorRgb
772*4cadd4f8SNickeau    {
773*4cadd4f8SNickeau        return $this->toMinimumContrastRatio(self::WHITE, $minimumContrastRatio, $darknessIncrement);
774*4cadd4f8SNickeau    }
775*4cadd4f8SNickeau
776*4cadd4f8SNickeau    /**
777*4cadd4f8SNickeau     * @throws ExceptionCombo
778*4cadd4f8SNickeau     */
779*4cadd4f8SNickeau    private
780*4cadd4f8SNickeau    function setHex(string $color): ColorRgb
781*4cadd4f8SNickeau    {
782*4cadd4f8SNickeau        // Hexadecimal
783*4cadd4f8SNickeau        if ($color[0] !== "#") {
784*4cadd4f8SNickeau            throw new ExceptionCombo("The value is not an hexadecimal color value ($color)");
785*4cadd4f8SNickeau        }
786*4cadd4f8SNickeau        [$this->red, $this->green, $this->blue, $this->transparency] = $this->hex2rgb($color);
787*4cadd4f8SNickeau        $this->nameType = self::VALUE_TYPE_RGB_HEX;
788*4cadd4f8SNickeau        $this->name = $color;
789*4cadd4f8SNickeau        return $this;
790*4cadd4f8SNickeau    }
791*4cadd4f8SNickeau
792*4cadd4f8SNickeau    /**
793*4cadd4f8SNickeau     * @throws ExceptionCombo
794*4cadd4f8SNickeau     */
795*4cadd4f8SNickeau    public
796*4cadd4f8SNickeau    function setRgbChannels(array $colorValue): ColorRgb
797*4cadd4f8SNickeau    {
798*4cadd4f8SNickeau        if (sizeof($colorValue) != 3) {
799*4cadd4f8SNickeau            throw new ExceptionCombo("A rgb color array should be of length 3");
800*4cadd4f8SNickeau        }
801*4cadd4f8SNickeau        foreach ($colorValue as $color) {
802*4cadd4f8SNickeau            try {
803*4cadd4f8SNickeau                $channel = DataType::toInteger($color);
804*4cadd4f8SNickeau            } catch (ExceptionCombo $e) {
805*4cadd4f8SNickeau                throw new ExceptionCombo("The rgb color $color is not an integer. Error: {$e->getMessage()}");
806*4cadd4f8SNickeau            }
807*4cadd4f8SNickeau            if ($channel < 0 and $channel > 255) {
808*4cadd4f8SNickeau                throw new ExceptionCombo("The rgb color $color is not between 0 and 255");
809*4cadd4f8SNickeau            }
810*4cadd4f8SNickeau        }
811*4cadd4f8SNickeau        [$this->red, $this->green, $this->blue] = $colorValue;
812*4cadd4f8SNickeau        $this->nameType = self::VALUE_TYPE_RGB_ARRAY;
813*4cadd4f8SNickeau        return $this;
814*4cadd4f8SNickeau    }
815*4cadd4f8SNickeau
816*4cadd4f8SNickeau    private
817*4cadd4f8SNickeau    function setNameType(string $type): ColorRgb
818*4cadd4f8SNickeau    {
819*4cadd4f8SNickeau        $this->nameType = $type;
820*4cadd4f8SNickeau        return $this;
821*4cadd4f8SNickeau    }
822*4cadd4f8SNickeau
823*4cadd4f8SNickeau    /**
824*4cadd4f8SNickeau     * Via a name
825*4cadd4f8SNickeau     * @throws ExceptionCombo
826*4cadd4f8SNickeau     */
827*4cadd4f8SNickeau    private
828*4cadd4f8SNickeau    function setName(string $name): ColorRgb
829*4cadd4f8SNickeau    {
830*4cadd4f8SNickeau
831*4cadd4f8SNickeau        $qualifiedName = strtolower($name);
832*4cadd4f8SNickeau        $this->name = $qualifiedName;
833*4cadd4f8SNickeau        if (in_array($qualifiedName, self::BOOTSTRAP_COLORS)) {
834*4cadd4f8SNickeau            /**
835*4cadd4f8SNickeau             * Branding colors overwrite
836*4cadd4f8SNickeau             */
837*4cadd4f8SNickeau            switch ($this->name) {
838*4cadd4f8SNickeau                case ColorRgb::PRIMARY_VALUE:
839*4cadd4f8SNickeau                    $primaryColor = Site::getPrimaryColorValue();
840*4cadd4f8SNickeau                    if ($primaryColor !== null) {
841*4cadd4f8SNickeau                        if ($primaryColor !== ColorRgb::PRIMARY_VALUE) {
842*4cadd4f8SNickeau                            return self::createFromString($primaryColor);
843*4cadd4f8SNickeau                        }
844*4cadd4f8SNickeau                        LogUtility::msg("The primary color cannot be set with the value primary. Default to bootstrap color.", self::BRANDING_COLOR_CANONICAL);
845*4cadd4f8SNickeau                    }
846*4cadd4f8SNickeau                    break;
847*4cadd4f8SNickeau                case ColorRgb::SECONDARY_VALUE:
848*4cadd4f8SNickeau                    $secondaryColor = Site::getSecondaryColorValue();
849*4cadd4f8SNickeau                    if ($secondaryColor !== null) {
850*4cadd4f8SNickeau                        if ($secondaryColor !== ColorRgb::SECONDARY_VALUE) {
851*4cadd4f8SNickeau                            return self::createFromString($secondaryColor);
852*4cadd4f8SNickeau                        }
853*4cadd4f8SNickeau                        LogUtility::msg("The secondary color cannot be set with the value secondary. Default to bootstrap color.", self::BRANDING_COLOR_CANONICAL);
854*4cadd4f8SNickeau                    }
855*4cadd4f8SNickeau                    break;
856*4cadd4f8SNickeau            }
857*4cadd4f8SNickeau
858*4cadd4f8SNickeau            return $this->setNameType(self::VALUE_TYPE_BOOTSTRAP_NAME);
859*4cadd4f8SNickeau        }
860*4cadd4f8SNickeau        if ($qualifiedName === self::VALUE_TYPE_RESET) {
861*4cadd4f8SNickeau            return $this->setNameType(self::VALUE_TYPE_RESET);
862*4cadd4f8SNickeau        }
863*4cadd4f8SNickeau        if (in_array($qualifiedName, array_keys(self::CSS_COLOR_NAMES))) {
864*4cadd4f8SNickeau            $this->setHex(self::CSS_COLOR_NAMES[$qualifiedName])
865*4cadd4f8SNickeau                ->setNameType(self::VALUE_TYPE_CSS_NAME);
866*4cadd4f8SNickeau            $this->name = $qualifiedName; // hex is a also a name, the previous setHex overwrite the name
867*4cadd4f8SNickeau            return $this;
868*4cadd4f8SNickeau        }
869*4cadd4f8SNickeau        LogUtility::msg("The color name ($name) is unknown");
870*4cadd4f8SNickeau        return $this;
871*4cadd4f8SNickeau
872*4cadd4f8SNickeau    }
873*4cadd4f8SNickeau
874*4cadd4f8SNickeau    public
875*4cadd4f8SNickeau    function getTransparency()
876*4cadd4f8SNickeau    {
877*4cadd4f8SNickeau        return $this->transparency;
878*4cadd4f8SNickeau    }
879*4cadd4f8SNickeau
880*4cadd4f8SNickeau
881*4cadd4f8SNickeau
882*4cadd4f8SNickeau
883*4cadd4f8SNickeau}
884