Passed
Push — master ( 689ec5...45f08c )
by Sebastian
05:26
created

FormatsConverter::array2associative()   A

Complexity

Conditions 5
Paths 5

Size

Total Lines 37
Code Lines 18

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 18
c 1
b 0
f 0
dl 0
loc 37
rs 9.3554
cc 5
nc 5
nop 1
1
<?php
2
/**
3
 * File containing the class {@see FormatsConverter}.
4
 *
5
 * @see FormatsConverter
6
 *@subpackage RGBAColor
7
 * @package AppUtils
8
 */
9
10
declare(strict_types=1);
11
12
namespace AppUtils\RGBAColor;
13
14
use AppUtils\RGBAColor;
15
use AppUtils\RGBAColor\FormatsConverter\HEXParser;
16
use function AppUtils\parseVariable;
17
18
/**
19
 * The converter static class is used to convert between color
20
 * information formats.
21
 *
22
 * @package AppUtils
23
 * @subpackage RGBAColor
24
 * @author Sebastian Mordziol <[email protected]>
25
 */
26
class FormatsConverter
27
{
28
    public const ERROR_INVALID_COLOR_ARRAY = 99701;
29
30
    /**
31
     * Converts the color to a HEX color value. This is either
32
     * a RRGGBB or RRGGBBAA string, depending on whether there
33
     * is an alpha channel value.
34
     *
35
     * NOTE: The HEX letters are always uppercase.
36
     *
37
     * @param RGBAColor $color
38
     * @return string
39
     */
40
    public static function color2HEX(RGBAColor $color) : string
41
    {
42
        $hex =
43
            UnitsConverter::int2hex($color->getRed()->get8Bit()) .
44
            UnitsConverter::int2hex($color->getGreen()->get8Bit()) .
45
            UnitsConverter::int2hex($color->getBlue()->get8Bit());
46
47
        if($color->hasTransparency())
48
        {
49
            $hex .= UnitsConverter::int2hex($color->getOpacity()->get8Bit());
50
        }
51
52
        return strtoupper($hex);
53
    }
54
55
    /**
56
     * Converts the color to a CSS `rgb()` or `rgba()` value.
57
     *
58
     * @param RGBAColor $color
59
     * @return string
60
     */
61
    public static function color2CSS(RGBAColor $color) : string
62
    {
63
        if($color->hasTransparency())
64
        {
65
            return sprintf(
66
                'rgba(%s, %s, %s, %s)',
67
                $color->getRed()->get8Bit(),
68
                $color->getGreen()->get8Bit(),
69
                $color->getBlue()->get8Bit(),
70
                $color->getOpacity()->getFloat()
71
            );
72
        }
73
74
        return sprintf(
75
            'rgb(%s, %s, %s)',
76
            $color->getRed()->get8Bit(),
77
            $color->getGreen()->get8Bit(),
78
            $color->getBlue()->get8Bit()
79
        );
80
    }
81
82
    public static function color2array(RGBAColor $color) : ArrayConverter
83
    {
84
        return new ArrayConverter($color);
85
    }
86
87
    /**
88
     * Checks if the array is a valid color array with
89
     * all expected color keys present. The `alpha` key
90
     * is optional. If it's not valid, throws an exception.
91
     *
92
     * @param array $color
93
     * @throws ColorException
94
     * @see RGBAColor::ERROR_INVALID_COLOR_ARRAY
95
     */
96
    public static function requireValidColorArray(array $color) : void
97
    {
98
        if(self::isColorArray($color))
99
        {
100
            return;
101
        }
102
103
        throw new ColorException(
104
            'Not a valid color array.',
105
            sprintf(
106
                'The color array is in the wrong format, or is missing required keys. '.
107
                'Given: '.PHP_EOL.
108
                '%s',
109
                parseVariable($color)->toString()
110
            ),
111
            RGBAColor::ERROR_INVALID_COLOR_ARRAY
112
        );
113
    }
114
115
    /**
116
     * Checks whether the specified array contains all required
117
     * color keys.
118
     *
119
     * @param array $color
120
     * @return bool
121
     */
122
    public static function isColorArray(array $color) : bool
123
    {
124
        $keys = array(
125
            RGBAColor::CHANNEL_RED,
126
            RGBAColor::CHANNEL_GREEN,
127
            RGBAColor::CHANNEL_BLUE
128
        );
129
130
        foreach($keys as $key)
131
        {
132
            if(!isset($color[$key]))
133
            {
134
                return false;
135
            }
136
        }
137
138
        return true;
139
    }
140
141
    /**
142
     * Human-readable label of the color. Automatically
143
     * switches between RGBA and RGB depending on whether
144
     * the color has any transparency.
145
     *
146
     * @param RGBAColor $color
147
     * @return string
148
     */
149
    public static function color2readable(RGBAColor $color) : string
150
    {
151
        if($color->hasTransparency())
152
        {
153
            return sprintf(
154
                'RGBA(%s %s %s %s)',
155
                $color->getRed()->get8Bit(),
156
                $color->getGreen()->get8Bit(),
157
                $color->getBlue()->get8Bit(),
158
                $color->getOpacity()->get8Bit()
159
            );
160
        }
161
162
        return sprintf(
163
            'RGB(%s %s %s)',
164
            $color->getRed()->get8Bit(),
165
            $color->getGreen()->get8Bit(),
166
            $color->getBlue()->get8Bit()
167
        );
168
    }
169
170
    /**
171
     * @var HEXParser|NULL
172
     */
173
    private static $hexParser = null;
174
175
    /**
176
     * Parses a HEX color value, and converts it to
177
     * an RGBA color array.
178
     *
179
     * Examples:
180
     *
181
     * <pre>
182
     * $color = RGBAColor_Utilities::parseHexColor('CCC');
183
     * $color = RGBAColor_Utilities::parseHexColor('CCDDEE');
184
     * $color = RGBAColor_Utilities::parseHexColor('CCDDEEFA');
185
     * </pre>
186
     *
187
     * @param string $hex
188
     * @param string $name
189
     * @return RGBAColor
190
     *
191
     * @throws ColorException
192
     * @see RGBAColor::ERROR_INVALID_HEX_LENGTH
193
     */
194
    public static function hex2color(string $hex, string $name='') : RGBAColor
195
    {
196
        if(!isset(self::$hexParser))
197
        {
198
            self::$hexParser = new HEXParser();
199
        }
200
201
        return self::$hexParser->parse($hex, $name);
202
    }
203
204
    /**
205
     * @var array<int,array{key:string,mandatory:bool}>
206
     */
207
    private static $keys = array(
208
        array(
209
            'key' => RGBAColor::CHANNEL_RED,
210
            'mandatory' => true
211
        ),
212
        array(
213
            'key' => RGBAColor::CHANNEL_GREEN,
214
            'mandatory' => true
215
        ),
216
        array(
217
            'key' => RGBAColor::CHANNEL_BLUE,
218
            'mandatory' => true
219
        ),
220
        array(
221
            'key' => RGBAColor::CHANNEL_ALPHA,
222
            'mandatory' => false
223
        )
224
    );
225
226
    /**
227
     * Converts a color array to an associative color
228
     * array. Works with indexed color arrays, as well
229
     * as arrays that are already associative.
230
     *
231
     * Expects the color values to always be in the same order:
232
     *
233
     * - red
234
     * - green
235
     * - blue
236
     * - alpha (optional)
237
     *
238
     * @param array<int,int|float> $color
239
     * @return array<string,int|float>
240
     *
241
     * @throws ColorException
242
     * @see FormatsConverter::ERROR_INVALID_COLOR_ARRAY
243
     */
244
    public static function array2associative(array $color) : array
245
    {
246
        // If one associative key is present, we assume
247
        // that the color array is already correct.
248
        if(isset($color[RGBAColor::CHANNEL_RED]))
249
        {
250
            return $color;
251
        }
252
253
        $values = array_values($color);
254
        $result = array();
255
256
        foreach(self::$keys as $idx => $def)
257
        {
258
            if(isset($values[$idx]))
259
            {
260
                $result[$def['key']] = $values[$idx];
261
                continue;
262
            }
263
264
            if(!$def['mandatory'])
265
            {
266
                continue;
267
            }
268
269
            throw new ColorException(
270
                'Invalid color array',
271
                sprintf(
272
                    'The value for [%s] is missing at index [%s] in the source array, and it is mandatory.',
273
                    $def['key'],
274
                    $idx
275
                ),
276
                self::ERROR_INVALID_COLOR_ARRAY
277
            );
278
        }
279
280
        return $result;
281
    }
282
}
283