PageRenderTime 42ms CodeModel.GetById 13ms RepoModel.GetById 1ms app.codeStats 0ms

/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Style/Color.php

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