Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
57 / 57
100.00% covered (success)
100.00%
16 / 16
CRAP
100.00% covered (success)
100.00%
1 / 1
Oklch
100.00% covered (success)
100.00%
57 / 57
100.00% covered (success)
100.00%
16 / 16
35
100.00% covered (success)
100.00%
1 / 1
 __construct
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
2
 setL
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
3
 setC
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
3
 setH
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
3
 setAlpha
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
3
 getL
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getC
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getH
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getAlpha
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 hasAlpha
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 toOklab
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
1
 toRgb
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 toArray
100.00% covered (success)
100.00%
13 / 13
100.00% covered (success)
100.00%
1 / 1
4
 render
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
8
 __toString
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 channels
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2declare(strict_types=1);
3/**
4 * Pop PHP Framework (https://www.popphp.org/)
5 *
6 * @link       https://github.com/popphp/popphp-framework
7 * @author     Nick Sagona, III <nick@popphp.org>
8 * @copyright  Copyright (c) 2009-2026 Nick Sagona, III
9 * @license    https://www.popphp.org/license     New BSD License
10 */
11
12/**
13 * @namespace
14 */
15namespace Pop\Color\Color;
16
17use OutOfRangeException;
18
19/**
20 * Pop Color Oklch color class
21 *
22 * @category   Pop
23 * @package    Pop\Color
24 * @author     Nick Sagona, III <nick@popphp.org>
25 * @copyright  Copyright (c) 2009-2026 Nick Sagona, III
26 * @license    https://www.popphp.org/license     New BSD License
27 * @version    2.0.0
28 */
29class Oklch extends AbstractColor
30{
31
32    /**
33     * L value
34     * @var float
35     */
36    protected float $l = 0;
37
38    /**
39     * C value
40     * @var float
41     */
42    protected float $c = 0;
43
44    /**
45     * H value
46     * @var int
47     */
48    protected int $h = 0;
49
50    /**
51     * Alpha value
52     * @var ?float
53     */
54    protected ?float $alpha = null;
55
56    /**
57     * Constructor
58     *
59     * Instantiate the Oklch color object
60     *
61     * @param float|string      $l
62     * @param float|string      $c
63     * @param int|string        $h
64     * @param float|string|null $alpha
65     */
66    public function __construct(float|string $l, float|string $c, int|string $h, float|string|null $alpha = null)
67    {
68        $this->setL($l);
69        $this->setC($c);
70        $this->setH($h);
71        if ($alpha !== null) {
72            $this->setAlpha($alpha);
73        }
74    }
75
76    /**
77     * Set L value
78     *
79     * @param  float|string $l
80     * @throws OutOfRangeException
81     * @return self
82     */
83    public function setL(float|string $l): self
84    {
85        $l = (float)$l;
86        if (($l > 1) || ($l < 0)) {
87            throw new OutOfRangeException('Error: The value of $l must be between 0 and 1.');
88        }
89        $this->l = $l;
90        return $this;
91    }
92
93    /**
94     * Set C value
95     *
96     * @param  float|string $c
97     * @throws OutOfRangeException
98     * @return self
99     */
100    public function setC(float|string $c): self
101    {
102        $c = (float)$c;
103        if (($c > 0.5) || ($c < 0)) {
104            throw new OutOfRangeException('Error: The value of $c must be between 0 and 0.5.');
105        }
106        $this->c = $c;
107        return $this;
108    }
109
110    /**
111     * Set H value
112     *
113     * @param  int|string $h
114     * @throws OutOfRangeException
115     * @return self
116     */
117    public function setH(int|string $h): self
118    {
119        $h = (int)$h;
120        if (($h > 360) || ($h < 0)) {
121            throw new OutOfRangeException('Error: The value of $h must be between 0 and 360.');
122        }
123        $this->h = $h;
124        return $this;
125    }
126
127    /**
128     * Set alpha value
129     *
130     * @param  float|string $alpha
131     * @throws OutOfRangeException
132     * @return self
133     */
134    public function setAlpha(float|string $alpha): self
135    {
136        $alpha = (float)$alpha;
137        if (($alpha > 1) || ($alpha < 0)) {
138            throw new OutOfRangeException('Error: The value of $alpha must be between 0 and 1.');
139        }
140        $this->alpha = $alpha;
141        return $this;
142    }
143
144    /**
145     * Get L value
146     *
147     * @return float
148     */
149    public function getL(): float
150    {
151        return $this->l;
152    }
153
154    /**
155     * Get C value
156     *
157     * @return float
158     */
159    public function getC(): float
160    {
161        return $this->c;
162    }
163
164    /**
165     * Get H value
166     *
167     * @return int
168     */
169    public function getH(): int
170    {
171        return $this->h;
172    }
173
174    /**
175     * Get alpha value
176     *
177     * @return float|null
178     */
179    public function getAlpha(): float|null
180    {
181        return $this->alpha;
182    }
183
184    /**
185     * Determine if the color object has an alpha value
186     *
187     * @return bool
188     */
189    public function hasAlpha(): bool
190    {
191        return ($this->alpha !== null);
192    }
193
194    /**
195     * Convert to Oklab
196     *
197     * @return Oklab
198     */
199    public function toOklab(): Oklab
200    {
201        $hRad = deg2rad($this->h);
202        $a = $this->c * cos($hRad);
203        $b = $this->c * sin($hRad);
204
205        return new Oklab($this->l, round($a, 4), round($b, 4), $this->alpha);
206    }
207
208    /**
209     * Convert to RGB
210     *
211     * @return Rgb
212     */
213    public function toRgb(): Rgb
214    {
215        return $this->toOklab()->toRgb();
216    }
217
218    /**
219     * Convert to array
220     *
221     * @param  bool $assoc
222     * @return array
223     */
224    public function toArray(bool $assoc = true): array
225    {
226        $oklch = [];
227
228        if ($assoc) {
229            $oklch['l'] = $this->l;
230            $oklch['c'] = $this->c;
231            $oklch['h'] = $this->h;
232            if ($this->alpha !== null) {
233                $oklch['alpha'] = $this->alpha;
234            }
235        } else {
236            $oklch[] = $this->l;
237            $oklch[] = $this->c;
238            $oklch[] = $this->h;
239            if ($this->alpha !== null) {
240                $oklch[] = $this->alpha;
241            }
242        }
243
244        return $oklch;
245    }
246
247    /**
248     * Convert to readable string
249     *
250     * @param  ?string $format
251     * @return string
252     */
253    public function render(?string $format = null): string
254    {
255        return match ($format) {
256            self::COMMA => $this->l . ', ' . $this->c . ', ' . $this->h .
257                (($this->alpha !== null) ? ', ' . $this->alpha : ''),
258            self::CSS => 'oklch(' . $this->l . ' ' . $this->c . ' ' . $this->h .
259                (($this->alpha !== null) ? ' / ' . $this->alpha : '') . ')',
260            self::PERCENT => $this->toRgb()->render(self::PERCENT),
261            default => $this->l . ' ' . $this->c . ' ' . $this->h .
262                (($this->alpha !== null) ? ' ' . $this->alpha : ''),
263        };
264    }
265
266    /**
267     * Return CSS-formatted string
268     *
269     * @return string
270     */
271    public function __toString(): string
272    {
273        return $this->render(self::CSS);
274    }
275
276    /**
277     * Get the valid channel names
278     *
279     * @return array
280     */
281    protected function channels(): array
282    {
283        return ['l', 'c', 'h', 'alpha'];
284    }
285
286}