Convert\Color methods will throw Exception instead of false on error

All Color methods will throw Exceptions:
LengthException,
InvalidArgumentException,
UnexpectedValueException

instead of returning bool: false

All methods will return valid color data as expected only
This commit is contained in:
Clemens Schwaighofer
2023-08-31 10:45:33 +09:00
parent 8a33ee5c15
commit cd81d15d9a
3 changed files with 172 additions and 73 deletions

View File

@@ -59,6 +59,27 @@ final class CoreLibsConvertColorsTest extends TestCase
3 => false, 3 => false,
4 => false 4 => false
], ],
'invalid color red ' => [
0 => -12,
1 => 12,
2 => 12,
3 => false,
4 => false
],
'invalid color green ' => [
0 => 12,
1 => -12,
2 => 12,
3 => false,
4 => false
],
'invalid color blue ' => [
0 => 12,
1 => 12,
2 => -12,
3 => false,
4 => false
],
]; ];
} }
@@ -150,10 +171,40 @@ final class CoreLibsConvertColorsTest extends TestCase
'valid' => true, 'valid' => true,
], ],
// invalid values // invalid values
'invalid color' => [ 'invalid color r/h/h low' => [
'rgb' => [-12, 300, 12], 'rgb' => [-1, 12, 12],
'hsb' => [-12, 300, 12], 'hsb' => [-1, 50, 50],
'hsl' => [-12, 300, 12], 'hsl' => [-1, 50, 50],
'valid' => false,
],
'invalid color r/h/h high' => [
'rgb' => [256, 12, 12],
'hsb' => [361, 50, 50],
'hsl' => [361, 50, 50],
'valid' => false,
],
'invalid color g/s/s low' => [
'rgb' => [12, -1, 12],
'hsb' => [1, -1, 50],
'hsl' => [1, -1, 50],
'valid' => false,
],
'invalid color g/s/s high' => [
'rgb' => [12, 256, 12],
'hsb' => [1, 101, 50],
'hsl' => [1, 101, 50],
'valid' => false,
],
'invalid color b/b/l low' => [
'rgb' => [12, 12, -1],
'hsb' => [1, 50, -1],
'hsl' => [1, 50, -1],
'valid' => false,
],
'invalid color b/b/l high' => [
'rgb' => [12, 12, 256],
'hsb' => [1, 50, 101],
'hsl' => [1, 50, 101],
'valid' => false, 'valid' => false,
], ],
]; ];
@@ -246,11 +297,22 @@ final class CoreLibsConvertColorsTest extends TestCase
* @param int $input_r * @param int $input_r
* @param int $input_g * @param int $input_g
* @param int $input_b * @param int $input_b
* @param string|bool $expected_hash
* @param string|bool $expected * @param string|bool $expected
* @return void * @return void
*/ */
public function testRgb2hex(int $input_r, int $input_g, int $input_b, $expected_hash, $expected) public function testRgb2hex(
{ int $input_r,
int $input_g,
int $input_b,
string|bool $expected_hash,
string|bool $expected
) {
// if expected hash is or expected is false, we need to check for
// LengthException
if ($expected_hash === false || $expected === false) {
$this->expectException(\LengthException::class);
}
// with # // with #
$this->assertEquals( $this->assertEquals(
$expected_hash, $expected_hash,
@@ -292,11 +354,19 @@ final class CoreLibsConvertColorsTest extends TestCase
*/ */
public function testHex2rgb( public function testHex2rgb(
string $input, string $input,
$expected, array|bool $expected,
$expected_str, string|bool $expected_str,
string $separator, string $separator,
$expected_str_sep string|bool $expected_str_sep
): void { ): void {
if ($expected === false || $expected_str === false || $expected_str_sep === false) {
$hex_string = preg_replace("/[^0-9A-Fa-f]/", '', $input);
if (!is_string($hex_string)) {
$this->expectException(\InvalidArgumentException::class);
} else {
$this->expectException(\UnexpectedValueException::class);
}
}
$this->assertEquals( $this->assertEquals(
$expected, $expected,
\CoreLibs\Convert\Colors::hex2rgb($input) \CoreLibs\Convert\Colors::hex2rgb($input)
@@ -324,8 +394,11 @@ final class CoreLibsConvertColorsTest extends TestCase
* @param array|bool $expected * @param array|bool $expected
* @return void * @return void
*/ */
public function testRgb2hsb(int $input_r, int $input_g, int $input_b, $expected): void public function testRgb2hsb(int $input_r, int $input_g, int $input_b, array|bool $expected): void
{ {
if ($expected === false) {
$this->expectException(\LengthException::class);
}
$this->assertEquals( $this->assertEquals(
$expected, $expected,
\CoreLibs\Convert\Colors::rgb2hsb($input_r, $input_g, $input_b) \CoreLibs\Convert\Colors::rgb2hsb($input_r, $input_g, $input_b)
@@ -345,8 +418,12 @@ final class CoreLibsConvertColorsTest extends TestCase
* @param array|bool $expected * @param array|bool $expected
* @return void * @return void
*/ */
public function testHsb2rgb(float $input_h, float $input_s, float $input_b, $expected): void public function testHsb2rgb(float $input_h, float $input_s, float $input_b, array|bool $expected): void
{ {
if ($expected === false) {
$this->expectException(\LengthException::class);
$expected = [];
}
$this->assertEquals( $this->assertEquals(
$expected, $expected,
\CoreLibs\Convert\Colors::hsb2rgb($input_h, $input_s, $input_b) \CoreLibs\Convert\Colors::hsb2rgb($input_h, $input_s, $input_b)
@@ -366,8 +443,11 @@ final class CoreLibsConvertColorsTest extends TestCase
* @param array|bool $expected * @param array|bool $expected
* @return void * @return void
*/ */
public function testRgb2hsl(int $input_r, int $input_g, int $input_b, $expected): void public function testRgb2hsl(int $input_r, int $input_g, int $input_b, array|bool $expected): void
{ {
if ($expected === false) {
$this->expectException(\LengthException::class);
}
$this->assertEquals( $this->assertEquals(
$expected, $expected,
\CoreLibs\Convert\Colors::rgb2hsl($input_r, $input_g, $input_b) \CoreLibs\Convert\Colors::rgb2hsl($input_r, $input_g, $input_b)
@@ -387,8 +467,11 @@ final class CoreLibsConvertColorsTest extends TestCase
* @param array|bool $expected * @param array|bool $expected
* @return void * @return void
*/ */
public function testHsl2rgb($input_h, float $input_s, float $input_l, $expected): void public function testHsl2rgb(int|float $input_h, float $input_s, float $input_l, array|bool $expected): void
{ {
if ($expected === false) {
$this->expectException(\LengthException::class);
}
$this->assertEquals( $this->assertEquals(
$expected, $expected,
\CoreLibs\Convert\Colors::hsl2rgb($input_h, $input_s, $input_l) \CoreLibs\Convert\Colors::hsl2rgb($input_h, $input_s, $input_l)
@@ -406,11 +489,11 @@ final class CoreLibsConvertColorsTest extends TestCase
*/ */
public function testHslHsb360hue(): void public function testHslHsb360hue(): void
{ {
$this->assertNotFalse( $this->assertIsArray(
\CoreLibs\Convert\Colors::hsl2rgb(360.0, 90.5, 41.2), \CoreLibs\Convert\Colors::hsl2rgb(360.0, 90.5, 41.2),
'HSL to RGB with 360 hue' 'HSL to RGB with 360 hue'
); );
$this->assertNotFalse( $this->assertIsArray(
\CoreLibs\Convert\Colors::hsb2rgb(360, 95, 78.0), \CoreLibs\Convert\Colors::hsb2rgb(360, 95, 78.0),
'HSB to RGB with 360 hue' 'HSB to RGB with 360 hue'
); );

View File

@@ -39,8 +39,18 @@ print '<div><h1>' . $PAGE_NAME . '</h1></div>';
// define a list of from to color sets for conversion test // define a list of from to color sets for conversion test
// A(out of bounds) // A(out of bounds)
print "C::S/COLOR invalid rgb->hex (gray 125): -1, -1, -1: " . CoreLibs\Convert\Colors::rgb2hex(-1, -1, -1) . "<br>"; try {
print "\$C::S/COLOR invalid rgb->hex (gray 125): -1, -1, -1: " . $color_class::rgb2hex(-1, -1, -1) . "<br>"; print "C::S/COLOR invalid rgb->hex (gray 125): -1, -1, -1: "
. CoreLibs\Convert\Colors::rgb2hex(-1, -1, -1) . "<br>";
} catch (\LengthException $e) {
print "*Exception: " . $e->getMessage() . "<br>" . $e . "<br>";
}
try {
print "\$C::S/COLOR invalid rgb->hex (gray 125): -1, -1, -1: "
. $color_class::rgb2hex(-1, -1, -1) . "<br>";
} catch (\LengthException $e) {
print "**Exception: " . $e->getMessage() . "<br><pre>" . print_r($e, true) . "</pre><br>";
}
// B(valid) // B(valid)
$rgb = [10, 20, 30]; $rgb = [10, 20, 30];
$hex = '#0a141e'; $hex = '#0a141e';

View File

@@ -28,15 +28,15 @@ class Colors
* @param int $green green 0-255 * @param int $green green 0-255
* @param int $blue blue 0-255 * @param int $blue blue 0-255
* @param bool $hex_prefix default true, prefix with "#" * @param bool $hex_prefix default true, prefix with "#"
* @return string|false rgb in hex values with leading # if set, * @return string rgb in hex values with leading # if set,
* false for invalid color * @throws \LengthException If any argument is not in the range of 0~255
*/ */
public static function rgb2hex( public static function rgb2hex(
int $red, int $red,
int $green, int $green,
int $blue, int $blue,
bool $hex_prefix = true bool $hex_prefix = true
): string|false { ): string {
$hex_color = ''; $hex_color = '';
if ($hex_prefix === true) { if ($hex_prefix === true) {
$hex_color = '#'; $hex_color = '#';
@@ -44,7 +44,8 @@ class Colors
foreach (['red', 'green', 'blue'] as $color) { foreach (['red', 'green', 'blue'] as $color) {
// if not valid, abort // if not valid, abort
if ($$color < 0 || $$color > 255) { if ($$color < 0 || $$color > 255) {
return false; throw new \LengthException('Argument value ' . $$color . ' for color ' . $color
. ' is not in the range of 0 to 255');
} }
// pad left with 0 // pad left with 0
$hex_color .= str_pad(dechex($$color), 2, '0', STR_PAD_LEFT); $hex_color .= str_pad(dechex($$color), 2, '0', STR_PAD_LEFT);
@@ -55,37 +56,39 @@ class Colors
/** /**
* converts a hex RGB color to the int numbers * converts a hex RGB color to the int numbers
* *
* @param string $hexStr RGB hexstring * @param string $hex_string RGB hexstring
* @param bool $return_as_string flag to return as string * @param bool $return_as_string flag to return as string
* @param string $seperator string seperator: default: "," * @param string $seperator string seperator: default: ","
* @return string|array<string,float|int>|false false on error or array with RGB * @return string|array<string,float|int> array with RGB
* or a string with the seperator * or a string with the seperator
* @throws \InvalidArgumentException if hex string is empty
* @throws \UnexpectedValueException if the hex string value is not valid
*/ */
public static function hex2rgb( public static function hex2rgb(
string $hexStr, string $hex_string,
bool $return_as_string = false, bool $return_as_string = false,
string $seperator = ',' string $seperator = ','
): string|array|false { ): string|array {
$hexStr = preg_replace("/[^0-9A-Fa-f]/", '', $hexStr); // Gets a proper hex string $hex_string = preg_replace("/[^0-9A-Fa-f]/", '', $hex_string); // Gets a proper hex string
if (!is_string($hexStr)) { if (!is_string($hex_string)) {
return false; throw new \InvalidArgumentException('hex_string argument cannot be empty');
} }
$rgbArray = []; $rgbArray = [];
if (strlen($hexStr) == 6) { if (strlen($hex_string) == 6) {
// If a proper hex code, convert using bitwise operation. // If a proper hex code, convert using bitwise operation.
// No overhead... faster // No overhead... faster
$colorVal = hexdec($hexStr); $colorVal = hexdec($hex_string);
$rgbArray['r'] = 0xFF & ($colorVal >> 0x10); $rgbArray['r'] = 0xFF & ($colorVal >> 0x10);
$rgbArray['g'] = 0xFF & ($colorVal >> 0x8); $rgbArray['g'] = 0xFF & ($colorVal >> 0x8);
$rgbArray['b'] = 0xFF & $colorVal; $rgbArray['b'] = 0xFF & $colorVal;
} elseif (strlen($hexStr) == 3) { } elseif (strlen($hex_string) == 3) {
// If shorthand notation, need some string manipulations // If shorthand notation, need some string manipulations
$rgbArray['r'] = hexdec(str_repeat(substr($hexStr, 0, 1), 2)); $rgbArray['r'] = hexdec(str_repeat(substr($hex_string, 0, 1), 2));
$rgbArray['g'] = hexdec(str_repeat(substr($hexStr, 1, 1), 2)); $rgbArray['g'] = hexdec(str_repeat(substr($hex_string, 1, 1), 2));
$rgbArray['b'] = hexdec(str_repeat(substr($hexStr, 2, 1), 2)); $rgbArray['b'] = hexdec(str_repeat(substr($hex_string, 2, 1), 2));
} else { } else {
// Invalid hex color code // Invalid hex color code
return false; throw new \UnexpectedValueException('Invalid hex_string: ' . $hex_string);
} }
// returns the rgb string or the associative array // returns the rgb string or the associative array
return $return_as_string ? implode($seperator, $rgbArray) : $rgbArray; return $return_as_string ? implode($seperator, $rgbArray) : $rgbArray;
@@ -97,20 +100,21 @@ class Colors
* returns: * returns:
* array with hue (0-360), sat (0-100%), brightness/value (0-100%) * array with hue (0-360), sat (0-100%), brightness/value (0-100%)
* *
* @param int $red red 0-255 * @param int $red red 0-255
* @param int $green green 0-255 * @param int $green green 0-255
* @param int $blue blue 0-255 * @param int $blue blue 0-255
* @return array<int|float>|false Hue, Sat, Brightness/Value * @return array<int|float> Hue, Sat, Brightness/Value
* false for input value error * @throws \LengthException If any argument is not in the range of 0~255
*/ */
public static function rgb2hsb(int $red, int $green, int $blue): array|false public static function rgb2hsb(int $red, int $green, int $blue): array
{ {
// check that rgb is from 0 to 255 // check that rgb is from 0 to 255
foreach (['red', 'green', 'blue'] as $c) { foreach (['red', 'green', 'blue'] as $color) {
if ($$c < 0 || $$c > 255) { if ($$color < 0 || $$color > 255) {
return false; throw new \LengthException('Argument value ' . $$color . ' for color ' . $color
. ' is not in the range of 0 to 255');
} }
$$c = $$c / 255; $$color = $$color / 255;
} }
$MAX = max($red, $green, $blue); $MAX = max($red, $green, $blue);
@@ -144,13 +148,13 @@ class Colors
* converts HSB/V to RGB values RGB is full INT * converts HSB/V to RGB values RGB is full INT
* if HSB/V value is invalid, sets this value to 0 * if HSB/V value is invalid, sets this value to 0
* *
* @param float $H hue 0-360 (int) * @param float $H hue 0-360 (int)
* @param float $S saturation 0-100 (int) * @param float $S saturation 0-100 (int)
* @param float $V brightness/value 0-100 (int) * @param float $V brightness/value 0-100 (int)
* @return array<int>|false 0 red/1 green/2 blue array as 0-255 * @return array<int> 0 red/1 green/2 blue array as 0-255
* false for input value error * @throws \LengthException If any argument is not in the valid range
*/ */
public static function hsb2rgb(float $H, float $S, float $V): array|false public static function hsb2rgb(float $H, float $S, float $V): array
{ {
// check that H is 0 to 359, 360 = 0 // check that H is 0 to 359, 360 = 0
// and S and V are 0 to 1 // and S and V are 0 to 1
@@ -158,13 +162,13 @@ class Colors
$H = 0; $H = 0;
} }
if ($H < 0 || $H > 359) { if ($H < 0 || $H > 359) {
return false; throw new \LengthException('Argument value ' . $H . ' for hue is not in the range of 0 to 359');
} }
if ($S < 0 || $S > 100) { if ($S < 0 || $S > 100) {
return false; throw new \LengthException('Argument value ' . $S . ' for saturation is not in the range of 0 to 100');
} }
if ($V < 0 || $V > 100) { if ($V < 0 || $V > 100) {
return false; throw new \LengthException('Argument value ' . $V . ' for brightness is not in the range of 0 to 100');
} }
// convert to internal 0-1 format // convert to internal 0-1 format
$S /= 100; $S /= 100;
@@ -230,20 +234,21 @@ class Colors
* return: * return:
* array with hue (0-360), saturation (0-100%) and luminance (0-100%) * array with hue (0-360), saturation (0-100%) and luminance (0-100%)
* *
* @param int $red red 0-255 * @param int $red red 0-255
* @param int $green green 0-255 * @param int $green green 0-255
* @param int $blue blue 0-255 * @param int $blue blue 0-255
* @return array<float>|false hue/sat/luminance * @return array<float> hue/sat/luminance
* false for input value error * @throws \LengthException If any argument is not in the range of 0~255
*/ */
public static function rgb2hsl(int $red, int $green, int $blue): array|false public static function rgb2hsl(int $red, int $green, int $blue): array
{ {
// check that rgb is from 0 to 255 // check that rgb is from 0 to 255
foreach (['red', 'green', 'blue'] as $c) { foreach (['red', 'green', 'blue'] as $color) {
if ($$c < 0 || $$c > 255) { if ($$color < 0 || $$color > 255) {
return false; throw new \LengthException('Argument value ' . $$color . ' for color ' . $color
. ' is not in the range of 0 to 255');
} }
$$c = $$c / 255; $$color = $$color / 255;
} }
$min = min($red, $green, $blue); $min = min($red, $green, $blue);
@@ -284,24 +289,25 @@ class Colors
* converts an HSL to RGB * converts an HSL to RGB
* if HSL value is invalid, set this value to 0 * if HSL value is invalid, set this value to 0
* *
* @param float $hue hue: 0-360 (degrees) * @param float $hue hue: 0-360 (degrees)
* @param float $sat saturation: 0-100 * @param float $sat saturation: 0-100
* @param float $lum luminance: 0-100 * @param float $lum luminance: 0-100
* @return array<int,float|int>|false red/blue/green 0-255 each * @return array<int,float|int> red/blue/green 0-255 each
* @throws \LengthException If any argument is not in the valid range
*/ */
public static function hsl2rgb(float $hue, float $sat, float $lum): array|false public static function hsl2rgb(float $hue, float $sat, float $lum): array
{ {
if ($hue == 360) { if ($hue == 360) {
$hue = 0; $hue = 0;
} }
if ($hue < 0 || $hue > 359) { if ($hue < 0 || $hue > 359) {
return false; throw new \LengthException('Argument value ' . $hue . ' for hue is not in the range of 0 to 359');
} }
if ($sat < 0 || $sat > 100) { if ($sat < 0 || $sat > 100) {
return false; throw new \LengthException('Argument value ' . $sat . ' for saturation is not in the range of 0 to 100');
} }
if ($lum < 0 || $lum > 100) { if ($lum < 0 || $lum > 100) {
return false; throw new \LengthException('Argument value ' . $lum . ' for luminance is not in the range of 0 to 100');
} }
// calc to internal convert value for hue // calc to internal convert value for hue
$hue = (1 / 360) * $hue; $hue = (1 / 360) * $hue;