Color Coordinates class udpates

move creation into the main constructor and do not rely on "::create" or
any other pass through creation.

Make all constructors equal with options array so we can create an Interface

Remove all outsite setters. Once a color is set this color stays
This commit is contained in:
Clemens Schwaighofer
2024-11-14 14:51:31 +09:00
parent 32c192a362
commit 3845bc7ff5
11 changed files with 351 additions and 150 deletions

View File

@@ -83,7 +83,7 @@ class CieXyz
} }
/** /**
* Undocumented function * Convert from oklab to cie lab
* *
* @param Lab $lab * @param Lab $lab
* @return Lab * @return Lab
@@ -98,7 +98,7 @@ class CieXyz
} }
/** /**
* Undocumented function * Convert from cie lab to oklab
* *
* @param Lab $lab * @param Lab $lab
* @return Lab * @return Lab
@@ -122,14 +122,14 @@ class CieXyz
*/ */
private static function xyzD65ToXyzD50(XYZ $xyz): XYZ private static function xyzD65ToXyzD50(XYZ $xyz): XYZ
{ {
return XYZ::__constructFromArray(Math::multiplyMatrices( return new XYZ(Math::multiplyMatrices(
a: [ a: [
[1.0479298208405488, 0.022946793341019088, -0.05019222954313557], [1.0479298208405488, 0.022946793341019088, -0.05019222954313557],
[0.029627815688159344, 0.990434484573249, -0.01707382502938514], [0.029627815688159344, 0.990434484573249, -0.01707382502938514],
[-0.009243058152591178, 0.015055144896577895, 0.7518742899580008], [-0.009243058152591178, 0.015055144896577895, 0.7518742899580008],
], ],
b: $xyz->returnAsArray(), b: $xyz->returnAsArray(),
), whitepoint: 'D50'); ), options: ["whitepoint" => 'D50']);
} }
/** /**
@@ -140,14 +140,14 @@ class CieXyz
*/ */
private static function xyzD50ToXyxD65(XYZ $xyz): XYZ private static function xyzD50ToXyxD65(XYZ $xyz): XYZ
{ {
return XYZ::__constructFromArray(Math::multiplyMatrices( return new XYZ(Math::multiplyMatrices(
a: [ a: [
[0.9554734527042182, -0.023098536874261423, 0.0632593086610217], [0.9554734527042182, -0.023098536874261423, 0.0632593086610217],
[-0.028369706963208136, 1.0099954580058226, 0.021041398966943008], [-0.028369706963208136, 1.0099954580058226, 0.021041398966943008],
[0.012314001688319899, -0.020507696433477912, 1.3303659366080753], [0.012314001688319899, -0.020507696433477912, 1.3303659366080753],
], ],
b: $xyz->returnAsArray() b: $xyz->returnAsArray()
), whitepoint: 'D65'); ), options: ["whitepoint" => 'D65']);
} }
// MARK: xyzD50 <-> Lab // MARK: xyzD50 <-> Lab
@@ -184,7 +184,7 @@ class CieXyz
$_xyz, $_xyz,
); );
return Lab::__constructFromArray([ return new Lab([
(116 * $f[1]) - 16, (116 * $f[1]) - 16,
500 * ($f[0] - $f[1]), 500 * ($f[0] - $f[1]),
200 * ($f[1] - $f[2]), 200 * ($f[1] - $f[2]),
@@ -227,13 +227,13 @@ class CieXyz
(1.0 - 0.3457 - 0.3585) / 0.3585, (1.0 - 0.3457 - 0.3585) / 0.3585,
]; ];
return XYZ::__constructFromArray( return new XYZ(
array_map( array_map(
fn ($k, $v) => $v * $d50[$k], fn ($k, $v) => $v * $d50[$k],
array_keys($xyz), array_keys($xyz),
array_values($xyz), array_values($xyz),
), ),
whitepoint: 'D50' options: ["whitepoint" => 'D50']
); );
} }
@@ -252,14 +252,14 @@ class CieXyz
if (!$rgb->linear) { if (!$rgb->linear) {
$rgb->toLinear(); $rgb->toLinear();
} }
return XYZ::__constructFromArray(Math::multiplyMatrices( return new XYZ(Math::multiplyMatrices(
[ [
[0.41239079926595934, 0.357584339383878, 0.1804807884018343], [0.41239079926595934, 0.357584339383878, 0.1804807884018343],
[0.21263900587151027, 0.715168678767756, 0.07219231536073371], [0.21263900587151027, 0.715168678767756, 0.07219231536073371],
[0.01933081871559182, 0.11919477979462598, 0.9505321522496607], [0.01933081871559182, 0.11919477979462598, 0.9505321522496607],
], ],
$rgb->returnAsArray() $rgb->returnAsArray()
), whitepoint: 'D65'); ), options: ["whitepoint" => 'D65']);
} }
/** /**
@@ -271,14 +271,14 @@ class CieXyz
private static function xyzD65ToLinRgb(XYZ $xyz): RGB private static function xyzD65ToLinRgb(XYZ $xyz): RGB
{ {
// xyz D65 to linrgb // xyz D65 to linrgb
return RGB::__constructFromArray(Math::multiplyMatrices( return new RGB(Math::multiplyMatrices(
a : [ a : [
[ 3.2409699419045226, -1.537383177570094, -0.4986107602930034 ], [ 3.2409699419045226, -1.537383177570094, -0.4986107602930034 ],
[ -0.9692436362808796, 1.8759675015077202, 0.04155505740717559 ], [ -0.9692436362808796, 1.8759675015077202, 0.04155505740717559 ],
[ 0.05563007969699366, -0.20397695888897652, 1.0569715142428786 ], [ 0.05563007969699366, -0.20397695888897652, 1.0569715142428786 ],
], ],
b : $xyz->returnAsArray() b : $xyz->returnAsArray()
), linear: true); ), options: ["linear" => true]);
} }
// MARK: xyzD65 <-> OkLab // MARK: xyzD65 <-> OkLab
@@ -291,7 +291,7 @@ class CieXyz
*/ */
private static function xyzD65ToOkLab(XYZ $xyz): Lab private static function xyzD65ToOkLab(XYZ $xyz): Lab
{ {
return Lab::__constructFromArray(Math::multiplyMatrices( return new Lab(Math::multiplyMatrices(
[ [
[0.2104542553, 0.7936177850, -0.0040720468], [0.2104542553, 0.7936177850, -0.0040720468],
[1.9779984951, -2.4285922050, 0.4505937099], [1.9779984951, -2.4285922050, 0.4505937099],
@@ -319,7 +319,7 @@ class CieXyz
*/ */
private static function okLabToXyzD65(Lab $lab): XYZ private static function okLabToXyzD65(Lab $lab): XYZ
{ {
return XYZ::__constructFromArray(Math::multiplyMatrices( return new XYZ(Math::multiplyMatrices(
a: [ a: [
[1.2268798733741557, -0.5578149965554813, 0.28139105017721583], [1.2268798733741557, -0.5578149965554813, 0.28139105017721583],
[-0.04057576262431372, 1.1122868293970594, -0.07171106666151701], [-0.04057576262431372, 1.1122868293970594, -0.07171106666151701],
@@ -337,7 +337,7 @@ class CieXyz
b: $lab->returnAsArray(), b: $lab->returnAsArray(),
), ),
), ),
), whitepoint: 'D65'); ), options: ["whitepoint" => 'D65']);
} }
} }

View File

@@ -109,7 +109,7 @@ class Color
// achromatic // achromatic
if ($chroma == 0) { if ($chroma == 0) {
// H, S, L // H, S, L
return HSL::__constructFromArray([ return new HSL([
0.0, 0.0,
0.0, 0.0,
$lum * 100, $lum * 100,
@@ -128,7 +128,7 @@ class Color
} }
$hue = $hue * 60; $hue = $hue * 60;
// $sat = 1 - abs(2 * $lum - 1); // $sat = 1 - abs(2 * $lum - 1);
return HSL::__constructFromArray([ return new HSL([
$hue, $hue,
$sat * 100, $sat * 100,
$lum * 100, $lum * 100,
@@ -158,7 +158,7 @@ class Color
// if saturation is 0 // if saturation is 0
if ($sat == 0) { if ($sat == 0) {
$lum = round($lum * 255); $lum = round($lum * 255);
return RGB::__constructFromArray([$lum, $lum, $lum]); return new RGB([$lum, $lum, $lum]);
} else { } else {
$m2 = $lum < 0.5 ? $lum * ($sat + 1) : ($lum + $sat) - ($lum * $sat); $m2 = $lum < 0.5 ? $lum * ($sat + 1) : ($lum + $sat) - ($lum * $sat);
$m1 = $lum * 2 - $m2; $m1 = $lum * 2 - $m2;
@@ -180,7 +180,7 @@ class Color
return $m1; return $m1;
}; };
return RGB::__constructFromArray([ return new RGB([
255 * $hueue($hue + (1 / 3)), 255 * $hueue($hue + (1 / 3)),
255 * $hueue($hue), 255 * $hueue($hue),
255 * $hueue($hue - (1 / 3)), 255 * $hueue($hue - (1 / 3)),
@@ -212,7 +212,7 @@ class Color
// achromatic // achromatic
if ($MAX == $MIN) { if ($MAX == $MIN) {
return HSB::__constructFromArray([0, 0, $MAX * 100]); return new HSB([0, 0, $MAX * 100]);
} }
if ($red == $MAX) { if ($red == $MAX) {
$HUE = fmod(($green - $blue) / $DELTA, 6); $HUE = fmod(($green - $blue) / $DELTA, 6);
@@ -227,7 +227,7 @@ class Color
$HUE += 360; $HUE += 360;
} }
return HSB::__constructFromArray([ return new HSB([
$HUE, // Hue $HUE, // Hue
($DELTA / $MAX) * 100, // Saturation ($DELTA / $MAX) * 100, // Saturation
$MAX * 100, // Brightness $MAX * 100, // Brightness
@@ -255,7 +255,7 @@ class Color
if ($S == 0) { if ($S == 0) {
$V = $V * 255; $V = $V * 255;
return RGB::__constructFromArray([$V, $V, $V]); return new RGB([$V, $V, $V]);
} }
$Hi = floor($H / 60); $Hi = floor($H / 60);
@@ -301,7 +301,7 @@ class Color
$blue = 0; $blue = 0;
} }
return RGB::__constructFromArray([ return new RGB([
$red * 255, $red * 255,
$green * 255, $green * 255,
$blue * 255, $blue * 255,
@@ -365,7 +365,7 @@ class Color
0 : 0 :
200 * (1 - $lightness / $value); 200 * (1 - $lightness / $value);
$value *= 100; $value *= 100;
return HSB::__constructFromArray([ return new HSB([
$hsl->H, $hsl->H,
$saturation, $saturation,
$value, $value,
@@ -392,7 +392,7 @@ class Color
100 * ($value - $lightness) / min($lightness, 1 - $lightness) 100 * ($value - $lightness) / min($lightness, 1 - $lightness)
; ;
return HSL::__constructFromArray([ return new HSL([
$hue, $hue,
$saturation, $saturation,
$lightness * 100, $lightness * 100,
@@ -442,7 +442,7 @@ class Color
public static function hsbToHwb(HSB $hsb): HWB public static function hsbToHwb(HSB $hsb): HWB
{ {
// hsv\Hwb // hsv\Hwb
return HWB::__constructFromArray([ return new HWB([
$hsb->H, // hue, $hsb->H, // hue,
$hsb->B * (100 - $hsb->S) / 100, // 2: brightness, 1: saturation $hsb->B * (100 - $hsb->S) / 100, // 2: brightness, 1: saturation
100 - $hsb->B, 100 - $hsb->B,
@@ -473,7 +473,7 @@ class Color
$value *= 100; $value *= 100;
} }
return HSB::__constructFromArray([ return new HSB([
$hue, $hue,
$saturation, $saturation,
$value, $value,
@@ -491,7 +491,7 @@ class Color
public static function labToLch(Lab $lab): LCH public static function labToLch(Lab $lab): LCH
{ {
// cieLab to cieLch // cieLab to cieLch
return LCH::__constructFromArray(self::__labToLch($lab), colorspace: 'CIELab'); return new LCH(self::__labToLch($lab), colorspace: 'CIELab');
} }
/** /**
@@ -502,7 +502,7 @@ class Color
*/ */
public static function lchToLab(LCH $lch): Lab public static function lchToLab(LCH $lch): Lab
{ {
return Lab::__constructFromArray(self::__lchToLab($lch), colorspace: 'CIELab'); return new Lab(self::__lchToLab($lch), colorspace: 'CIELab');
} }
// MARK: OkLch <-> OkLab // MARK: OkLch <-> OkLab
@@ -516,7 +516,7 @@ class Color
public static function okLabToOkLch(Lab $lab): LCH public static function okLabToOkLch(Lab $lab): LCH
{ {
// okLab\toOkLch // okLab\toOkLch
return LCH::__constructFromArray(self::__labToLch($lab), colorspace: 'OkLab'); return new LCH(self::__labToLch($lab), colorspace: 'OkLab');
} }
/** /**
@@ -529,7 +529,7 @@ class Color
{ {
// oklch/toOkLab // oklch/toOkLab
// oklch to oklab // oklch to oklab
return Lab::__constructFromArray(self::__lchToLab($lch), colorspace: 'OkLab'); return new Lab(self::__lchToLab($lch), colorspace: 'OkLab');
} }
// MARK: rgb <-> oklab // MARK: rgb <-> oklab

View File

@@ -11,7 +11,7 @@ declare(strict_types=1);
namespace CoreLibs\Convert\Color\Coordinates; namespace CoreLibs\Convert\Color\Coordinates;
class HSB class HSB implements Interface\CoordinatesInterface
{ {
/** @var array<string> allowed colorspaces */ /** @var array<string> allowed colorspaces */
private const COLORSPACES = ['sRGB']; private const COLORSPACES = ['sRGB'];
@@ -29,22 +29,43 @@ class HSB
/** /**
* HSB (HSV) color coordinates * HSB (HSV) color coordinates
* Hue/Saturation/Brightness or Value * Hue/Saturation/Brightness or Value
*
* @param string|array{0:float,1:float,2:float} $colors
* @param string $colorspace [default=sRGB]
* @param array<string,string> $options [default=[]]
* @throws \InvalidArgumentException only array colors allowed
*/ */
public function __construct() public function __construct(string|array $colors, string $colorspace = 'sRGB', array $options = [])
{ {
if (!is_array($colors)) {
throw new \InvalidArgumentException('Only array colors allowed', 0);
}
$this->setColorspace($colorspace)->parseOptions($options)->setFromArray($colors);
} }
/** /**
* set from array * set from array
* where 0: Hue, 1: Saturation, 2: Brightness * where 0: Hue, 1: Saturation, 2: Brightness
* *
* @param array{0:float,1:float,2:float} $colors * @param string|array{0:float,1:float,2:float} $colors
* @param string $colorspace [default=sRGB] * @param string $colorspace [default=sRGB]
* @param array<string,string> $options [default=[]]
* @return self * @return self
*/ */
public static function __constructFromArray(array $colors, string $colorspace = 'sRGB'): self public static function create(string|array $colors, string $colorspace = 'sRGB', array $options = []): self
{ {
return (new HSB())->setColorspace($colorspace)->setFromArray($colors); return new HSB($colors, $colorspace, $options);
}
/**
* parse options
*
* @param array<string,string> $options
* @return self
*/
private function parseOptions(array $options): self
{
return $this;
} }
/** /**
@@ -54,7 +75,7 @@ class HSB
* @param float $value * @param float $value
* @return void * @return void
*/ */
public function __set(string $name, float $value): void private function set(string $name, float $value): void
{ {
$name = strtoupper($name); $name = strtoupper($name);
if (!property_exists($this, $name)) { if (!property_exists($this, $name)) {
@@ -65,9 +86,9 @@ class HSB
if ((int)$value == 360) { if ((int)$value == 360) {
$value = 0; $value = 0;
} }
if ((int)$value < 0 || (int)$value > 359) { if ((int)$value < 0 || (int)$value > 360) {
throw new \LengthException( throw new \LengthException(
'Argument value ' . $value . ' for hue is not in the range of 0 to 359', 'Argument value ' . $value . ' for hue is not in the range of 0 to 360',
1 1
); );
} }
@@ -98,7 +119,7 @@ class HSB
* @param string $name * @param string $name
* @return float * @return float
*/ */
public function __get(string $name): float public function __get(string $name): float|string|bool
{ {
$name = strtoupper($name); $name = strtoupper($name);
if (!property_exists($this, $name)) { if (!property_exists($this, $name)) {
@@ -140,11 +161,11 @@ class HSB
* @param array{0:float,1:float,2:float} $colors * @param array{0:float,1:float,2:float} $colors
* @return self * @return self
*/ */
public function setFromArray(array $colors): self private function setFromArray(array $colors): self
{ {
$this->__set('H', $colors[0]); $this->set('H', $colors[0]);
$this->__set('S', $colors[1]); $this->set('S', $colors[1]);
$this->__set('B', $colors[2]); $this->set('B', $colors[2]);
return $this; return $this;
} }

View File

@@ -13,7 +13,7 @@ namespace CoreLibs\Convert\Color\Coordinates;
use CoreLibs\Convert\Color\Stringify; use CoreLibs\Convert\Color\Stringify;
class HSL class HSL implements Interface\CoordinatesInterface
{ {
/** @var array<string> allowed colorspaces */ /** @var array<string> allowed colorspaces */
private const COLORSPACES = ['sRGB']; private const COLORSPACES = ['sRGB'];
@@ -31,22 +31,43 @@ class HSL
/** /**
* Color Coordinate HSL * Color Coordinate HSL
* Hue/Saturation/Lightness * Hue/Saturation/Lightness
*
* @param string|array{0:float,1:float,2:float} $colors
* @param string $colorspace [default=sRGB]
* @param array<string,string> $options [default=[]]
* @throws \InvalidArgumentException only array colors allowed
*/ */
public function __construct() public function __construct(string|array $colors, string $colorspace = 'sRGB', array $options = [])
{ {
if (!is_array($colors)) {
throw new \InvalidArgumentException('Only array colors allowed', 0);
}
$this->setColorspace($colorspace)->parseOptions($options)->setFromArray($colors);
} }
/** /**
* set from array * set from array
* where 0: Hue, 1: Saturation, 2: Lightness * where 0: Hue, 1: Saturation, 2: Lightness
* *
* @param array{0:float,1:float,2:float} $colors * @param string|array{0:float,1:float,2:float} $colors
* @param string $colorspace [default=sRGB] * @param string $colorspace [default=sRGB]
* @param array<string,string> $options [default=[]]
* @return self * @return self
*/ */
public static function __constructFromArray(array $colors, string $colorspace = 'sRGB'): self public static function create(string|array $colors, string $colorspace = 'sRGB', array $options = []): self
{ {
return (new HSL())->setColorspace($colorspace)->setFromArray($colors); return new HSL($colors, $colorspace, $options);
}
/**
* parse options
*
* @param array<string,string> $options
* @return self
*/
private function parseOptions(array $options): self
{
return $this;
} }
/** /**
@@ -56,7 +77,7 @@ class HSL
* @param float $value * @param float $value
* @return void * @return void
*/ */
public function __set(string $name, float $value): void private function set(string $name, float $value): void
{ {
if (!property_exists($this, $name)) { if (!property_exists($this, $name)) {
throw new \ErrorException('Creation of dynamic property is not allowed', 0); throw new \ErrorException('Creation of dynamic property is not allowed', 0);
@@ -66,9 +87,9 @@ class HSL
if ((int)$value == 360) { if ((int)$value == 360) {
$value = 0; $value = 0;
} }
if ((int)$value < 0 || (int)$value > 359) { if ((int)$value < 0 || (int)$value > 360) {
throw new \LengthException( throw new \LengthException(
'Argument value ' . $value . ' for hue is not in the range of 0 to 359', 'Argument value ' . $value . ' for hue is not in the range of 0 to 360',
1 1
); );
} }
@@ -84,7 +105,7 @@ class HSL
case 'L': case 'L':
if ((int)$value < 0 || (int)$value > 100) { if ((int)$value < 0 || (int)$value > 100) {
throw new \LengthException( throw new \LengthException(
'Argument value ' . $value . ' for luminance is not in the range of 0 to 100', 'Argument value ' . $value . ' for lightness is not in the range of 0 to 100',
3 3
); );
} }
@@ -99,7 +120,7 @@ class HSL
* @param string $name * @param string $name
* @return float * @return float
*/ */
public function __get(string $name): float public function __get(string $name): float|string|bool
{ {
if (!property_exists($this, $name)) { if (!property_exists($this, $name)) {
throw new \ErrorException('Creation of dynamic property is not allowed', 0); throw new \ErrorException('Creation of dynamic property is not allowed', 0);
@@ -140,11 +161,11 @@ class HSL
* @param array{0:float,1:float,2:float} $colors * @param array{0:float,1:float,2:float} $colors
* @return self * @return self
*/ */
public function setFromArray(array $colors): self private function setFromArray(array $colors): self
{ {
$this->__set('H', $colors[0]); $this->set('H', $colors[0]);
$this->__set('S', $colors[1]); $this->set('S', $colors[1]);
$this->__set('L', $colors[2]); $this->set('L', $colors[2]);
return $this; return $this;
} }

View File

@@ -13,7 +13,7 @@ namespace CoreLibs\Convert\Color\Coordinates;
use CoreLibs\Convert\Color\Stringify; use CoreLibs\Convert\Color\Stringify;
class HWB class HWB implements Interface\CoordinatesInterface
{ {
/** @var array<string> allowed colorspaces */ /** @var array<string> allowed colorspaces */
private const COLORSPACES = ['sRGB']; private const COLORSPACES = ['sRGB'];
@@ -31,22 +31,43 @@ class HWB
/** /**
* Color Coordinate: HWB * Color Coordinate: HWB
* Hue/Whiteness/Blackness * Hue/Whiteness/Blackness
*
* @param string|array{0:float,1:float,2:float} $colors
* @param string $colorspace [default=sRGB]
* @param array<string,string> $options [default=[]]
* @throws \InvalidArgumentException only array colors allowed
*/ */
public function __construct() public function __construct(string|array $colors, string $colorspace = 'sRGB', array $options = [])
{ {
if (!is_array($colors)) {
throw new \InvalidArgumentException('Only array colors allowed', 0);
}
$this->setColorspace($colorspace)->parseOptions($options)->setFromArray($colors);
} }
/** /**
* set from array * set from array
* where 0: Hue, 1: Whiteness, 2: Blackness * where 0: Hue, 1: Whiteness, 2: Blackness
* *
* @param array{0:float,1:float,2:float} $colors * @param string|array{0:float,1:float,2:float} $colors
* @param string $colorspace [default=sRGB] * @param string $colorspace [default=sRGB]
* @param array<string,string> $options [default=[]]
* @return self * @return self
*/ */
public static function __constructFromArray(array $colors, string $colorspace = 'sRGB'): self public static function create(string|array $colors, string $colorspace = 'sRGB', array $options = []): self
{ {
return (new HWB())->setColorspace($colorspace)->setFromArray($colors); return new HWB($colors, $colorspace, $options);
}
/**
* parse options
*
* @param array<string,string> $options
* @return self
*/
private function parseOptions(array $options): self
{
return $this;
} }
/** /**
@@ -56,7 +77,7 @@ class HWB
* @param float $value * @param float $value
* @return void * @return void
*/ */
public function __set(string $name, float $value): void private function set(string $name, float $value): void
{ {
if (!property_exists($this, $name)) { if (!property_exists($this, $name)) {
throw new \ErrorException('Creation of dynamic property is not allowed', 0); throw new \ErrorException('Creation of dynamic property is not allowed', 0);
@@ -76,7 +97,7 @@ class HWB
case 'W': case 'W':
if ((int)$value < 0 || (int)$value > 100) { if ((int)$value < 0 || (int)$value > 100) {
throw new \LengthException( throw new \LengthException(
'Argument value ' . $value . ' for saturation is not in the range of 0 to 100', 'Argument value ' . $value . ' for whiteness is not in the range of 0 to 100',
2 2
); );
} }
@@ -84,7 +105,7 @@ class HWB
case 'B': case 'B':
if ((int)$value < 0 || (int)$value > 100) { if ((int)$value < 0 || (int)$value > 100) {
throw new \LengthException( throw new \LengthException(
'Argument value ' . $value . ' for luminance is not in the range of 0 to 100', 'Argument value ' . $value . ' for blackness is not in the range of 0 to 100',
3 3
); );
} }
@@ -99,7 +120,7 @@ class HWB
* @param string $name * @param string $name
* @return float * @return float
*/ */
public function __get(string $name): float public function __get(string $name): float|string|bool
{ {
if (!property_exists($this, $name)) { if (!property_exists($this, $name)) {
throw new \ErrorException('Creation of dynamic property is not allowed', 0); throw new \ErrorException('Creation of dynamic property is not allowed', 0);
@@ -140,11 +161,11 @@ class HWB
* @param array{0:float,1:float,2:float} $colors * @param array{0:float,1:float,2:float} $colors
* @return self * @return self
*/ */
public function setFromArray(array $colors): self private function setFromArray(array $colors): self
{ {
$this->__set('H', $colors[0]); $this->set('H', $colors[0]);
$this->__set('W', $colors[1]); $this->set('W', $colors[1]);
$this->__set('B', $colors[2]); $this->set('B', $colors[2]);
return $this; return $this;
} }

View File

@@ -0,0 +1,53 @@
<?php
/**
* AUTHOR: Clemens Schwaighofer
* CREATED: Ymd
* DESCRIPTION:
* DescriptionHere
*/
declare(strict_types=1);
namespace CoreLibs\Convert\Color\Coordinates\Interface;
interface CoordinatesInterface
{
/**
* create class via "Class::create()" call
* was used for multiple create interfaces
* no longer needed, use "new Class()" instead
*
* @param string|array{0:float,1:float,2:float} $colors
* @param string $colorspace [default='']
* @param array<string,string|bool|int> $options [default=[]]
* @return self
*/
public static function create(string|array $colors, string $colorspace = '', array $options = []): self;
/**
* get color
*
* @param string $name
* @return float
*/
public function __get(string $name): float|string|bool;
/**
* Returns the color as array
* where 0: Lightness, 1: a, 2: b
*
* @return array{0:float,1:float,2:float}
*/
public function returnAsArray(): array;
/**
* Convert into css string with optional opacity
*
* @param null|float|string|null $opacity
* @return string
*/
public function toCssString(null|float|string $opacity = null): string;
}
// __END__

View File

@@ -14,7 +14,7 @@ namespace CoreLibs\Convert\Color\Coordinates;
use CoreLibs\Convert\Color\Stringify; use CoreLibs\Convert\Color\Stringify;
class LCH class LCH implements Interface\CoordinatesInterface
{ {
/** @var array<string> allowed colorspaces */ /** @var array<string> allowed colorspaces */
private const COLORSPACES = ['OkLab', 'CIELab']; private const COLORSPACES = ['OkLab', 'CIELab'];
@@ -42,22 +42,43 @@ class LCH
/** /**
* Color Coordinate Lch * Color Coordinate Lch
* for oklch * for oklch
*
* @param string|array{0:float,1:float,2:float} $colors
* @param string $colorspace [default='']
* @param array<string,string> $options [default=[]]
* @throws \InvalidArgumentException only array colors allowed
*/ */
public function __construct() public function __construct(string|array $colors, string $colorspace = '', array $options = [])
{ {
if (!is_array($colors)) {
throw new \InvalidArgumentException('Only array colors allowed', 0);
}
$this->setColorspace($colorspace)->parseOptions($options)->setFromArray($colors);
} }
/** /**
* set from array * set from array
* where 0: Lightness, 1: Chroma, 2: Hue * where 0: Lightness, 1: Chroma, 2: Hue
* *
* @param array{0:float,1:float,2:float} $colors * @param string|{0:float,1:float,2:float} $colors
* @param string $colorspace * @param string $colorspace [default='']
* @param array<string,string> $options [default=[]]
* @return self * @return self
*/ */
public static function __constructFromArray(array $colors, string $colorspace): self public static function create(string|array $colors, string $colorspace = '', array $options = []): self
{ {
return (new LCH())->setColorspace($colorspace)->setFromArray($colors); return new LCH($colors, $colorspace, $options);
}
/**
* parse options
*
* @param array<string,string> $options
* @return self
*/
private function parseOptions(array $options): self
{
return $this;
} }
/** /**
@@ -67,7 +88,7 @@ class LCH
* @param float $value * @param float $value
* @return void * @return void
*/ */
public function __set(string $name, float $value): void private function set(string $name, float $value): void
{ {
if (!property_exists($this, $name)) { if (!property_exists($this, $name)) {
throw new \ErrorException('Creation of dynamic property is not allowed', 0); throw new \ErrorException('Creation of dynamic property is not allowed', 0);
@@ -124,7 +145,7 @@ class LCH
* @param string $name * @param string $name
* @return float * @return float
*/ */
public function __get(string $name): float public function __get(string $name): float|string|bool
{ {
if (!property_exists($this, $name)) { if (!property_exists($this, $name)) {
throw new \ErrorException('Creation of dynamic property is not allowed', 0); throw new \ErrorException('Creation of dynamic property is not allowed', 0);
@@ -165,11 +186,11 @@ class LCH
* @param array{0:float,1:float,2:float} $colors * @param array{0:float,1:float,2:float} $colors
* @return self * @return self
*/ */
public function setFromArray(array $colors): self private function setFromArray(array $colors): self
{ {
$this->__set('L', $colors[0]); $this->set('L', $colors[0]);
$this->__set('C', $colors[1]); $this->set('C', $colors[1]);
$this->__set('H', $colors[2]); $this->set('H', $colors[2]);
return $this; return $this;
} }

View File

@@ -14,7 +14,7 @@ namespace CoreLibs\Convert\Color\Coordinates;
use CoreLibs\Convert\Color\Stringify; use CoreLibs\Convert\Color\Stringify;
class Lab class Lab implements Interface\CoordinatesInterface
{ {
/** @var array<string> allowed colorspaces */ /** @var array<string> allowed colorspaces */
private const COLORSPACES = ['OkLab', 'CIELab']; private const COLORSPACES = ['OkLab', 'CIELab'];
@@ -44,22 +44,43 @@ class Lab
/** /**
* Color Coordinate: Lab * Color Coordinate: Lab
* for oklab or cie * for oklab or cie
*
* @param string|array{0:float,1:float,2:float} $rgb
* @param string $colorspace [default='']
* @param array<string,string> $options [default=[]]
* @throws \InvalidArgumentException only array colors allowed
*/ */
public function __construct() public function __construct(string|array $colors, string $colorspace = '', array $options = [])
{ {
if (!is_array($colors)) {
throw new \InvalidArgumentException('Only array colors allowed', 0);
}
$this->setColorspace($colorspace)->parseOptions($options)->setFromArray($colors);
} }
/** /**
* set from array * set from array
* where 0: Lightness, 1: a, 2: b * where 0: Lightness, 1: a, 2: b
* *
* @param array{0:float,1:float,2:float} $rgb * @param array{0:float,1:float,2:float} $rgb
* @param string $colorspace * @param string $colorspace [default='']
* @param array<string,string> $options [default=[]]
* @return self * @return self
*/ */
public static function __constructFromArray(array $colors, string $colorspace): self public static function create(string|array $colors, string $colorspace = '', array $options = []): self
{ {
return (new Lab())->setColorspace($colorspace)->setFromArray($colors); return new Lab($colors, $colorspace, $options);
}
/**
* parse options
*
* @param array<string,string> $options
* @return self
*/
private function parseOptions(array $options): self
{
return $this;
} }
/** /**
@@ -69,7 +90,7 @@ class Lab
* @param float $value * @param float $value
* @return void * @return void
*/ */
public function __set(string $name, float $value): void private function set(string $name, float $value): void
{ {
if (!property_exists($this, $name)) { if (!property_exists($this, $name)) {
throw new \ErrorException('Creation of dynamic property is not allowed', 0); throw new \ErrorException('Creation of dynamic property is not allowed', 0);
@@ -112,7 +133,7 @@ class Lab
* @param string $name * @param string $name
* @return float * @return float
*/ */
public function __get(string $name): float public function __get(string $name): float|string|bool
{ {
if (!property_exists($this, $name)) { if (!property_exists($this, $name)) {
throw new \ErrorException('Creation of dynamic property is not allowed', 0); throw new \ErrorException('Creation of dynamic property is not allowed', 0);
@@ -153,11 +174,11 @@ class Lab
* @param array{0:float,1:float,2:float} $colors * @param array{0:float,1:float,2:float} $colors
* @return self * @return self
*/ */
public function setFromArray(array $colors): self private function setFromArray(array $colors): self
{ {
$this->__set('L', $colors[0]); $this->set('L', $colors[0]);
$this->__set('a', $colors[1]); $this->set('a', $colors[1]);
$this->__set('b', $colors[2]); $this->set('b', $colors[2]);
return $this; return $this;
} }

View File

@@ -13,7 +13,7 @@ namespace CoreLibs\Convert\Color\Coordinates;
use CoreLibs\Convert\Color\Stringify; use CoreLibs\Convert\Color\Stringify;
class RGB class RGB implements Interface\CoordinatesInterface
{ {
/** @var array<string> allowed colorspaces */ /** @var array<string> allowed colorspaces */
private const COLORSPACES = ['sRGB']; private const COLORSPACES = ['sRGB'];
@@ -33,41 +33,48 @@ class RGB
/** /**
* Color Coordinate RGB * Color Coordinate RGB
* @param array{0:float,1:float,2:float}|string $colors RGB color array or hex string
* @param string $colorspace [default=sRGB]
* @param array<string,bool> $options [default=[]] only "linear" allowed at the moment
*/ */
public function __construct() public function __construct(string|array $colors, string $colorspace = 'sRGB', array $options = [])
{ {
$this->setColorspace($colorspace)->parseOptions($options);
if (is_array($colors)) {
$this->setFromArray($colors);
} else {
$this->setFromHex($colors);
}
} }
/** /**
* set from array * set from array or string
* where 0: Red, 1: Green, 2: Blue * where 0: Red, 1: Green, 2: Blue
* OR #ffffff or ffffff
* *
* @param array{0:float,1:float,2:float} $colors * @param array{0:float,1:float,2:float}|string $colors RGB color array or hex string
* @param string $colorspace [default=sRGB] * @param string $colorspace [default=sRGB]
* @param bool $linear [default=false] * @param array<string,bool> $options [default=[]] only "linear" allowed at the moment
* @return self * @return self
*/ */
public static function __constructFromArray(array $colors, string $colorspace = 'sRGB', bool $linear = false): self public static function create(string|array $colors, string $colorspace = 'sRGB', array $options = []): self
{ {
return (new RGB())->setColorspace($colorspace)->flagLinear($linear)->setFromArray($colors); return new RGB($colors, $colorspace, $options);
} }
/** /**
* Undocumented function * parse options
* *
* @param string $hex_string * @param array<string,bool> $options
* @param string $colorspace
* @param bool $linear
* @return self * @return self
*/ */
public static function __constructFromHexString( private function parseOptions(array $options): self
string $hex_string, {
string $colorspace = 'sRGB', $this->flagLinear($options['linear'] ?? false);
bool $linear = false return $this;
): self {
return (new RGB())->setColorspace($colorspace)->flagLinear($linear)->setFromHex($hex_string);
} }
/** /**
* set color * set color
* *
@@ -75,7 +82,7 @@ class RGB
* @param float $value * @param float $value
* @return void * @return void
*/ */
public function __set(string $name, float $value): void private function set(string $name, float $value): void
{ {
// do not allow setting linear from outside // do not allow setting linear from outside
if ($name == 'linear') { if ($name == 'linear') {
@@ -90,7 +97,7 @@ class RGB
. ' is not in the range of 0 to 255', 1); . ' is not in the range of 0 to 255', 1);
} elseif ($this->linear && ((int)$value < 0 || (int)$value > 1)) { } elseif ($this->linear && ((int)$value < 0 || (int)$value > 1)) {
throw new \LengthException('Argument value ' . $value . ' for color ' . $name throw new \LengthException('Argument value ' . $value . ' for color ' . $name
. ' is not in the range of 0 to 1 for linear rgb', 1); . ' is not in the range of 0 to 1 for linear rgb', 2);
} }
$this->$name = $value; $this->$name = $value;
} }
@@ -101,7 +108,7 @@ class RGB
* @param string $name * @param string $name
* @return float|bool * @return float|bool
*/ */
public function __get(string $name): float|bool public function __get(string $name): float|string|bool
{ {
if (!property_exists($this, $name)) { if (!property_exists($this, $name)) {
throw new \ErrorException('Creation of dynamic property is not allowed', 0); throw new \ErrorException('Creation of dynamic property is not allowed', 0);
@@ -142,11 +149,11 @@ class RGB
* @param array{0:float,1:float,2:float} $colors * @param array{0:float,1:float,2:float} $colors
* @return self * @return self
*/ */
public function setFromArray(array $colors): self private function setFromArray(array $colors): self
{ {
$this->__set('R', $colors[0]); $this->set('R', $colors[0]);
$this->__set('G', $colors[1]); $this->set('G', $colors[1]);
$this->__set('B', $colors[2]); $this->set('B', $colors[2]);
return $this; return $this;
} }
@@ -179,11 +186,11 @@ class RGB
* @param string $hex_string * @param string $hex_string
* @return self * @return self
*/ */
public function setFromHex(string $hex_string): self private function setFromHex(string $hex_string): self
{ {
$hex_string = preg_replace("/[^0-9A-Fa-f]/", '', $hex_string); // Gets a proper hex string $hex_string = preg_replace("/[^0-9A-Fa-f]/", '', $hex_string); // Gets a proper hex string
if (!is_string($hex_string)) { if (empty($hex_string) || !is_string($hex_string)) {
throw new \InvalidArgumentException('hex_string argument cannot be empty', 1); throw new \InvalidArgumentException('hex_string argument cannot be empty', 3);
} }
$rgbArray = []; $rgbArray = [];
if (strlen($hex_string) == 6) { if (strlen($hex_string) == 6) {
@@ -204,7 +211,7 @@ class RGB
]; ];
} else { } else {
// Invalid hex color code // Invalid hex color code
throw new \UnexpectedValueException('Invalid hex_string: ' . $hex_string, 2); throw new \UnexpectedValueException('Invalid hex_string: ' . $hex_string, 4);
} }
return $this->setFromArray($rgbArray); return $this->setFromArray($rgbArray);
} }

View File

@@ -15,7 +15,7 @@ declare(strict_types=1);
namespace CoreLibs\Convert\Color\Coordinates; namespace CoreLibs\Convert\Color\Coordinates;
class XYZ class XYZ implements Interface\CoordinatesInterface
{ {
/** @var array<string> allowed colorspaces */ /** @var array<string> allowed colorspaces */
private const COLORSPACES = ['CIEXYZ']; private const COLORSPACES = ['CIEXYZ'];
@@ -35,34 +35,58 @@ class XYZ
/** @var string color space: either ok or cie */ /** @var string color space: either ok or cie */
private string $colorspace = ''; private string $colorspace = '';
/** @var string illuminat white point: only D50 and D65 are allowed */
private string $whitepoint = ''; private string $whitepoint = '';
/** /**
* Color Coordinate Lch * Color Coordinate Lch
* for oklch * for oklch conversion
*
* @param string|array{0:float,1:float,2:float} $colors
* @param string $colorspace [default=CIEXYZ]
* @param array<string,string> $options [default=[]] Only "whitepoint" option allowed
* @throws \InvalidArgumentException only array colors allowed
*/ */
public function __construct() public function __construct(
{ string|array $colors,
string $colorspace = 'CIEXYZ',
array $options = [],
) {
if (!is_array($colors)) {
throw new \InvalidArgumentException('Only array colors allowed', 0);
}
$this->setColorspace($colorspace)
->parseOptions($options)
->setFromArray($colors);
} }
/** /**
* set from array * set from array
* where 0: X, 1: Y, 2: Z * where 0: X, 1: Y, 2: Z
* *
* @param array{0:float,1:float,2:float} $colors * @param array{0:float,1:float,2:float} $colors
* @param string $colorspace [default=CIEXYZ] * @param string $colorspace [default=CIEXYZ]
* @param string $whitepoint [default=''] only D65 or D50 allowed * @param array<string,string> $options [default=[]] Only "whitepoint" option allowed
* @return self * @return self
*/ */
public static function __constructFromArray( public static function create(
array $colors, string|array $colors,
string $colorspace = 'CIEXYZ', string $colorspace = 'CIEXYZ',
string $whitepoint = '' array $options = [],
): self { ): self {
return (new XYZ()) return new XYZ($colors, $colorspace, $options);
->setColorspace($colorspace) }
->setWhitepoint($whitepoint)
->setFromArray($colors); /**
* parse options
*
* @param array<string,bool> $options
* @return self
*/
private function parseOptions(array $options): self
{
$this->setWhitepoint($options['whitepoint'] ?? '');
return $this;
} }
/** /**
@@ -72,7 +96,7 @@ class XYZ
* @param float $value * @param float $value
* @return void * @return void
*/ */
public function __set(string $name, float $value): void private function set(string $name, float $value): void
{ {
if (!property_exists($this, $name)) { if (!property_exists($this, $name)) {
throw new \ErrorException('Creation of dynamic property is not allowed', 0); throw new \ErrorException('Creation of dynamic property is not allowed', 0);
@@ -90,7 +114,7 @@ class XYZ
* @param string $name * @param string $name
* @return float * @return float
*/ */
public function __get(string $name): float public function __get(string $name): float|string|bool
{ {
if (!property_exists($this, $name)) { if (!property_exists($this, $name)) {
throw new \ErrorException('Creation of dynamic property is not allowed', 0); throw new \ErrorException('Creation of dynamic property is not allowed', 0);
@@ -150,13 +174,25 @@ class XYZ
* @param array{0:float,1:float,2:float} $colors * @param array{0:float,1:float,2:float} $colors
* @return self * @return self
*/ */
public function setFromArray(array $colors): self private function setFromArray(array $colors): self
{ {
$this->__set('X', $colors[0]); $this->set('X', $colors[0]);
$this->__set('Y', $colors[1]); $this->set('Y', $colors[1]);
$this->__set('Z', $colors[2]); $this->set('Z', $colors[2]);
return $this; return $this;
} }
/**
* no hsb in css
*
* @param float|string|null $opacity
* @return string
* @throws \ErrorException
*/
public function toCssString(null|float|string $opacity = null): string
{
throw new \ErrorException('XYZ is not available as CSS color string', 0);
}
} }
// __END__ // __END__

View File

@@ -40,7 +40,7 @@ class Colors
int $blue, int $blue,
bool $hex_prefix = true bool $hex_prefix = true
): string { ): string {
return Coordinates\RGB::__constructFromArray([$red, $green, $blue])->returnAsHex($hex_prefix); return (new Coordinates\RGB([$red, $green, $blue]))->returnAsHex($hex_prefix);
} }
/** /**
@@ -61,7 +61,7 @@ class Colors
): string|array { ): string|array {
$rgbArray = []; $rgbArray = [];
// rewrite to previous r/g/b key output // rewrite to previous r/g/b key output
foreach (Coordinates\RGB::__constructFromHexString($hex_string)->returnAsArray() as $p => $el) { foreach ((new Coordinates\RGB($hex_string))->returnAsArray() as $p => $el) {
switch ($p) { switch ($p) {
case 0: case 0:
$k = 'r'; $k = 'r';
@@ -96,7 +96,7 @@ class Colors
return array_map( return array_map(
fn ($v) => (int)round($v), fn ($v) => (int)round($v),
Color::rgbToHsb( Color::rgbToHsb(
Coordinates\RGB::__constructFromArray([$red, $green, $blue]) new Coordinates\RGB([$red, $green, $blue])
)->returnAsArray() )->returnAsArray()
); );
} }
@@ -117,7 +117,7 @@ class Colors
return array_map( return array_map(
fn ($v) => (int)round($v), fn ($v) => (int)round($v),
Color::hsbToRgb( Color::hsbToRgb(
Coordinates\HSB::__constructFromArray([$H, $S, $V]) new Coordinates\HSB([$H, $S, $V])
)->returnAsArray() )->returnAsArray()
); );
} }
@@ -138,7 +138,7 @@ class Colors
return array_map( return array_map(
fn ($v) => round($v, 1), fn ($v) => round($v, 1),
Color::rgbToHsl( Color::rgbToHsl(
Coordinates\RGB::__constructFromArray([$red, $green, $blue]) new Coordinates\RGB([$red, $green, $blue])
)->returnAsArray() )->returnAsArray()
); );
} }
@@ -158,7 +158,7 @@ class Colors
return array_map( return array_map(
fn ($v) => round($v), fn ($v) => round($v),
Color::hslToRgb( Color::hslToRgb(
Coordinates\HSL::__constructFromArray([$hue, $sat, $lum]) new Coordinates\HSL([$hue, $sat, $lum])
)->returnAsArray() )->returnAsArray()
); );
} }