9 Commits
9 changed files with 755 additions and 191 deletions
@@ -0,0 +1,41 @@
<?php
namespace TorstenHettstedt\Colors\Transformer;
use TorstenHettstedt\Colors\ColorModels\CyanMagentaYellowKey;
use TorstenHettstedt\Colors\ColorModels\HueSaturationValue;
use TorstenHettstedt\Colors\ColorModels\RedGreenBlue;
class HueSaturationValueTransformer implements ColorModelTransformInterface
{
protected HueSaturationValue $color;
/**
* @param HueSaturationValue $color
*/
public function __construct(HueSaturationValue $color)
{
$this->color = $color;
}
public function toRedGreenBlue(): RedGreenBlue
{
$utility = new Utilities\HueSaturationValueToRedGreenBlue($this->color);
return $utility->convert();
}
public function toCyanMagentaYellowKey(): CyanMagentaYellowKey
{
$utility = new Utilities\HueSaturationValueToCyanMagentaYellowKey($this->color);
return $utility->convert();
}
public function toHueSaturationValue(): HueSaturationValue
{
return clone $this->color;
}
}
@@ -0,0 +1,42 @@
<?php
namespace TorstenHettstedt\Colors\Transformer;
use TorstenHettstedt\Colors\ColorModels\CyanMagentaYellowKey;
use TorstenHettstedt\Colors\ColorModels\HueSaturationValue;
use TorstenHettstedt\Colors\ColorModels\RedGreenBlue;
class RedGreenBlueTransformer implements ColorModelTransformInterface
{
protected RedGreenBlue $color;
/**
* @param RedGreenBlue $color
*/
public function __construct(RedGreenBlue $color)
{
$this->color = $color;
}
public function toRedGreenBlue(): RedGreenBlue
{
return clone $this->color;
}
public function toCyanMagentaYellowKey(): CyanMagentaYellowKey
{
$hsv_color = (new Utilities\RedGreenBlueToHueSaturationValue($this->color))->convert();
$utility = new Utilities\HueSaturationValueToCyanMagentaYellowKey($hsv_color);
return $utility->convert();
}
public function toHueSaturationValue(): HueSaturationValue
{
$utility = new Utilities\RedGreenBlueToHueSaturationValue($this->color);
return $utility->convert();
}
}
@@ -55,6 +55,9 @@ class CyanMagentaYellowKeyToHueSaturationValue
$this->minCmyProperty = min($this->cyan, $this->magenta, $this->yellow);
$this->hue = $this->buildHueAmount();
if ($this->hue === 1.0) {
$this->hue = 0.0;
}
$this->saturation = $this->maxCmyProperty;
$this->value = 1 - $this->key;
}
@@ -71,7 +74,7 @@ class CyanMagentaYellowKeyToHueSaturationValue
protected function buildHueAmount(): float
{
if ($this->maxCmyProperty === 0) {
if ($this->maxCmyProperty === 0.0) {
return 0.0;
}
@@ -88,10 +91,6 @@ class CyanMagentaYellowKeyToHueSaturationValue
*/
private function hueAmount(string $property): float
{
if ($this->maxCmyProperty === 0.0) {
return 0.0;
}
static $amount_share = 2.0;
$divisor = $this->maxCmyProperty - $this->minCmyProperty;
@@ -0,0 +1,110 @@
<?php
namespace TorstenHettstedt\Colors\Transformer\Utilities;
use TorstenHettstedt\Colors\ColorModels\CyanMagentaYellowKey;
use TorstenHettstedt\Colors\ColorModels\HueSaturationValue;
class HueSaturationValueToCyanMagentaYellowKey
{
/** @var int : Größe des Intervals in 1/100 Grad */
protected const INTERVAL = 60.0 * 100.0;
// Daten für HSV
/** @var float : Definition des Farbton als Anteil eines Vollkreises '$Hue * π' */
protected float $hue;
/** @var float : Anteil am Vollkreis in 1/100 Grad */
protected float $hueAsPercentGrad;
/** @var float : Definition der Sättigung der Farbe */
protected float $saturation;
/** @var float : Definition der Helligkeit der Farbe */
protected float $value;
// Daten für CMYK
/** @var float : Definition des Cyan-Anteil */
protected float $cyan = 0.0;
/** @var float : Definition des Magenta-Anteil */
protected float $magenta = 0.0;
/** @var float : Definition des Gelbanteil */
protected float $yellow = 0.0;
/** @var float : Definition des Schwarzanteil */
protected float $key = 0.0;
/**
* HueSaturationValueToRedGreenBlue constructor.
* @param HueSaturationValue $from_color
* @noinspection PhpPureAttributeCanBeAddedInspection
*/
public function __construct(HueSaturationValue $from_color)
{
$this->hue = $from_color->getHue();
$this->hueAsPercentGrad = intval($this->hue * self::INTERVAL * 6);
$this->saturation = $from_color->getSaturation();
$this->value = $from_color->getValue();
}
public function convert(): CyanMagentaYellowKey
{
$this->processConvert();
return (new CyanMagentaYellowKey())
->setCyan($this->cyan)
->setMagenta($this->magenta)
->setYellow($this->yellow)
->setKey($this->key);
}
protected function processConvert(): void
{
$this->key = 1 - $this->value;
if ($this->saturation !== 0.0) {
$this->splitColor();
}
}
protected function splitColor(): void
{
// ID des zu nutzenden Interval
$interval_id = intdiv($this->hueAsPercentGrad , self::INTERVAL);
switch ($interval_id) {
case 1: // Yellow
$this->cyan = $this->calcRemainder();
$this->yellow = $this->saturation;
break;
case 2:
$this->cyan = $this->saturation;
$this->yellow = $this->calcRemainder(true);
break;
case 3: // Cyan
$this->cyan = $this->saturation;
$this->magenta = $this->calcRemainder();
break;
case 4:
$this->cyan = $this->calcRemainder(true);
$this->magenta = $this->saturation;
break;
case 5: // Magenta
$this->magenta = $this->saturation;
$this->yellow = $this->calcRemainder();
break;
default:
$this->magenta = $this->calcRemainder(true);
$this->yellow = $this->saturation;
break;
}
}
protected function calcRemainder($reciprocal = false): float
{
// Rest-Anteil am Vollkreis des aktuellen Intervals als Wert '[0,1]'
$remainder_grad = $this->hueAsPercentGrad % self::INTERVAL;
// Rest-Anteil am Vollkreis des aktuellen Intervals als Wert '[0,1]'
$remainder = $remainder_grad / self::INTERVAL;
return $this->saturation * ($reciprocal ? (1 - $remainder) : $remainder);
}
}
@@ -0,0 +1,134 @@
<?php
namespace TorstenHettstedt\Colors\Transformer\Utilities;
use TorstenHettstedt\Colors\ColorModels\HueSaturationValue;
use TorstenHettstedt\Colors\ColorModels\RedGreenBlue;
class RedGreenBlueToHueSaturationValue
{
const PROPERTY_RED = 'red';
const PROPERTY_GREEN = 'green';
const PROPERTY_BLUE = 'blue';
// Daten für RGB
/** @var float : Definition des Rotanteil */
protected float $red;
/** @var float : Definition des Grünanteil */
protected float $green;
/** @var float : Definition des Blauanteil */
protected float $blu;
/** @var float : Der größte RGB-Farbwert */
protected float $maxRgbProperty;
/** @var float : Der kleinste RGB-Farbwert */
protected float $minRgbProperty;
// Daten für HSV
/** @var float : Definition des Farbton als Anteil eines Vollkreises '$Hue * π' */
protected float $hue = 0.0;
/** @var float : Definition der Sättigung der Farbe */
protected float $saturation = 0.0;
/** @var float : Definition der Helligkeit der Farbe */
protected float $value = 1.0;
/**
* CyanMagentaYellowKeyToHueSaturationValue constructor.
*
* @param RedGreenBlue $from_color
*
* @noinspection PhpPureAttributeCanBeAddedInspection
*/
public function __construct(RedGreenBlue $from_color)
{
$this->red = $from_color->getRed();
$this->green = $from_color->getGreen();
$this->blu = $from_color->getBlue();
}
protected function processConvert(): void
{
$this->maxRgbProperty = max($this->red, $this->green, $this->blu);
$this->minRgbProperty = min($this->red, $this->green, $this->blu);
$this->hue = $this->buildHueAmount();
$this->saturation = $this->buildSaturation();
$this->value = $this->maxRgbProperty;
while($this->hue < 0.0) {
$this->hue += 1.0;
}
while($this->hue > 1.0) {
$this->hue -= 1.0;
}
}
public function convert(): HueSaturationValue
{
$this->processConvert();
return (new HueSaturationValue())
->setHue($this->hue)
->setSaturation($this->saturation)
->setValue($this->value);
}
protected function buildHueAmount(): float
{
if ($this->maxRgbProperty === $this->minRgbProperty) {
return 0.0;
}
return match ($this->maxRgbProperty) {
$this->red => $this->hueAmount(self::PROPERTY_RED),
$this->green => $this->hueAmount(self::PROPERTY_GREEN),
default => $this->hueAmount(self::PROPERTY_BLUE),
};
}
protected function buildSaturation(): float
{
if ($this->maxRgbProperty === 0.0) {
return 0.0;
}
$dividend = $this->maxRgbProperty - $this->minRgbProperty;
return $dividend / $this->maxRgbProperty;
}
/**
* @param string $property : Name der CMYK-Eigenschaft
*
* @return float
*/
private function hueAmount(string $property): float
{
static $amount_share = 2.0;
$divisor = $this->maxRgbProperty - $this->minRgbProperty;
switch ($property) {
case self::PROPERTY_RED:
$amount = 0; // 0.0
$dividend = $this->green - $this->blu;
break;
case self::PROPERTY_GREEN:
$amount = 1; // 0.333
$dividend = $this->blu -$this->red;
break;
case self::PROPERTY_BLUE:
$amount = 2; // 0.999
$dividend = $this->red - $this->green;
break;
default:
return 0;
}
$start_amount = $amount * $amount_share;
$expansion_amount = $dividend / $divisor;
return ($start_amount + $expansion_amount) / 6.0;
}
}
@@ -19,99 +19,10 @@ class CyanMagentaYellowKeyTransformerTest extends Unit
*/
public function validRgbValuesProvider(): array
{
return [
'weiß' => [
[
'cyan' => 0.0,
'magenta' => 0.0,
'yellow' => 0.0,
'key' => 0.0,
],
[
'red' => 1.0,
'green' => 1.0,
'blue' => 1.0,
]
],
'schwarz' => [
[
'cyan' => 0.0,
'magenta' => 0.0,
'yellow' => 0.0,
'key' => 1.0,
],
[
'red' => 0.0,
'green' => 0.0,
'blue' => 0.0,
]
],
'cyan' => [
[
'cyan' => 1.0,
'magenta' => 0.0,
'yellow' => 0.0,
'key' => 0.0,
],
[
'red' => 0.0,
'green' => 1.0,
'blue' => 1.0,
]
],
'magenta' => [
[
'cyan' => 0.0,
'magenta' => 1.0,
'yellow' => 0.0,
'key' => 0.0,
],
[
'red' => 1.0,
'green' => 0.0,
'blue' => 1.0,
]
],
'gelb' => [
[
'cyan' => 0.0,
'magenta' => 0.0,
'yellow' => 1.0,
'key' => 0.0,
],
[
'red' => 1.0,
'green' => 1.0,
'blue' => 0.0,
]
],
'gold' => [
[
'cyan' => 0.0,
'magenta' => 0.13,
'yellow' => 0.76,
'key' => 0.13,
],
[
'red' => 0.87,
'green' => 0.757,
'blue' => 0.209,
]
],
'violet' => [
[
'cyan' => 0.19,
'magenta' => 0.32,
'yellow' => 0.0,
'key' => 0.29,
],
[
'red' => 0.575,
'green' => 0.482,
'blue' => 0.71,
]
],
];
return (new ValidColorValuesProvider())->getValidColorValues([
ValidColorValuesProvider::CMYK,
ValidColorValuesProvider::RGB
]);
}
/**
@@ -119,99 +30,10 @@ class CyanMagentaYellowKeyTransformerTest extends Unit
*/
public function validHsvValuesProvider(): array
{
return [
'weiß' => [
[
'cyan' => 0.0,
'magenta' => 0.0,
'yellow' => 0.0,
'key' => 0.0,
],
[
'hue' => 0.0,
'saturation' => 0.0,
'value' => 1.0,
]
],
'schwarz' => [
[
'cyan' => 0.0,
'magenta' => 0.0,
'yellow' => 0.0,
'key' => 1.0,
],
[
'hue' => 0.0,
'saturation' => 0.0,
'value' => 0.0,
]
],
'cyan' => [
[
'cyan' => 1.0,
'magenta' => 0.0,
'yellow' => 0.0,
'key' => 0.0,
],
[
'hue' => 0.5,
'saturation' => 1.0,
'value' => 1.0,
]
],
'magenta' => [
[
'cyan' => 0.0,
'magenta' => 1.0,
'yellow' => 0.0,
'key' => 0.0,
],
[
'hue' => 0.833,
'saturation' => 1.0,
'value' => 1.0,
]
],
'gelb' => [
[
'cyan' => 0.0,
'magenta' => 0.0,
'yellow' => 1.0,
'key' => 0.0,
],
[
'hue' => 0.167,
'saturation' => 1.0,
'value' => 1.0,
]
],
'gold' => [
[
'cyan' => 0.0,
'magenta' => 0.13,
'yellow' => 0.76,
'key' => 0.13,
],
[
'hue' => 0.138,
'saturation' => 0.76,
'value' => 0.87,
]
],
'violet' => [
[
'cyan' => 0.19,
'magenta' => 0.32,
'yellow' => 0.0,
'key' => 0.29,
],
[
'hue' => 0.734,
'saturation' => 0.32,
'value' => 0.71,
]
],
];
return (new ValidColorValuesProvider())->getValidColorValues([
ValidColorValuesProvider::CMYK,
ValidColorValuesProvider::HSV
]);
}
/**
@@ -0,0 +1,105 @@
<?php /** @noinspection PhpArrayShapeAttributeCanBeAddedInspection */
namespace TorstenHettstedtUnitTests\Colors\Transformer;
use Codeception\Test\Unit;
use Exception;
use TorstenHettstedt\Colors\ColorModels\HueSaturationValue;
use TorstenHettstedt\Colors\Transformer\HueSaturationValueTransformer;
class HueSaturationValueTransformerTest extends Unit
{
const FLOAT_DELTA = 0.001;
protected HueSaturationValue $color;
/**
* @return float[][][]
*/
public function validCmykValuesProvider(): array
{
return (new ValidColorValuesProvider())->getValidColorValues([
ValidColorValuesProvider::HSV,
ValidColorValuesProvider::CMYK,
]);
}
/**
* @return float[][][]
*/
public function validRgbValuesProvider(): array
{
return (new ValidColorValuesProvider())->getValidColorValues([
ValidColorValuesProvider::HSV,
ValidColorValuesProvider::RGB,
]);
}
/**
* @param array $hsv
* @param array $rgb
*
* @dataProvider validRgbValuesProvider
*
* @throws Exception
*/
public function testToRedGreenBlue(array $hsv, array $rgb)
{
$this->color = $this->make(HueSaturationValue::class, $hsv);
$transformer = new HueSaturationValueTransformer($this->color);
$color = $transformer->toRedGreenBlue();
$this->assertEqualsWithDelta($rgb['red'], $color->getRed(), self::FLOAT_DELTA);
$this->assertEqualsWithDelta($rgb['green'], $color->getGreen(), self::FLOAT_DELTA);
$this->assertEqualsWithDelta($rgb['blue'], $color->getBlue(), self::FLOAT_DELTA);
}
/**
* @param array $hsv
* @param array $cmyk
*
* @throws Exception
* @dataProvider validCmykValuesProvider
*
*/
public function testToCyanMagentaYellowKey(array $hsv, array $cmyk)
{
$this->color = $this->make(HueSaturationValue::class, $hsv);
$transformer = new HueSaturationValueTransformer($this->color);
$color = $transformer->toCyanMagentaYellowKey();
$this->assertEqualsWithDelta($cmyk['cyan'], $color->getCyan(), self::FLOAT_DELTA);
$this->assertEqualsWithDelta($cmyk['magenta'], $color->getMagenta(), self::FLOAT_DELTA);
$this->assertEqualsWithDelta($cmyk['yellow'], $color->getYellow(), self::FLOAT_DELTA);
$this->assertEqualsWithDelta($cmyk['key'], $color->getKey(), self::FLOAT_DELTA);
}
/**
* @param array $hsv
* @param array $cmyk
*
* @throws Exception
*
* @dataProvider validCmykValuesProvider
*
*/
public function testToHueSaturationValue(array $hsv, array $cmyk)
{
$this->color = $this->make(HueSaturationValue::class, $hsv);
$transformer = new HueSaturationValueTransformer($this->color);
$color = $transformer->toHueSaturationValue();
$this->assertEqualsWithDelta($hsv['hue'], $color->getHue(), self::FLOAT_DELTA);
$this->assertEqualsWithDelta($hsv['saturation'], $color->getSaturation(), self::FLOAT_DELTA);
$this->assertEqualsWithDelta($hsv['value'], $color->getValue(), self::FLOAT_DELTA);
}
}
@@ -0,0 +1,102 @@
<?php /** @noinspection PhpArrayShapeAttributeCanBeAddedInspection */
namespace TorstenHettstedtUnitTests\Colors\Transformer;
use Codeception\Test\Unit;
use Exception;
use TorstenHettstedt\Colors\ColorModels\RedGreenBlue;
use TorstenHettstedt\Colors\Transformer\RedGreenBlueTransformer;
class RedGreenBlueTransformerTest extends Unit
{
const FLOAT_DELTA = 0.001;
protected RedGreenBlue $color;
/**
* @return float[][][]
*/
public function validCmykValuesProvider(): array
{
return (new ValidColorValuesProvider())->getValidColorValues([
ValidColorValuesProvider::RGB,
ValidColorValuesProvider::CMYK,
]);
}
/**
* @return float[][][]
*/
public function validHsvValuesProvider(): array
{
return (new ValidColorValuesProvider())->getValidColorValues([
ValidColorValuesProvider::RGB,
ValidColorValuesProvider::HSV,
]);
}
/**
* @param array $rgb
*
* @dataProvider validCmykValuesProvider
*
* @throws Exception
*/
public function testToRedGreenBlue(array $rgb)
{
$this->color = $this->make(RedGreenBlue::class, $rgb);
$transformer = new RedGreenBlueTransformer($this->color);
$color = $transformer->toRedGreenBlue();
$this->assertEqualsWithDelta($rgb['red'], $color->getRed(), self::FLOAT_DELTA);
$this->assertEqualsWithDelta($rgb['green'], $color->getGreen(), self::FLOAT_DELTA);
$this->assertEqualsWithDelta($rgb['blue'], $color->getBlue(), self::FLOAT_DELTA);
}
/**
* @param array $rgb
* @param array $cmyk
*
* @throws Exception
* @dataProvider validCmykValuesProvider
*
*/
public function testToCyanMagentaYellowKey(array $rgb, array $cmyk)
{
$this->color = $this->make(RedGreenBlue::class, $rgb);
$transformer = new RedGreenBlueTransformer($this->color);
$color = $transformer->toCyanMagentaYellowKey();
$this->assertEqualsWithDelta($cmyk['cyan'], $color->getCyan(), self::FLOAT_DELTA);
$this->assertEqualsWithDelta($cmyk['magenta'], $color->getMagenta(), self::FLOAT_DELTA);
$this->assertEqualsWithDelta($cmyk['yellow'], $color->getYellow(), self::FLOAT_DELTA);
$this->assertEqualsWithDelta($cmyk['key'], $color->getKey(), self::FLOAT_DELTA);
}
/**
* @param array $rgb
* @param array $hsv
*
* @throws Exception
* @dataProvider validHsvValuesProvider
*/
public function testToHueSaturationValue(array $rgb, array $hsv)
{
$this->color = $this->make(RedGreenBlue::class, $rgb);
$transformer = new RedGreenBlueTransformer($this->color);
$color = $transformer->toHueSaturationValue();
$this->assertEqualsWithDelta($hsv['hue'], $color->getHue(), self::FLOAT_DELTA);
$this->assertEqualsWithDelta($hsv['saturation'], $color->getSaturation(), self::FLOAT_DELTA);
$this->assertEqualsWithDelta($hsv['value'], $color->getValue(), self::FLOAT_DELTA);
}
}
@@ -0,0 +1,209 @@
<?php
namespace TorstenHettstedtUnitTests\Colors\Transformer;
class ValidColorValuesProvider
{
const CMYK = 'cmyk';
const RGB = 'rgb';
const HSV = 'hsv';
protected array $definitions = [
'weiß' => [
self::CMYK => [
'cyan' => 0.0,
'magenta' => 0.0,
'yellow' => 0.0,
'key' => 0.0,
],
self::RGB => [
'red' => 1.0,
'green' => 1.0,
'blue' => 1.0,
],
self::HSV => [
'hue' => 0.0,
'saturation' => 0.0,
'value' => 1.0,
],
],
'schwarz' => [
self::CMYK => [
'cyan' => 0.0,
'magenta' => 0.0,
'yellow' => 0.0,
'key' => 1.0,
],
self::RGB => [
'red' => 0.0,
'green' => 0.0,
'blue' => 0.0,
],
self::HSV => [
'hue' => 0.0,
'saturation' => 0.0,
'value' => 0.0,
],
],
'gelb' => [
self::CMYK => [
'cyan' => 0.0,
'magenta' => 0.0,
'yellow' => 1.0,
'key' => 0.0,
],
self::RGB => [
'red' => 1.0,
'green' => 1.0,
'blue' => 0.0,
],
self::HSV => [
'hue' => 1.0 / 6.0,
'saturation' => 1.0,
'value' => 1.0,
],
],
'grün' => [
self::CMYK => [
'cyan' => 1.0,
'magenta' => 0.0,
'yellow' => 1.0,
'key' => 0.0,
],
self::RGB => [
'red' => 0.0,
'green' => 1.0,
'blue' => 0.0,
],
self::HSV => [
'hue' => 2.0 / 6.0,
'saturation' => 1.0,
'value' => 1.0,
],
],
'cyan' => [
self::CMYK => [
'cyan' => 1.0,
'magenta' => 0.0,
'yellow' => 0.0,
'key' => 0.0,
],
self::RGB => [
'red' => 0.0,
'green' => 1.0,
'blue' => 1.0,
],
self::HSV => [
'hue' => 3.0 / 6.0,
'saturation' => 1.0,
'value' => 1.0,
],
],
'blau' => [
self::CMYK => [
'cyan' => 1.0,
'magenta' => 1.0,
'yellow' => 0.0,
'key' => 0.0,
],
self::RGB => [
'red' => 0.0,
'green' => 0.0,
'blue' => 1.0,
],
self::HSV => [
'hue' => 4.0 / 6.0,
'saturation' => 1.0,
'value' => 1.0,
],
],
'magenta' => [
self::CMYK => [
'cyan' => 0.0,
'magenta' => 1.0,
'yellow' => 0.0,
'key' => 0.0,
],
self::RGB => [
'red' => 1.0,
'green' => 0.0,
'blue' => 1.0,
],
self::HSV => [
'hue' => 5.0 / 6.0,
'saturation' => 1.0,
'value' => 1.0,
],
],
'rot' => [
self::CMYK => [
'cyan' => 0.0,
'magenta' => 1.0,
'yellow' => 1.0,
'key' => 0.0,
],
self::RGB => [
'red' => 1.0,
'green' => 0.0,
'blue' => 0.0,
],
self::HSV => [
'hue' => 0.0,
'saturation' => 1.0,
'value' => 1.0,
],
],
'gold' => [
self::CMYK => [
'cyan' => 0.0,
'magenta' => 0.13,
'yellow' => 0.76,
'key' => 0.13,
],
self::RGB => [
'red' => 0.87,
'green' => 0.757,
'blue' => 0.209,
],
self::HSV => [
'hue' => 0.138,
'saturation' => 0.76,
'value' => 0.87,
],
],
'violet' => [
self::CMYK => [
'cyan' => 0.191,
'magenta' => 0.321,
'yellow' => 0.0,
'key' => 0.29,
],
self::RGB => [
'red' => 0.575,
'green' => 0.482,
'blue' => 0.71,
],
self::HSV => [
'hue' => 0.734,
'saturation' => 0.321,
'value' => 0.71,
],
],
];
public function getValidColorValues(array $order): array
{
$values = [];
foreach ($this->definitions as $color => $definition) {
$definitions = [];
foreach ($order as $key) {
$definitions[] = $definition[$key];
}
$values[$color] = $definitions;
}
return $values;
}
}