1 |
efrain |
1 |
<?php
|
|
|
2 |
|
|
|
3 |
namespace PhpOffice\PhpSpreadsheet\Style;
|
|
|
4 |
|
|
|
5 |
class Color extends Supervisor
|
|
|
6 |
{
|
|
|
7 |
const NAMED_COLORS = [
|
|
|
8 |
'Black',
|
|
|
9 |
'White',
|
|
|
10 |
'Red',
|
|
|
11 |
'Green',
|
|
|
12 |
'Blue',
|
|
|
13 |
'Yellow',
|
|
|
14 |
'Magenta',
|
|
|
15 |
'Cyan',
|
|
|
16 |
];
|
|
|
17 |
|
|
|
18 |
// Colors
|
|
|
19 |
const COLOR_BLACK = 'FF000000';
|
|
|
20 |
const COLOR_WHITE = 'FFFFFFFF';
|
|
|
21 |
const COLOR_RED = 'FFFF0000';
|
|
|
22 |
const COLOR_DARKRED = 'FF800000';
|
|
|
23 |
const COLOR_BLUE = 'FF0000FF';
|
|
|
24 |
const COLOR_DARKBLUE = 'FF000080';
|
|
|
25 |
const COLOR_GREEN = 'FF00FF00';
|
|
|
26 |
const COLOR_DARKGREEN = 'FF008000';
|
|
|
27 |
const COLOR_YELLOW = 'FFFFFF00';
|
|
|
28 |
const COLOR_DARKYELLOW = 'FF808000';
|
|
|
29 |
const COLOR_MAGENTA = 'FFFF00FF';
|
|
|
30 |
const COLOR_CYAN = 'FF00FFFF';
|
|
|
31 |
|
|
|
32 |
const NAMED_COLOR_TRANSLATIONS = [
|
|
|
33 |
'Black' => self::COLOR_BLACK,
|
|
|
34 |
'White' => self::COLOR_WHITE,
|
|
|
35 |
'Red' => self::COLOR_RED,
|
|
|
36 |
'Green' => self::COLOR_GREEN,
|
|
|
37 |
'Blue' => self::COLOR_BLUE,
|
|
|
38 |
'Yellow' => self::COLOR_YELLOW,
|
|
|
39 |
'Magenta' => self::COLOR_MAGENTA,
|
|
|
40 |
'Cyan' => self::COLOR_CYAN,
|
|
|
41 |
];
|
|
|
42 |
|
|
|
43 |
const VALIDATE_ARGB_SIZE = 8;
|
|
|
44 |
const VALIDATE_RGB_SIZE = 6;
|
|
|
45 |
const VALIDATE_COLOR_6 = '/^[A-F0-9]{6}$/i';
|
|
|
46 |
const VALIDATE_COLOR_8 = '/^[A-F0-9]{8}$/i';
|
|
|
47 |
|
|
|
48 |
private const INDEXED_COLORS = [
|
|
|
49 |
1 => 'FF000000', // System Colour #1 - Black
|
|
|
50 |
2 => 'FFFFFFFF', // System Colour #2 - White
|
|
|
51 |
3 => 'FFFF0000', // System Colour #3 - Red
|
|
|
52 |
4 => 'FF00FF00', // System Colour #4 - Green
|
|
|
53 |
5 => 'FF0000FF', // System Colour #5 - Blue
|
|
|
54 |
6 => 'FFFFFF00', // System Colour #6 - Yellow
|
|
|
55 |
7 => 'FFFF00FF', // System Colour #7- Magenta
|
|
|
56 |
8 => 'FF00FFFF', // System Colour #8- Cyan
|
|
|
57 |
9 => 'FF800000', // Standard Colour #9
|
|
|
58 |
10 => 'FF008000', // Standard Colour #10
|
|
|
59 |
11 => 'FF000080', // Standard Colour #11
|
|
|
60 |
12 => 'FF808000', // Standard Colour #12
|
|
|
61 |
13 => 'FF800080', // Standard Colour #13
|
|
|
62 |
14 => 'FF008080', // Standard Colour #14
|
|
|
63 |
15 => 'FFC0C0C0', // Standard Colour #15
|
|
|
64 |
16 => 'FF808080', // Standard Colour #16
|
|
|
65 |
17 => 'FF9999FF', // Chart Fill Colour #17
|
|
|
66 |
18 => 'FF993366', // Chart Fill Colour #18
|
|
|
67 |
19 => 'FFFFFFCC', // Chart Fill Colour #19
|
|
|
68 |
20 => 'FFCCFFFF', // Chart Fill Colour #20
|
|
|
69 |
21 => 'FF660066', // Chart Fill Colour #21
|
|
|
70 |
22 => 'FFFF8080', // Chart Fill Colour #22
|
|
|
71 |
23 => 'FF0066CC', // Chart Fill Colour #23
|
|
|
72 |
24 => 'FFCCCCFF', // Chart Fill Colour #24
|
|
|
73 |
25 => 'FF000080', // Chart Line Colour #25
|
|
|
74 |
26 => 'FFFF00FF', // Chart Line Colour #26
|
|
|
75 |
27 => 'FFFFFF00', // Chart Line Colour #27
|
|
|
76 |
28 => 'FF00FFFF', // Chart Line Colour #28
|
|
|
77 |
29 => 'FF800080', // Chart Line Colour #29
|
|
|
78 |
30 => 'FF800000', // Chart Line Colour #30
|
|
|
79 |
31 => 'FF008080', // Chart Line Colour #31
|
|
|
80 |
32 => 'FF0000FF', // Chart Line Colour #32
|
|
|
81 |
33 => 'FF00CCFF', // Standard Colour #33
|
|
|
82 |
34 => 'FFCCFFFF', // Standard Colour #34
|
|
|
83 |
35 => 'FFCCFFCC', // Standard Colour #35
|
|
|
84 |
36 => 'FFFFFF99', // Standard Colour #36
|
|
|
85 |
37 => 'FF99CCFF', // Standard Colour #37
|
|
|
86 |
38 => 'FFFF99CC', // Standard Colour #38
|
|
|
87 |
39 => 'FFCC99FF', // Standard Colour #39
|
|
|
88 |
40 => 'FFFFCC99', // Standard Colour #40
|
|
|
89 |
41 => 'FF3366FF', // Standard Colour #41
|
|
|
90 |
42 => 'FF33CCCC', // Standard Colour #42
|
|
|
91 |
43 => 'FF99CC00', // Standard Colour #43
|
|
|
92 |
44 => 'FFFFCC00', // Standard Colour #44
|
|
|
93 |
45 => 'FFFF9900', // Standard Colour #45
|
|
|
94 |
46 => 'FFFF6600', // Standard Colour #46
|
|
|
95 |
47 => 'FF666699', // Standard Colour #47
|
|
|
96 |
48 => 'FF969696', // Standard Colour #48
|
|
|
97 |
49 => 'FF003366', // Standard Colour #49
|
|
|
98 |
50 => 'FF339966', // Standard Colour #50
|
|
|
99 |
51 => 'FF003300', // Standard Colour #51
|
|
|
100 |
52 => 'FF333300', // Standard Colour #52
|
|
|
101 |
53 => 'FF993300', // Standard Colour #53
|
|
|
102 |
54 => 'FF993366', // Standard Colour #54
|
|
|
103 |
55 => 'FF333399', // Standard Colour #55
|
|
|
104 |
56 => 'FF333333', // Standard Colour #56
|
|
|
105 |
];
|
|
|
106 |
|
|
|
107 |
/**
|
|
|
108 |
* ARGB - Alpha RGB.
|
|
|
109 |
*
|
|
|
110 |
* @var null|string
|
|
|
111 |
*/
|
|
|
112 |
protected $argb;
|
|
|
113 |
|
|
|
114 |
/** @var bool */
|
|
|
115 |
private $hasChanged = false;
|
|
|
116 |
|
|
|
117 |
/**
|
|
|
118 |
* Create a new Color.
|
|
|
119 |
*
|
|
|
120 |
* @param string $colorValue ARGB value for the colour, or named colour
|
|
|
121 |
* @param bool $isSupervisor Flag indicating if this is a supervisor or not
|
|
|
122 |
* Leave this value at default unless you understand exactly what
|
|
|
123 |
* its ramifications are
|
|
|
124 |
* @param bool $isConditional Flag indicating if this is a conditional style or not
|
|
|
125 |
* Leave this value at default unless you understand exactly what
|
|
|
126 |
* its ramifications are
|
|
|
127 |
*/
|
|
|
128 |
public function __construct($colorValue = self::COLOR_BLACK, $isSupervisor = false, $isConditional = false)
|
|
|
129 |
{
|
|
|
130 |
// Supervisor?
|
|
|
131 |
parent::__construct($isSupervisor);
|
|
|
132 |
|
|
|
133 |
// Initialise values
|
|
|
134 |
if (!$isConditional) {
|
|
|
135 |
$this->argb = $this->validateColor($colorValue) ?: self::COLOR_BLACK;
|
|
|
136 |
}
|
|
|
137 |
}
|
|
|
138 |
|
|
|
139 |
/**
|
|
|
140 |
* Get the shared style component for the currently active cell in currently active sheet.
|
|
|
141 |
* Only used for style supervisor.
|
|
|
142 |
*
|
|
|
143 |
* @return Color
|
|
|
144 |
*/
|
|
|
145 |
public function getSharedComponent()
|
|
|
146 |
{
|
|
|
147 |
/** @var Style */
|
|
|
148 |
$parent = $this->parent;
|
|
|
149 |
/** @var Border|Fill $sharedComponent */
|
|
|
150 |
$sharedComponent = $parent->getSharedComponent();
|
|
|
151 |
if ($sharedComponent instanceof Fill) {
|
|
|
152 |
if ($this->parentPropertyName === 'endColor') {
|
|
|
153 |
return $sharedComponent->getEndColor();
|
|
|
154 |
}
|
|
|
155 |
|
|
|
156 |
return $sharedComponent->getStartColor();
|
|
|
157 |
}
|
|
|
158 |
|
|
|
159 |
return $sharedComponent->getColor();
|
|
|
160 |
}
|
|
|
161 |
|
|
|
162 |
/**
|
|
|
163 |
* Build style array from subcomponents.
|
|
|
164 |
*
|
|
|
165 |
* @param array $array
|
|
|
166 |
*
|
|
|
167 |
* @return array
|
|
|
168 |
*/
|
|
|
169 |
public function getStyleArray($array)
|
|
|
170 |
{
|
|
|
171 |
/** @var Style */
|
|
|
172 |
$parent = $this->parent;
|
|
|
173 |
|
|
|
174 |
return $parent->/** @scrutinizer ignore-call */ getStyleArray([$this->parentPropertyName => $array]);
|
|
|
175 |
}
|
|
|
176 |
|
|
|
177 |
/**
|
|
|
178 |
* Apply styles from array.
|
|
|
179 |
*
|
|
|
180 |
* <code>
|
|
|
181 |
* $spreadsheet->getActiveSheet()->getStyle('B2')->getFont()->getColor()->applyFromArray(['rgb' => '808080']);
|
|
|
182 |
* </code>
|
|
|
183 |
*
|
|
|
184 |
* @param array $styleArray Array containing style information
|
|
|
185 |
*
|
|
|
186 |
* @return $this
|
|
|
187 |
*/
|
|
|
188 |
public function applyFromArray(array $styleArray)
|
|
|
189 |
{
|
|
|
190 |
if ($this->isSupervisor) {
|
|
|
191 |
$this->getActiveSheet()->getStyle($this->getSelectedCells())->applyFromArray($this->getStyleArray($styleArray));
|
|
|
192 |
} else {
|
|
|
193 |
if (isset($styleArray['rgb'])) {
|
|
|
194 |
$this->setRGB($styleArray['rgb']);
|
|
|
195 |
}
|
|
|
196 |
if (isset($styleArray['argb'])) {
|
|
|
197 |
$this->setARGB($styleArray['argb']);
|
|
|
198 |
}
|
|
|
199 |
}
|
|
|
200 |
|
|
|
201 |
return $this;
|
|
|
202 |
}
|
|
|
203 |
|
|
|
204 |
private function validateColor(?string $colorValue): string
|
|
|
205 |
{
|
|
|
206 |
if ($colorValue === null || $colorValue === '') {
|
|
|
207 |
return self::COLOR_BLACK;
|
|
|
208 |
}
|
|
|
209 |
$named = ucfirst(strtolower($colorValue));
|
|
|
210 |
if (array_key_exists($named, self::NAMED_COLOR_TRANSLATIONS)) {
|
|
|
211 |
return self::NAMED_COLOR_TRANSLATIONS[$named];
|
|
|
212 |
}
|
|
|
213 |
if (preg_match(self::VALIDATE_COLOR_8, $colorValue) === 1) {
|
|
|
214 |
return $colorValue;
|
|
|
215 |
}
|
|
|
216 |
if (preg_match(self::VALIDATE_COLOR_6, $colorValue) === 1) {
|
|
|
217 |
return 'FF' . $colorValue;
|
|
|
218 |
}
|
|
|
219 |
|
|
|
220 |
return '';
|
|
|
221 |
}
|
|
|
222 |
|
|
|
223 |
/**
|
|
|
224 |
* Get ARGB.
|
|
|
225 |
*/
|
|
|
226 |
public function getARGB(): ?string
|
|
|
227 |
{
|
|
|
228 |
if ($this->isSupervisor) {
|
|
|
229 |
return $this->getSharedComponent()->getARGB();
|
|
|
230 |
}
|
|
|
231 |
|
|
|
232 |
return $this->argb;
|
|
|
233 |
}
|
|
|
234 |
|
|
|
235 |
/**
|
|
|
236 |
* Set ARGB.
|
|
|
237 |
*
|
|
|
238 |
* @param string $colorValue ARGB value, or a named color
|
|
|
239 |
*
|
|
|
240 |
* @return $this
|
|
|
241 |
*/
|
|
|
242 |
public function setARGB(?string $colorValue = self::COLOR_BLACK)
|
|
|
243 |
{
|
|
|
244 |
$this->hasChanged = true;
|
|
|
245 |
$colorValue = $this->validateColor($colorValue);
|
|
|
246 |
if ($colorValue === '') {
|
|
|
247 |
return $this;
|
|
|
248 |
}
|
|
|
249 |
|
|
|
250 |
if ($this->isSupervisor) {
|
|
|
251 |
$styleArray = $this->getStyleArray(['argb' => $colorValue]);
|
|
|
252 |
$this->getActiveSheet()->getStyle($this->getSelectedCells())->applyFromArray($styleArray);
|
|
|
253 |
} else {
|
|
|
254 |
$this->argb = $colorValue;
|
|
|
255 |
}
|
|
|
256 |
|
|
|
257 |
return $this;
|
|
|
258 |
}
|
|
|
259 |
|
|
|
260 |
/**
|
|
|
261 |
* Get RGB.
|
|
|
262 |
*/
|
|
|
263 |
public function getRGB(): string
|
|
|
264 |
{
|
|
|
265 |
if ($this->isSupervisor) {
|
|
|
266 |
return $this->getSharedComponent()->getRGB();
|
|
|
267 |
}
|
|
|
268 |
|
|
|
269 |
return substr($this->argb ?? '', 2);
|
|
|
270 |
}
|
|
|
271 |
|
|
|
272 |
/**
|
|
|
273 |
* Set RGB.
|
|
|
274 |
*
|
|
|
275 |
* @param string $colorValue RGB value, or a named color
|
|
|
276 |
*
|
|
|
277 |
* @return $this
|
|
|
278 |
*/
|
|
|
279 |
public function setRGB(?string $colorValue = self::COLOR_BLACK)
|
|
|
280 |
{
|
|
|
281 |
return $this->setARGB($colorValue);
|
|
|
282 |
}
|
|
|
283 |
|
|
|
284 |
/**
|
|
|
285 |
* Get a specified colour component of an RGB value.
|
|
|
286 |
*
|
|
|
287 |
* @param string $rgbValue The colour as an RGB value (e.g. FF00CCCC or CCDDEE
|
|
|
288 |
* @param int $offset Position within the RGB value to extract
|
|
|
289 |
* @param bool $hex Flag indicating whether the component should be returned as a hex or a
|
|
|
290 |
* decimal value
|
|
|
291 |
*
|
|
|
292 |
* @return int|string The extracted colour component
|
|
|
293 |
*/
|
|
|
294 |
private static function getColourComponent($rgbValue, $offset, $hex = true)
|
|
|
295 |
{
|
|
|
296 |
$colour = substr($rgbValue, $offset, 2) ?: '';
|
|
|
297 |
if (preg_match('/^[0-9a-f]{2}$/i', $colour) !== 1) {
|
|
|
298 |
$colour = '00';
|
|
|
299 |
}
|
|
|
300 |
|
|
|
301 |
return ($hex) ? $colour : (int) hexdec($colour);
|
|
|
302 |
}
|
|
|
303 |
|
|
|
304 |
/**
|
|
|
305 |
* Get the red colour component of an RGB value.
|
|
|
306 |
*
|
|
|
307 |
* @param string $rgbValue The colour as an RGB value (e.g. FF00CCCC or CCDDEE
|
|
|
308 |
* @param bool $hex Flag indicating whether the component should be returned as a hex or a
|
|
|
309 |
* decimal value
|
|
|
310 |
*
|
|
|
311 |
* @return int|string The red colour component
|
|
|
312 |
*/
|
|
|
313 |
public static function getRed($rgbValue, $hex = true)
|
|
|
314 |
{
|
|
|
315 |
return self::getColourComponent($rgbValue, strlen($rgbValue) - 6, $hex);
|
|
|
316 |
}
|
|
|
317 |
|
|
|
318 |
/**
|
|
|
319 |
* Get the green colour component of an RGB value.
|
|
|
320 |
*
|
|
|
321 |
* @param string $rgbValue The colour as an RGB value (e.g. FF00CCCC or CCDDEE
|
|
|
322 |
* @param bool $hex Flag indicating whether the component should be returned as a hex or a
|
|
|
323 |
* decimal value
|
|
|
324 |
*
|
|
|
325 |
* @return int|string The green colour component
|
|
|
326 |
*/
|
|
|
327 |
public static function getGreen($rgbValue, $hex = true)
|
|
|
328 |
{
|
|
|
329 |
return self::getColourComponent($rgbValue, strlen($rgbValue) - 4, $hex);
|
|
|
330 |
}
|
|
|
331 |
|
|
|
332 |
/**
|
|
|
333 |
* Get the blue colour component of an RGB value.
|
|
|
334 |
*
|
|
|
335 |
* @param string $rgbValue The colour as an RGB value (e.g. FF00CCCC or CCDDEE
|
|
|
336 |
* @param bool $hex Flag indicating whether the component should be returned as a hex or a
|
|
|
337 |
* decimal value
|
|
|
338 |
*
|
|
|
339 |
* @return int|string The blue colour component
|
|
|
340 |
*/
|
|
|
341 |
public static function getBlue($rgbValue, $hex = true)
|
|
|
342 |
{
|
|
|
343 |
return self::getColourComponent($rgbValue, strlen($rgbValue) - 2, $hex);
|
|
|
344 |
}
|
|
|
345 |
|
|
|
346 |
/**
|
|
|
347 |
* Adjust the brightness of a color.
|
|
|
348 |
*
|
|
|
349 |
* @param string $hexColourValue The colour as an RGBA or RGB value (e.g. FF00CCCC or CCDDEE)
|
|
|
350 |
* @param float $adjustPercentage The percentage by which to adjust the colour as a float from -1 to 1
|
|
|
351 |
*
|
|
|
352 |
* @return string The adjusted colour as an RGBA or RGB value (e.g. FF00CCCC or CCDDEE)
|
|
|
353 |
*/
|
|
|
354 |
public static function changeBrightness($hexColourValue, $adjustPercentage)
|
|
|
355 |
{
|
|
|
356 |
$rgba = (strlen($hexColourValue) === 8);
|
|
|
357 |
$adjustPercentage = max(-1.0, min(1.0, $adjustPercentage));
|
|
|
358 |
|
|
|
359 |
/** @var int $red */
|
|
|
360 |
$red = self::getRed($hexColourValue, false);
|
|
|
361 |
/** @var int $green */
|
|
|
362 |
$green = self::getGreen($hexColourValue, false);
|
|
|
363 |
/** @var int $blue */
|
|
|
364 |
$blue = self::getBlue($hexColourValue, false);
|
|
|
365 |
|
|
|
366 |
return (($rgba) ? 'FF' : '') . RgbTint::rgbAndTintToRgb($red, $green, $blue, $adjustPercentage);
|
|
|
367 |
}
|
|
|
368 |
|
|
|
369 |
/**
|
|
|
370 |
* Get indexed color.
|
|
|
371 |
*
|
|
|
372 |
* @param int $colorIndex Index entry point into the colour array
|
|
|
373 |
* @param bool $background Flag to indicate whether default background or foreground colour
|
|
|
374 |
* should be returned if the indexed colour doesn't exist
|
|
|
375 |
*/
|
|
|
376 |
public static function indexedColor($colorIndex, $background = false, ?array $palette = null): self
|
|
|
377 |
{
|
|
|
378 |
// Clean parameter
|
|
|
379 |
$colorIndex = (int) $colorIndex;
|
|
|
380 |
|
|
|
381 |
if (empty($palette)) {
|
|
|
382 |
if (isset(self::INDEXED_COLORS[$colorIndex])) {
|
|
|
383 |
return new self(self::INDEXED_COLORS[$colorIndex]);
|
|
|
384 |
}
|
|
|
385 |
} else {
|
|
|
386 |
if (isset($palette[$colorIndex])) {
|
|
|
387 |
return new self($palette[$colorIndex]);
|
|
|
388 |
}
|
|
|
389 |
}
|
|
|
390 |
|
|
|
391 |
return ($background) ? new self(self::COLOR_WHITE) : new self(self::COLOR_BLACK);
|
|
|
392 |
}
|
|
|
393 |
|
|
|
394 |
/**
|
|
|
395 |
* Get hash code.
|
|
|
396 |
*
|
|
|
397 |
* @return string Hash code
|
|
|
398 |
*/
|
|
|
399 |
public function getHashCode(): string
|
|
|
400 |
{
|
|
|
401 |
if ($this->isSupervisor) {
|
|
|
402 |
return $this->getSharedComponent()->getHashCode();
|
|
|
403 |
}
|
|
|
404 |
|
|
|
405 |
return md5(
|
|
|
406 |
$this->argb .
|
|
|
407 |
__CLASS__
|
|
|
408 |
);
|
|
|
409 |
}
|
|
|
410 |
|
|
|
411 |
protected function exportArray1(): array
|
|
|
412 |
{
|
|
|
413 |
$exportedArray = [];
|
|
|
414 |
$this->exportArray2($exportedArray, 'argb', $this->getARGB());
|
|
|
415 |
|
|
|
416 |
return $exportedArray;
|
|
|
417 |
}
|
|
|
418 |
|
|
|
419 |
public function getHasChanged(): bool
|
|
|
420 |
{
|
|
|
421 |
if ($this->isSupervisor) {
|
|
|
422 |
return $this->getSharedComponent()->hasChanged;
|
|
|
423 |
}
|
|
|
424 |
|
|
|
425 |
return $this->hasChanged;
|
|
|
426 |
}
|
|
|
427 |
}
|