Math: add epsilon compare for float, update Color Coordinate calls
Math has a compare with epsilon for float numbers. Use this for fixing sligth color conversion issues. NOTE: this might need some adjustment over time All phpunint tests written and checked
This commit is contained in:
@@ -72,7 +72,7 @@ print '<div><h1>' . $PAGE_NAME . '</h1></div>';
|
||||
|
||||
// define a list of from to color sets for conversion test
|
||||
|
||||
$hwb = Color::hsbToHwb(Coordinates\HSB::__constructFromArray([
|
||||
$hwb = Color::hsbToHwb(new Coordinates\HSB([
|
||||
160,
|
||||
0,
|
||||
50,
|
||||
@@ -81,7 +81,7 @@ print "HWB: " . DgS::printAr($hwb) . "<br>";
|
||||
$hsb = Color::hwbToHsb($hwb);
|
||||
print "HSB: " . DgS::printAr($hsb) . "<br>";
|
||||
|
||||
$oklch = Color::rgbToOkLch(Coordinates\RGB::__constructFromArray([
|
||||
$oklch = Color::rgbToOkLch(Coordinates\RGB::create([
|
||||
250,
|
||||
0,
|
||||
0
|
||||
@@ -90,7 +90,7 @@ print "OkLch: " . DgS::printAr($oklch) . "<br>";
|
||||
$rgb = Color::okLchToRgb($oklch);
|
||||
print "OkLch -> RGB: " . DgS::printAr($rgb) . "<br>";
|
||||
|
||||
$oklab = Color::rgbToOkLab(Coordinates\RGB::__constructFromArray([
|
||||
$oklab = Color::rgbToOkLab(Coordinates\RGB::create([
|
||||
250,
|
||||
0,
|
||||
0
|
||||
@@ -101,24 +101,24 @@ $rgb = Color::okLabToRgb($oklab);
|
||||
print "OkLab -> RGB: " . DgS::printAr($rgb) . "<br>";
|
||||
print display($rgb->toCssString(), $rgb->toCssString(), 'OkLab to RGB');
|
||||
|
||||
$rgb = Coordinates\RGB::__constructFromArray([250, 100, 10])->toLinear();
|
||||
$rgb = Coordinates\RGB::create([250, 100, 10])->toLinear();
|
||||
print "RGBlinear: " . DgS::printAr($rgb) . "<br>";
|
||||
$rgb = Coordinates\RGB::__constructFromArray([0, 0, 0])->toLinear();
|
||||
$rgb = Coordinates\RGB::create([0, 0, 0])->toLinear();
|
||||
print "RGBlinear: " . DgS::printAr($rgb) . "<br>";
|
||||
|
||||
$cie_lab = Color::okLabToLab($oklab);
|
||||
print "CieLab: " . DgS::printAr($cie_lab) . "<br>";
|
||||
print display($cie_lab->toCssString(), $cie_lab->toCssString(), 'OkLab to Cie Lab');
|
||||
|
||||
$rgb = Coordinates\RGB::__constructFromArray([0, 0, 60]);
|
||||
$rgb = Coordinates\RGB::create([0, 0, 60]);
|
||||
$hsb = Color::rgbToHsb($rgb);
|
||||
$rgb_b = Color::hsbToRgb($hsb);
|
||||
print "RGB: " . DgS::printAr($rgb) . "<br>";
|
||||
print "RGB->HSB: " . DgS::printAr($hsb) . "<br>";
|
||||
print "HSB->RGB: " . DgS::printAr($rgb_b) . "<br>";
|
||||
|
||||
$hsl = Coordinates\HSL::__constructFromArray([0, 20, 0]);
|
||||
$hsb = Coordinates\HSB::__constructFromArray([0, 20, 0]);
|
||||
$hsl = Coordinates\HSL::create([0, 20, 0]);
|
||||
$hsb = Coordinates\HSB::create([0, 20, 0]);
|
||||
$hsl_from_hsb = Color::hsbToHsl($hsb);
|
||||
print "HSL from HSB: " . DgS::printAr($hsl_from_hsb) . "<br>";
|
||||
|
||||
|
||||
@@ -250,7 +250,7 @@ class CieXyz
|
||||
{
|
||||
// if not linear, convert to linear
|
||||
if (!$rgb->linear) {
|
||||
$rgb->toLinear();
|
||||
$rgb = (new RGB($rgb->returnAsArray()))->toLinear();
|
||||
}
|
||||
return new XYZ(Math::multiplyMatrices(
|
||||
[
|
||||
|
||||
@@ -766,11 +766,6 @@ class Color
|
||||
public static function rgbToLab(RGB $rgb): Lab
|
||||
{
|
||||
return CieXyz::rgbViaXyzD65ViaXyzD50ToLab($rgb);
|
||||
/* return CieXyz::xyzD50ToLab(
|
||||
CieXyz::xyzD65ToXyzD50(
|
||||
CieXyz::linRgbToXyzD65($rgb)
|
||||
)
|
||||
); */
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -783,11 +778,6 @@ class Color
|
||||
public static function labToRgb(Lab $lab): RGB
|
||||
{
|
||||
return CieXyz::labViaXyzD50ViaXyzD65ToRgb($lab);
|
||||
/* return CieXyz::xyzD65ToLinRgb(
|
||||
CieXyz::xyzD50ToXyxD65(
|
||||
CieXyz::labToXyzD50($lab)
|
||||
)
|
||||
)->fromLinear(); */
|
||||
}
|
||||
|
||||
// MARK: RGB <-> Lch (Cie)
|
||||
|
||||
@@ -11,6 +11,8 @@ declare(strict_types=1);
|
||||
|
||||
namespace CoreLibs\Convert\Color\Coordinates;
|
||||
|
||||
use CoreLibs\Convert\Color\Utils;
|
||||
|
||||
class HSB implements Interface\CoordinatesInterface
|
||||
{
|
||||
/** @var array<string> allowed colorspaces */
|
||||
@@ -83,10 +85,11 @@ class HSB implements Interface\CoordinatesInterface
|
||||
}
|
||||
switch ($name) {
|
||||
case 'H':
|
||||
if ((int)$value == 360) {
|
||||
if ($value == 360.0) {
|
||||
$value = 0;
|
||||
}
|
||||
if ((int)$value < 0 || (int)$value > 360) {
|
||||
// if ($value < 0 || $value > 360) {
|
||||
if (Utils::compare(0.0, $value, 360.0, Utils::EPSILON_SMALL)) {
|
||||
throw new \LengthException(
|
||||
'Argument value ' . $value . ' for hue is not in the range of 0 to 360',
|
||||
1
|
||||
@@ -94,7 +97,8 @@ class HSB implements Interface\CoordinatesInterface
|
||||
}
|
||||
break;
|
||||
case 'S':
|
||||
if ((int)$value < 0 || (int)$value > 100) {
|
||||
// if ($value < 0 || $value > 100) {
|
||||
if (Utils::compare(0.0, $value, 100.0, Utils::EPSILON_SMALL)) {
|
||||
throw new \LengthException(
|
||||
'Argument value ' . $value . ' for saturation is not in the range of 0 to 100',
|
||||
2
|
||||
@@ -102,7 +106,8 @@ class HSB implements Interface\CoordinatesInterface
|
||||
}
|
||||
break;
|
||||
case 'B':
|
||||
if ((int)$value < 0 || (int)$value > 100) {
|
||||
// if ($value < 0 || $value > 100) {
|
||||
if (Utils::compare(0.0, $value, 100.0, Utils::EPSILON_SMALL)) {
|
||||
throw new \LengthException(
|
||||
'Argument value ' . $value . ' for brightness is not in the range of 0 to 100',
|
||||
3
|
||||
|
||||
@@ -11,7 +11,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace CoreLibs\Convert\Color\Coordinates;
|
||||
|
||||
use CoreLibs\Convert\Color\Stringify;
|
||||
use CoreLibs\Convert\Color\Utils;
|
||||
|
||||
class HSL implements Interface\CoordinatesInterface
|
||||
{
|
||||
@@ -84,10 +84,11 @@ class HSL implements Interface\CoordinatesInterface
|
||||
}
|
||||
switch ($name) {
|
||||
case 'H':
|
||||
if ((int)$value == 360) {
|
||||
if ($value == 360.0) {
|
||||
$value = 0;
|
||||
}
|
||||
if ((int)$value < 0 || (int)$value > 360) {
|
||||
// if ($value < 0 || $value > 360) {
|
||||
if (Utils::compare(0.0, $value, 360.0, Utils::EPSILON_SMALL)) {
|
||||
throw new \LengthException(
|
||||
'Argument value ' . $value . ' for hue is not in the range of 0 to 360',
|
||||
1
|
||||
@@ -95,7 +96,8 @@ class HSL implements Interface\CoordinatesInterface
|
||||
}
|
||||
break;
|
||||
case 'S':
|
||||
if ((int)$value < 0 || (int)$value > 100) {
|
||||
// if ($value < 0 || $value > 100) {
|
||||
if (Utils::compare(0.0, $value, 100.0, Utils::EPSILON_SMALL)) {
|
||||
throw new \LengthException(
|
||||
'Argument value ' . $value . ' for saturation is not in the range of 0 to 100',
|
||||
2
|
||||
@@ -103,7 +105,8 @@ class HSL implements Interface\CoordinatesInterface
|
||||
}
|
||||
break;
|
||||
case 'L':
|
||||
if ((int)$value < 0 || (int)$value > 100) {
|
||||
// if ($value < 0 || $value > 100) {
|
||||
if (Utils::compare(0.0, $value, 100.0, Utils::EPSILON_SMALL)) {
|
||||
throw new \LengthException(
|
||||
'Argument value ' . $value . ' for lightness is not in the range of 0 to 100',
|
||||
3
|
||||
@@ -183,7 +186,7 @@ class HSL implements Interface\CoordinatesInterface
|
||||
. $this->S
|
||||
. ' '
|
||||
. $this->L
|
||||
. Stringify::setOpacity($opacity)
|
||||
. Utils::setOpacity($opacity)
|
||||
. ')';
|
||||
return $string;
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace CoreLibs\Convert\Color\Coordinates;
|
||||
|
||||
use CoreLibs\Convert\Color\Stringify;
|
||||
use CoreLibs\Convert\Color\Utils;
|
||||
|
||||
class HWB implements Interface\CoordinatesInterface
|
||||
{
|
||||
@@ -84,10 +84,11 @@ class HWB implements Interface\CoordinatesInterface
|
||||
}
|
||||
switch ($name) {
|
||||
case 'H':
|
||||
if ((int)$value == 360) {
|
||||
if ($value == 360.0) {
|
||||
$value = 0;
|
||||
}
|
||||
if ((int)$value < 0 || (int)$value > 360) {
|
||||
// if ($value < 0 || $value > 360) {
|
||||
if (Utils::compare(0.0, $value, 360.0, Utils::EPSILON_SMALL)) {
|
||||
throw new \LengthException(
|
||||
'Argument value ' . $value . ' for hue is not in the range of 0 to 360',
|
||||
1
|
||||
@@ -95,7 +96,8 @@ class HWB implements Interface\CoordinatesInterface
|
||||
}
|
||||
break;
|
||||
case 'W':
|
||||
if ((int)$value < 0 || (int)$value > 100) {
|
||||
// if ($value < 0 || $value > 100) {
|
||||
if (Utils::compare(0.0, $value, 100.0, Utils::EPSILON_SMALL)) {
|
||||
throw new \LengthException(
|
||||
'Argument value ' . $value . ' for whiteness is not in the range of 0 to 100',
|
||||
2
|
||||
@@ -103,7 +105,8 @@ class HWB implements Interface\CoordinatesInterface
|
||||
}
|
||||
break;
|
||||
case 'B':
|
||||
if ((int)$value < 0 || (int)$value > 100) {
|
||||
// if ($value < 0 || $value > 100) {
|
||||
if (Utils::compare(0.0, $value, 100.0, Utils::EPSILON_SMALL)) {
|
||||
throw new \LengthException(
|
||||
'Argument value ' . $value . ' for blackness is not in the range of 0 to 100',
|
||||
3
|
||||
@@ -183,7 +186,7 @@ class HWB implements Interface\CoordinatesInterface
|
||||
. $this->W
|
||||
. ' '
|
||||
. $this->B
|
||||
. Stringify::setOpacity($opacity)
|
||||
. Utils::setOpacity($opacity)
|
||||
. ')';
|
||||
return $string;
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace CoreLibs\Convert\Color\Coordinates;
|
||||
|
||||
use CoreLibs\Convert\Color\Stringify;
|
||||
use CoreLibs\Convert\Color\Utils;
|
||||
|
||||
class LCH implements Interface\CoordinatesInterface
|
||||
{
|
||||
@@ -94,43 +94,43 @@ class LCH implements Interface\CoordinatesInterface
|
||||
throw new \ErrorException('Creation of dynamic property is not allowed', 0);
|
||||
}
|
||||
switch ($name) {
|
||||
// case 'L':
|
||||
// if ($this->colorspace == 'cie' && ($value < 0 || $value > 100)) {
|
||||
// throw new \LengthException(
|
||||
// 'Argument value ' . $value . ' for lightness is not in the range of '
|
||||
// . '0 to 100',
|
||||
// 3
|
||||
// );
|
||||
// } elseif ($this->colorspace == 'ok' && ($value < 0 || $value > 1)) {
|
||||
// throw new \LengthException(
|
||||
// 'Argument value ' . $value . ' for lightness is not in the range of '
|
||||
// . '0 to 1',
|
||||
// 3
|
||||
// );
|
||||
// }
|
||||
// break;
|
||||
// case 'c':
|
||||
// if ($this->colorspace == 'cie' && ($value < 0 || $value > 230)) {
|
||||
// throw new \LengthException(
|
||||
// 'Argument value ' . $value . ' for chroma is not in the range of '
|
||||
// . '0 to 230 with normal upper limit of 150',
|
||||
// 3
|
||||
// );
|
||||
// } elseif ($this->colorspace == 'ok' && ($value < 0 || $value > 0.5)) {
|
||||
// throw new \LengthException(
|
||||
// 'Argument value ' . $value . ' for chroma is not in the range of '
|
||||
// . '0 to 0.5 with normal upper limit of 0.5',
|
||||
// 3
|
||||
// );
|
||||
// }
|
||||
// break;
|
||||
case 'h':
|
||||
if ($value == 360) {
|
||||
$value = 0;
|
||||
}
|
||||
if ($value < 0 || $value > 360) {
|
||||
case 'L':
|
||||
// if ($this->colorspace == 'CIELab' && ($value < 0 || $value > 100)) {
|
||||
if ($this->colorspace == 'CIELab' && Utils::compare(0.0, $value, 100.0, Utils::ESPILON_BIG)) {
|
||||
throw new \LengthException(
|
||||
'Argument value ' . $value . ' for lightness is not in the range of 0 to 360',
|
||||
'Argument value ' . $value . ' for lightness is not in the range of 0 to 100 for CIE Lab',
|
||||
1
|
||||
);
|
||||
// } elseif ($this->colorspace == 'OkLab' && ($value < 0 || $value > 1)) {
|
||||
} elseif ($this->colorspace == 'OkLab' && Utils::compare(0.0, $value, 1.0, Utils::EPSILON_SMALL)) {
|
||||
throw new \LengthException(
|
||||
'Argument value ' . $value . ' for lightness is not in the range of 0.0 to 1.0 for OkLab',
|
||||
1
|
||||
);
|
||||
}
|
||||
break;
|
||||
case 'C':
|
||||
// if ($this->colorspace == 'CIELab' && ($value < 0 || $value > 230)) {
|
||||
if ($this->colorspace == 'CIELab' && Utils::compare(0.0, $value, 230.0, Utils::EPSILON_SMALL)) {
|
||||
throw new \LengthException(
|
||||
'Argument value ' . $value . ' for chroma is not in the range of '
|
||||
. '0 to 150 and a maximum of 230 for CIE Lab',
|
||||
1
|
||||
);
|
||||
// } elseif ($this->colorspace == 'OkLab' && ($value < 0 || $value > 0.55)) {
|
||||
} elseif ($this->colorspace == 'OkLab' && Utils::compare(0.0, $value, 0.55, Utils::EPSILON_SMALL)) {
|
||||
throw new \LengthException(
|
||||
'Argument value ' . $value . ' for lightness is not in the range of '
|
||||
. '0.0 to 0.4 and a maximum of 0.5 for OkLab',
|
||||
1
|
||||
);
|
||||
}
|
||||
break;
|
||||
case 'H':
|
||||
// if ($value < 0 || $value > 360) {
|
||||
if (Utils::compare(0.0, $value, 360.0, Utils::EPSILON_SMALL)) {
|
||||
throw new \LengthException(
|
||||
'Argument value ' . $value . ' for hue is not in the range of 0.0 to 360.0',
|
||||
1
|
||||
);
|
||||
}
|
||||
@@ -217,7 +217,7 @@ class LCH implements Interface\CoordinatesInterface
|
||||
. $this->c
|
||||
. ' '
|
||||
. $this->h
|
||||
. Stringify::setOpacity($opacity)
|
||||
. Utils::setOpacity($opacity)
|
||||
. ');';
|
||||
|
||||
return $string;
|
||||
|
||||
@@ -12,7 +12,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace CoreLibs\Convert\Color\Coordinates;
|
||||
|
||||
use CoreLibs\Convert\Color\Stringify;
|
||||
use CoreLibs\Convert\Color\Utils;
|
||||
|
||||
class Lab implements Interface\CoordinatesInterface
|
||||
{
|
||||
@@ -95,35 +95,53 @@ class Lab implements Interface\CoordinatesInterface
|
||||
if (!property_exists($this, $name)) {
|
||||
throw new \ErrorException('Creation of dynamic property is not allowed', 0);
|
||||
}
|
||||
// switch ($name) {
|
||||
// case 'L':
|
||||
// if ($value == 360) {
|
||||
// $value = 0;
|
||||
// }
|
||||
// if ($value < 0 || $value > 360) {
|
||||
// throw new \LengthException(
|
||||
// 'Argument value ' . $value . ' for lightness is not in the range of 0 to 360',
|
||||
// 1
|
||||
// );
|
||||
// }
|
||||
// break;
|
||||
// case 'a':
|
||||
// if ($value < 0 || $value > 100) {
|
||||
// throw new \LengthException(
|
||||
// 'Argument value ' . $value . ' for a is not in the range of 0 to 100',
|
||||
// 2
|
||||
// );
|
||||
// }
|
||||
// break;
|
||||
// case 'b':
|
||||
// if ($value < 0 || $value > 100) {
|
||||
// throw new \LengthException(
|
||||
// 'Argument value ' . $value . ' for b is not in the range of 0 to 100',
|
||||
// 3
|
||||
// );
|
||||
// }
|
||||
// break;
|
||||
// }
|
||||
switch ($name) {
|
||||
case 'L':
|
||||
// if ($this->colorspace == 'CIELab' && ($value < 0 || $value > 100)) {
|
||||
if ($this->colorspace == 'CIELab' && Utils::compare(0.0, $value, 100.0, Utils::ESPILON_BIG)) {
|
||||
throw new \LengthException(
|
||||
'Argument value ' . $value . ' for lightness is not in the range of 0 to 100 for CIE Lab',
|
||||
1
|
||||
);
|
||||
// } elseif ($this->colorspace == 'OkLab' && ($value < 0 || $value > 1)) {
|
||||
} elseif ($this->colorspace == 'OkLab' && Utils::compare(0.0, $value, 1.0, Utils::EPSILON_SMALL)) {
|
||||
throw new \LengthException(
|
||||
'Argument value ' . $value . ' for lightness is not in the range of 0.0 to 1.0 for OkLab',
|
||||
1
|
||||
);
|
||||
}
|
||||
break;
|
||||
case 'a':
|
||||
// if ($this->colorspace == 'CIELab' && ($value < -125 || $value > 125)) {
|
||||
if ($this->colorspace == 'CIELab' && Utils::compare(-125.0, $value, 125.0, Utils::EPSILON_SMALL)) {
|
||||
throw new \LengthException(
|
||||
'Argument value ' . $value . ' for a is not in the range of -125 to 125 for CIE Lab',
|
||||
2
|
||||
);
|
||||
// } elseif ($this->colorspace == 'OkLab' && ($value < -0.55 || $value > 0.55)) {
|
||||
} elseif ($this->colorspace == 'OkLab' && Utils::compare(-0.55, $value, 0.55, Utils::EPSILON_SMALL)) {
|
||||
throw new \LengthException(
|
||||
'Argument value ' . $value . ' for a is not in the range of -0.5 to 0.5 for OkLab',
|
||||
2
|
||||
);
|
||||
}
|
||||
break;
|
||||
case 'b':
|
||||
// if ($this->colorspace == 'CIELab' && ($value < -125 || $value > 125)) {
|
||||
if ($this->colorspace == 'CIELab' && Utils::compare(-125.0, $value, 125.0, Utils::EPSILON_SMALL)) {
|
||||
throw new \LengthException(
|
||||
'Argument value ' . $value . ' for b is not in the range of -125 to 125 for CIE Lab',
|
||||
3
|
||||
);
|
||||
// } elseif ($this->colorspace == 'OkLab' && ($value < -0.55 || $value > 0.55)) {
|
||||
} elseif ($this->colorspace == 'OkLab' && Utils::compare(-0.55, $value, 0.55, Utils::EPSILON_SMALL)) {
|
||||
throw new \LengthException(
|
||||
'Argument value ' . $value . ' for b is not in the range of -0.5 to 0.5 for OkLab',
|
||||
3
|
||||
);
|
||||
}
|
||||
break;
|
||||
}
|
||||
$this->$name = $value;
|
||||
}
|
||||
|
||||
@@ -205,7 +223,7 @@ class Lab implements Interface\CoordinatesInterface
|
||||
. $this->a
|
||||
. ' '
|
||||
. $this->b
|
||||
. Stringify::setOpacity($opacity)
|
||||
. Utils::setOpacity($opacity)
|
||||
. ');';
|
||||
|
||||
return $string;
|
||||
|
||||
@@ -11,7 +11,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace CoreLibs\Convert\Color\Coordinates;
|
||||
|
||||
use CoreLibs\Convert\Color\Stringify;
|
||||
use CoreLibs\Convert\Color\Utils;
|
||||
|
||||
class RGB implements Interface\CoordinatesInterface
|
||||
{
|
||||
@@ -94,8 +94,11 @@ class RGB implements Interface\CoordinatesInterface
|
||||
// if not linear
|
||||
if (!$this->linear && ((int)$value < 0 || (int)$value > 255)) {
|
||||
throw new \LengthException('Argument value ' . $value . ' for color ' . $name
|
||||
. ' is not in the range of 0 to 255', 1);
|
||||
} elseif ($this->linear && ((int)$value < 0 || (int)$value > 1)) {
|
||||
. ' is not in the range of 0 to 255', 1);
|
||||
} elseif (
|
||||
// $this->linear && ($value < 0.0 || $value > 1.0)
|
||||
$this->linear && Utils::compare(0.0, $value, 1.0, 0.000001)
|
||||
) {
|
||||
throw new \LengthException('Argument value ' . $value . ' for color ' . $name
|
||||
. ' is not in the range of 0 to 1 for linear rgb', 2);
|
||||
}
|
||||
@@ -244,6 +247,10 @@ class RGB implements Interface\CoordinatesInterface
|
||||
*/
|
||||
public function toLinear(): self
|
||||
{
|
||||
// if linear, as is
|
||||
if ($this->linear) {
|
||||
return $this;
|
||||
}
|
||||
$this->flagLinear(true)->setFromArray(array_map(
|
||||
callback: function (int|float $v) {
|
||||
$v = (float)($v / 255);
|
||||
@@ -268,6 +275,10 @@ class RGB implements Interface\CoordinatesInterface
|
||||
*/
|
||||
public function fromLinear(): self
|
||||
{
|
||||
// if not linear, as is
|
||||
if (!$this->linear) {
|
||||
return $this;
|
||||
}
|
||||
$this->flagLinear(false)->setFromArray(array_map(
|
||||
callback: function (int|float $v) {
|
||||
$abs = abs($v);
|
||||
@@ -282,7 +293,6 @@ class RGB implements Interface\CoordinatesInterface
|
||||
},
|
||||
array: $this->returnAsArray(),
|
||||
));
|
||||
// $this->linear = false;
|
||||
return $this;
|
||||
}
|
||||
|
||||
@@ -307,7 +317,7 @@ class RGB implements Interface\CoordinatesInterface
|
||||
. (int)round($this->G, 0)
|
||||
. ' '
|
||||
. (int)round($this->B, 0)
|
||||
. Stringify::setOpacity($opacity)
|
||||
. Utils::setOpacity($opacity)
|
||||
. ')';
|
||||
if ($was_linear) {
|
||||
$this->toLinear();
|
||||
|
||||
@@ -15,6 +15,8 @@ declare(strict_types=1);
|
||||
|
||||
namespace CoreLibs\Convert\Color\Coordinates;
|
||||
|
||||
// use CoreLibs\Convert\Color\Utils;
|
||||
|
||||
class XYZ implements Interface\CoordinatesInterface
|
||||
{
|
||||
/** @var array<string> allowed colorspaces */
|
||||
@@ -101,9 +103,11 @@ class XYZ implements Interface\CoordinatesInterface
|
||||
if (!property_exists($this, $name)) {
|
||||
throw new \ErrorException('Creation of dynamic property is not allowed', 0);
|
||||
}
|
||||
// if ($value < 0 || $value > 255) {
|
||||
// TODO: setup XYZ value limits
|
||||
// X: 0 to 95.047, Y: 0 to 100, Z: 0 to 108.88
|
||||
// if (Utils::compare(0.0, $value, 100.0, Utils::EPSILON_SMALL))) {
|
||||
// throw new \LengthException('Argument value ' . $value . ' for color ' . $name
|
||||
// . ' is not in the range of 0 to 255', 1);
|
||||
// . ' is not in the range of 0 to 100.0', 1);
|
||||
// }
|
||||
$this->$name = $value;
|
||||
}
|
||||
|
||||
@@ -19,25 +19,6 @@ use CoreLibs\Convert\Color\Coordinates\LCH;
|
||||
|
||||
class Stringify
|
||||
{
|
||||
/**
|
||||
* Build the opactiy sub string part and return it
|
||||
*
|
||||
* @param null|float|string|null $opacity
|
||||
* @return string
|
||||
*/
|
||||
public static function setOpacity(null|float|string $opacity = null): string
|
||||
{
|
||||
// set opacity, either a string or float
|
||||
if (is_string($opacity)) {
|
||||
$opacity = ' / ' . $opacity;
|
||||
} elseif ($opacity !== null) {
|
||||
$opacity = ' / ' . $opacity;
|
||||
} else {
|
||||
$opacity = '';
|
||||
}
|
||||
return $opacity;
|
||||
}
|
||||
|
||||
/**
|
||||
* return the CSS string including optional opacity
|
||||
*
|
||||
|
||||
56
www/lib/CoreLibs/Convert/Color/Utils.php
Normal file
56
www/lib/CoreLibs/Convert/Color/Utils.php
Normal file
@@ -0,0 +1,56 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* AUTHOR: Clemens Schwaighofer
|
||||
* CREATED: 2024/11/14
|
||||
* DESCRIPTION:
|
||||
* Utils for color
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace CoreLibs\Convert\Color;
|
||||
|
||||
use CoreLibs\Convert\Math;
|
||||
|
||||
class Utils
|
||||
{
|
||||
/** @var int deviation allowed for valid data checks, small */
|
||||
public const EPSILON_SMALL = 0.000000000001;
|
||||
/** @var int deviation allowed for valid data checks, medium */
|
||||
public const EPSILON_MEDIUM = 0.0000001;
|
||||
/** @var int deviation allowed for valid data checks, big */
|
||||
public const ESPILON_BIG = 0.0001;
|
||||
|
||||
public static function compare(float $lower, float $value, float $upper, float $epslion): bool
|
||||
{
|
||||
if (
|
||||
Math::compareWithEpsilon($value, '<', $lower, $epslion) ||
|
||||
Math::compareWithEpsilon($value, '>', $upper, $epslion)
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the opactiy sub string part and return it
|
||||
*
|
||||
* @param null|float|string|null $opacity
|
||||
* @return string
|
||||
*/
|
||||
public static function setOpacity(null|float|string $opacity = null): string
|
||||
{
|
||||
// set opacity, either a string or float
|
||||
if (is_string($opacity)) {
|
||||
$opacity = ' / ' . $opacity;
|
||||
} elseif ($opacity !== null) {
|
||||
$opacity = ' / ' . $opacity;
|
||||
} else {
|
||||
$opacity = '';
|
||||
}
|
||||
return $opacity;
|
||||
}
|
||||
}
|
||||
|
||||
// __END__
|
||||
@@ -68,6 +68,66 @@ class Math
|
||||
return pow((float)$number, 1.0 / 3);
|
||||
}
|
||||
|
||||
/**
|
||||
* use PHP_FLOAT_EPSILON to compare if two float numbers are matching
|
||||
*
|
||||
* @param float $x
|
||||
* @param float $y
|
||||
* @param float $epsilon [default=PHP_FLOAT_EPSILON]
|
||||
* @return bool True equal
|
||||
*/
|
||||
public static function equalWithEpsilon(float $x, float $y, float $epsilon = PHP_FLOAT_EPSILON): bool
|
||||
{
|
||||
if (abs($x - $y) < $epsilon) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compare two value base on direction given
|
||||
* The default delta is PHP_FLOAT_EPSILON
|
||||
*
|
||||
* @param float $value
|
||||
* @param string $compare
|
||||
* @param float $limit
|
||||
* @param float $epsilon [default=PHP_FLOAT_EPSILON]
|
||||
* @return bool True on smaller/large or equal
|
||||
*/
|
||||
public static function compareWithEpsilon(
|
||||
float $value,
|
||||
string $compare,
|
||||
float $limit,
|
||||
float $epsilon = PHP_FLOAT_EPSILON
|
||||
): bool {
|
||||
switch ($compare) {
|
||||
case '<':
|
||||
if ($value < ($limit - $epsilon)) {
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case '<=':
|
||||
if ($value <= ($limit - $epsilon)) {
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case '==':
|
||||
return self::equalWithEpsilon($value, $limit, $epsilon);
|
||||
break;
|
||||
case '>':
|
||||
if ($value > ($limit + $epsilon)) {
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case '>=':
|
||||
if ($value >= ($limit + $epsilon)) {
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function is directly inspired by the multiplyMatrices() function in color.js
|
||||
* form Lea Verou and Chris Lilley.
|
||||
|
||||
Reference in New Issue
Block a user