Completed
Push — master ( 360b8c...500af5 )
by ARCANEDEV
9s
created

HSVTrait::fromRgbToHsv()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 22
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 16
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 22
ccs 16
cts 16
cp 1
rs 9.2
c 0
b 0
f 0
cc 2
eloc 16
nc 2
nop 3
crap 2
1
<?php namespace Arcanedev\Color\Converters;
2
3
/**
4
 * Trait     HSVTrait
5
 *
6
 * @package  Arcanedev\Color\Converters
7
 * @author   ARCANEDEV <[email protected]>
8
 */
9
trait HSVTrait
10
{
11
    /* ------------------------------------------------------------------------------------------------
12
     |  Main Functions
13
     | ------------------------------------------------------------------------------------------------
14
     */
15
    /**
16
     * Convert an RGB color to an HSV array (alias).
17
     *
18
     * @see    fromRgbToHsv
19
     *
20
     * @param  int  $red
21
     * @param  int  $green
22
     * @param  int  $blue
23
     *
24
     * @return array
25
     */
26 8
    public static function rgbToHsv($red, $green, $blue)
27
    {
28 8
        return (new self())->fromRgbToHsv($red, $green, $blue);
29
    }
30
31
    /**
32
     * Convert an RGB color to an HSV array.
33
     *
34
     * @param  int  $red
35
     * @param  int  $green
36
     * @param  int  $blue
37
     *
38
     * @return array
39
     */
40 16
    public function fromRgbToHsv($red, $green, $blue)
41
    {
42 16
        $red        = $red   / 255;
43 16
        $green      = $green / 255;
44 16
        $blue       = $blue  / 255;
45 16
        $maxRGB     = max($red, $green, $blue);
46 16
        $minRGB     = min($red, $green, $blue);
47
48 16
        $hue        = 0;
49 16
        $saturation = 0;
50 16
        $value      = 100 * $maxRGB;
51 16
        $chroma     = $maxRGB - $minRGB;
52
53 16
        if ($chroma != 0) {
54 16
            $saturation = 100 * ($chroma / $maxRGB);
55 16
            $hue        = $this->recalculateHue($red, $green, $blue, $minRGB, $chroma) * 60;
56 8
        }
57
58
        return array_map(function ($value) {
59 16
            return round($value, 2);
60 16
        }, [$hue, $saturation, $value]);
61
    }
62
63
    /**
64
     * Convert an HSV color to an RGB array (alias).
65
     *
66
     * @see    fromHsvToRgb
67
     *
68
     * @param  float|int  $hue
69
     * @param  float|int  $saturation
70
     * @param  float|int  $value
71
     *
72
     * @return array
73
     */
74 8
    public static function hsvToRgb($hue, $saturation, $value)
75
    {
76 8
        return (new self)->fromHsvToRgb($hue, $saturation, $value);
77
    }
78
79
    /**
80
     * Convert an HSV color to an RGB array.
81
     *
82
     * @param  float|int  $hue
83
     * @param  float|int  $saturation
84
     * @param  float|int  $value
85
     *
86
     * @return array
87
     */
88 16
    public function fromHsvToRgb($hue, $saturation, $value)
89
    {
90
        // Lightness: 0.0 - 1.0
91 16
        $lightness = $this->sanitizeHsvValue($value, 0, 100) / 100.0;
92
        // Chroma:    0.0 - 1.0
93 16
        $chroma    = $lightness * ($this->sanitizeHsvValue($saturation, 0, 100) / 100.0);
94
95 16
        return array_map(function ($color) use ($lightness, $chroma) {
96 16
            return (int) round(($color + ($lightness - $chroma)) * 255);
97 16
        }, $this->calculateRgbWithHueAndChroma($hue, $chroma));
98
    }
99
100
    /* ------------------------------------------------------------------------------------------------
101
     |  Other Functions
102
     | ------------------------------------------------------------------------------------------------
103
     */
104
    /**
105
     * Recalculate the Hue.
106
     *
107
     * @param  float|int  $red
108
     * @param  float|int  $green
109
     * @param  float|int  $blue
110
     * @param  float|int  $minRGB
111
     * @param  float|int  $chroma
112
     *
113
     * @return float|int
114
     */
115 16
    protected function recalculateHue($red, $green, $blue, $minRGB, $chroma)
116
    {
117
        switch ($minRGB) {
118 16
            case $red:
119 8
                return 3 - (($green - $blue) / $chroma);
120
121 16
            case $blue:
122 16
                return 1 - (($red - $green) / $chroma);
123
124 8
            case $green:
125 4
            default:
126 8
                return 5 - (($blue - $red) / $chroma);
127
        }
128
    }
129
130
    /**
131
     * Calculate RGB with hue and chroma.
132
     *
133
     * @param  float|int  $hue
134
     * @param  float|int  $chroma
135
     *
136
     * @return array
137
     */
138 16
    protected function calculateRgbWithHueAndChroma($hue, $chroma)
139
    {
140 16
        $hPrime = $this->sanitizeHsvValue($hue, 0, 360) / 60.0;
141 16
        $xPrime = $this->calculateXPrime($hPrime, $chroma);
142 16
        $colors = $this->getColorsRange($chroma, $xPrime);
143 16
        $index  = (int) floor($hPrime);
144
145 16
        return array_key_exists($index, $colors) ? $colors[$index] : [0.0, 0.0, 0.0];
146
    }
147
148
    /**
149
     * Calculate X-Prime.
150
     *
151
     * @param  float|int  $hPrime
152
     * @param  float|int  $chroma
153
     *
154
     * @return float|int
155
     */
156 16
    protected function calculateXPrime($hPrime, $chroma)
157
    {
158 16
        while ($hPrime >= 2.0) $hPrime -= 2.0;
159
160 16
        return $chroma * (1 - abs($hPrime - 1));
161
    }
162
163
    /**
164
     * Sanitize HSV value.
165
     *
166
     * @param  int  $value
167
     * @param  int  $min
168
     * @param  int  $max
169
     *
170
     * @return float|int
171
     */
172 16
    protected function sanitizeHsvValue($value, $min, $max)
173
    {
174 16
        if ($value < $min) return $min;
175 16
        if ($value > $max) return $max;
176
177 16
        return $value;
178
    }
179
180
    /**
181
     * Get the colors range.
182
     *
183
     * @param  float|int  $chroma
184
     * @param  float|int  $xPrime
185
     *
186
     * @return array
187
     */
188 16
    protected function getColorsRange($chroma, $xPrime)
189
    {
190
        return [
191 16
            0 => [$chroma, $xPrime, 0.0],
192 16
            1 => [$xPrime, $chroma, 0.0],
193 16
            2 => [0.0, $chroma, $xPrime],
194 16
            3 => [0.0, $xPrime, $chroma],
195 16
            4 => [$xPrime, 0.0, $chroma],
196 16
            5 => [$chroma, 0.0, $xPrime],
197 8
        ];
198
    }
199
}
200