14cadd4f8SNickeau<?php 24cadd4f8SNickeau/** 34cadd4f8SNickeau * Copyright (c) 2020. ComboStrap, Inc. and its affiliates. All Rights Reserved. 44cadd4f8SNickeau * 54cadd4f8SNickeau * This source code is licensed under the GPL license found in the 64cadd4f8SNickeau * COPYING file in the root directory of this source tree. 74cadd4f8SNickeau * 84cadd4f8SNickeau * @license GPL 3 (https://www.gnu.org/licenses/gpl-3.0.en.html) 94cadd4f8SNickeau * @author ComboStrap <support@combostrap.com> 104cadd4f8SNickeau * 114cadd4f8SNickeau */ 124cadd4f8SNickeau 134cadd4f8SNickeaunamespace ComboStrap; 144cadd4f8SNickeauclass ColorHsl 154cadd4f8SNickeau{ 164cadd4f8SNickeau 174cadd4f8SNickeau const CANONICAL = "color"; 184cadd4f8SNickeau private $hue; 194cadd4f8SNickeau 204cadd4f8SNickeau private $saturation; 214cadd4f8SNickeau /** 224cadd4f8SNickeau * @var float|int 234cadd4f8SNickeau */ 244cadd4f8SNickeau private $lightness; 254cadd4f8SNickeau 264cadd4f8SNickeau /** 274cadd4f8SNickeau * ColorHsl constructor. 284cadd4f8SNickeau * @param $hue 294cadd4f8SNickeau * @param $saturation 304cadd4f8SNickeau * @param float|int $lightness 314cadd4f8SNickeau */ 324cadd4f8SNickeau public function __construct($hue, $saturation, $lightness) 334cadd4f8SNickeau { 344cadd4f8SNickeau $this->hue = $hue; 354cadd4f8SNickeau $this->saturation = $saturation; 364cadd4f8SNickeau $this->lightness = $lightness; 374cadd4f8SNickeau } 384cadd4f8SNickeau 394cadd4f8SNickeau 404cadd4f8SNickeau public static function createFromChannels(float $hue, float $saturation, float $lightness): ColorHsl 414cadd4f8SNickeau { 424cadd4f8SNickeau return new ColorHsl($hue, $saturation, $lightness); 434cadd4f8SNickeau } 444cadd4f8SNickeau 454cadd4f8SNickeau public function getLightness() 464cadd4f8SNickeau { 474cadd4f8SNickeau return $this->lightness; 484cadd4f8SNickeau } 494cadd4f8SNickeau 504cadd4f8SNickeau public function getSaturation() 514cadd4f8SNickeau { 524cadd4f8SNickeau return $this->saturation; 534cadd4f8SNickeau } 544cadd4f8SNickeau 554cadd4f8SNickeau public function getHue() 564cadd4f8SNickeau { 574cadd4f8SNickeau return $this->hue; 584cadd4f8SNickeau } 594cadd4f8SNickeau 604cadd4f8SNickeau /** 61*04fd306cSNickeau * @throws ExceptionCompile 624cadd4f8SNickeau */ 634cadd4f8SNickeau public function setLightness(int $int): ColorHsl 644cadd4f8SNickeau { 654cadd4f8SNickeau if ($int < 0 || $int > 100) { 66*04fd306cSNickeau throw new ExceptionCompile("Lightness should be between 0 and 100"); 674cadd4f8SNickeau } 684cadd4f8SNickeau $this->lightness = $int; 694cadd4f8SNickeau return $this; 704cadd4f8SNickeau } 714cadd4f8SNickeau 724cadd4f8SNickeau /** 734cadd4f8SNickeau * @return ColorRgb Reference: 744cadd4f8SNickeau * 754cadd4f8SNickeau * Reference: 764cadd4f8SNickeau * https://en.wikipedia.org/wiki/HSL_and_HSV#HSL_to_RGB 774cadd4f8SNickeau * https://gist.github.com/brandonheyer/5254516 78*04fd306cSNickeau * @throws ExceptionCompile 794cadd4f8SNickeau */ 804cadd4f8SNickeau function toRgb(): ColorRgb 814cadd4f8SNickeau { 824cadd4f8SNickeau 834cadd4f8SNickeau $lightness = $this->lightness / 100; 844cadd4f8SNickeau $saturation = $this->saturation / 100; 854cadd4f8SNickeau $hue = $this->hue; 864cadd4f8SNickeau 874cadd4f8SNickeau $chroma = (1 - abs(2 * $lightness - 1)) * $saturation; 884cadd4f8SNickeau $x = $chroma * (1 - abs(fmod(($hue / 60), 2) - 1)); 894cadd4f8SNickeau $m = $lightness - ($chroma / 2); 904cadd4f8SNickeau 914cadd4f8SNickeau if ($hue < 60) { 924cadd4f8SNickeau $red = $chroma; 934cadd4f8SNickeau $green = $x; 944cadd4f8SNickeau $blue = 0; 954cadd4f8SNickeau } else if ($hue < 120) { 964cadd4f8SNickeau $red = $x; 974cadd4f8SNickeau $green = $chroma; 984cadd4f8SNickeau $blue = 0; 994cadd4f8SNickeau } else if ($hue < 180) { 1004cadd4f8SNickeau $red = 0; 1014cadd4f8SNickeau $green = $chroma; 1024cadd4f8SNickeau $blue = $x; 1034cadd4f8SNickeau } else if ($hue < 240) { 1044cadd4f8SNickeau $red = 0; 1054cadd4f8SNickeau $green = $x; 1064cadd4f8SNickeau $blue = $chroma; 1074cadd4f8SNickeau } else if ($hue < 300) { 1084cadd4f8SNickeau $red = $x; 1094cadd4f8SNickeau $green = 0; 1104cadd4f8SNickeau $blue = $chroma; 1114cadd4f8SNickeau } else { 1124cadd4f8SNickeau $red = $chroma; 1134cadd4f8SNickeau $green = 0; 1144cadd4f8SNickeau $blue = $x; 1154cadd4f8SNickeau } 1164cadd4f8SNickeau 1174cadd4f8SNickeau $red = ($red + $m) * 255; 1184cadd4f8SNickeau $green = ($green + $m) * 255; 1194cadd4f8SNickeau $blue = ($blue + $m) * 255; 1204cadd4f8SNickeau 1214cadd4f8SNickeau /** 1224cadd4f8SNickeau * To the closest integer 1234cadd4f8SNickeau */ 1244cadd4f8SNickeau try { 1254cadd4f8SNickeau return ColorRgb::createFromRgbChannels( 1264cadd4f8SNickeau intval(round($red)), 1274cadd4f8SNickeau intval(round($green)), 1284cadd4f8SNickeau intval(round($blue)) 1294cadd4f8SNickeau ); 130*04fd306cSNickeau } catch (ExceptionCompile $e) { 1314cadd4f8SNickeau // should not happen but yeah, who knows 1324cadd4f8SNickeau // and because there is no safe constructor, no safe default, we throw 1334cadd4f8SNickeau $message = "Error while creating the rgb color from the hsl ($this)"; 134*04fd306cSNickeau throw new ExceptionCompile($message, self::CANONICAL, 0, $e); 1354cadd4f8SNickeau } 1364cadd4f8SNickeau 1374cadd4f8SNickeau } 1384cadd4f8SNickeau 1394cadd4f8SNickeau /** 140*04fd306cSNickeau * @throws ExceptionCompile 1414cadd4f8SNickeau */ 1424cadd4f8SNickeau public function setSaturation(int $saturation): ColorHsl 1434cadd4f8SNickeau { 1444cadd4f8SNickeau if ($saturation < 0 || $saturation > 100) { 145*04fd306cSNickeau throw new ExceptionCompile("Saturation should be between 0 and 100"); 1464cadd4f8SNickeau } 1474cadd4f8SNickeau $this->saturation = $saturation; 1484cadd4f8SNickeau return $this; 1494cadd4f8SNickeau } 1504cadd4f8SNickeau 1514cadd4f8SNickeau public function toComplement(): ColorHsl 1524cadd4f8SNickeau { 1534cadd4f8SNickeau // Adjust Hue 180 degrees 1544cadd4f8SNickeau $this->hue += ($this->hue > 180) ? -180 : 180; 1554cadd4f8SNickeau return $this; 1564cadd4f8SNickeau } 1574cadd4f8SNickeau 1584cadd4f8SNickeau public function __toString() 1594cadd4f8SNickeau { 1604cadd4f8SNickeau return "hsl($this->hue deg, $this->saturation%, $this->lightness%)"; 1614cadd4f8SNickeau } 1624cadd4f8SNickeau 1634cadd4f8SNickeau public function darken(int $lightness = 5): ColorHsl 1644cadd4f8SNickeau { 1654cadd4f8SNickeau if ($this->lightness - $lightness < 0) { 1664cadd4f8SNickeau $this->lightness = 0; 1674cadd4f8SNickeau } 1684cadd4f8SNickeau $this->lightness -= $lightness; 1694cadd4f8SNickeau return $this; 1704cadd4f8SNickeau } 1714cadd4f8SNickeau 1724cadd4f8SNickeau /** 173*04fd306cSNickeau * @throws ExceptionCompile 1744cadd4f8SNickeau */ 1754cadd4f8SNickeau public function diff($color): array 1764cadd4f8SNickeau { 1774cadd4f8SNickeau if ($color instanceof ColorRgb) { 1784cadd4f8SNickeau $color = $color->toHsl(); 1794cadd4f8SNickeau } 1804cadd4f8SNickeau 1814cadd4f8SNickeau return [ 1824cadd4f8SNickeau "h" => round($this->getHue() - $color->getHue(), 2), 1834cadd4f8SNickeau "s" => round($this->getSaturation() - $color->getSaturation(), 2), 1844cadd4f8SNickeau "l" => round($this->getLightness() - $color->getLightness(), 2), 1854cadd4f8SNickeau ]; 1864cadd4f8SNickeau } 1874cadd4f8SNickeau 1884cadd4f8SNickeau 1894cadd4f8SNickeau} 190