Вход Регистрация
Файл: vendor/intervention/image/src/Colors/Hsv/Colorspace.php
Строк: 225
<?php

declare(strict_types=1);

namespace 
InterventionImageColorsHsv;

use 
InterventionImageColorsAbstractColorspace;
use 
InterventionImageColorsCmykColor as CmykColor;
use 
InterventionImageColorsHslColor as HslColor;
use 
InterventionImageColorsHsvColor as HsvColor;
use 
InterventionImageColorsOklabColor as OklabColor;
use 
InterventionImageColorsOklchColor as OklchColor;
use 
InterventionImageColorsRgbColor as RgbColor;
use 
InterventionImageColorsRgbColorspace as RgbColorspace;
use 
InterventionImageColorsRgbNamedColor;
use 
InterventionImageExceptionsColorException;
use 
InterventionImageExceptionsInvalidArgumentException;
use 
InterventionImageInterfacesColorChannelInterface;
use 
InterventionImageInterfacesColorInterface;
use 
TypeError;

class 
Colorspace extends AbstractColorspace
{
    
/**
     * Channel class names of colorspace.
     *
     * @var array<string>
     */
    
public static array $channels = [
        
ChannelsHue::class,
        
ChannelsSaturation::class,
        
ChannelsValue::class,
        
ChannelsAlpha::class,
    ];

    
/**
     * {@inheritdoc}
     *
     * @see ColorspaceInterface::colorFromNormalized()
     *
     * @throws InvalidArgumentException
     */
    
public static function colorFromNormalized(array $normalized): HsvColor
    
{
        if (!
in_array(count($normalized), [3, 4])) {
            throw new 
InvalidArgumentException('Number of color channels must be 3 or 4 for ' . static::class);
        }

        
// add alpha value if missing
        
$normalized = count($normalized) === 3 ? array_pad($normalized, 4, 1) : $normalized;

        return new 
Color(...array_map(
            function (
string $channel, null|float $normalized) {
                try {
                    return 
$channel::fromNormalized($normalized);
                } catch (
TypeError $e) {
                    throw new 
InvalidArgumentException(
                        
'Normalized color value must be in range 0 to 1',
                        
previous: $e,
                    );
                }
            },
            
self::$channels,
            
$normalized,
        ));
    }

    
/**
     * {@inheritdoc}
     *
     * @see ColorspaceInterface::importColor()
     *
     * @throws InvalidArgumentException
     * @throws ColorException
     */
    
public function importColor(ColorInterface $color): HsvColor
    
{
        return 
match ($color::class) {
            
CmykColor::class,
            
OklchColor::class,
            
NamedColor::class,
            
OklabColor::class => $this->importViaRgbColor($color),
            
RgbColor::class => $this->importRgbColor($color),
            
HslColor::class => $this->importHslColor($color),
            
HsvColor::class => $color,
            default => throw new 
ColorException(
                
'Unable to import color ' . $color::class . ' to ' . $this::class,
            ),
        };
    }

    
/**
     * Import given RGB color to HSV colorspace.
     *
     * @throws ColorException
     */
    
private function importRgbColor(RgbColor $color): HsvColor
    
{
        
// normalized values of rgb channels
        
$values = array_map(
            
fn(ColorChannelInterface $channel): float => $channel->normalized(),
            
$color->channels(),
        );

        
// take only RGB
        
$values = array_slice($values, 0, 3);

        
// calculate chroma
        
$min = min(...$values);
        
$max = max(...$values);
        
$chroma = $max - $min;

        
// calculate value
        
$v = 100 * $max;

        if (
$chroma === 0.0) {
            
// grayscale color
            
try {
                return new 
Color(0, 0, intval(round($v)), $color->alpha()->normalized());
            } catch (
InvalidArgumentException $e) {
                throw new 
ColorException(
                    
'Failed to import color ' . $color::class . ' to ' . $this::class,
                    
previous: $e,
                );
            }
        }

        
// calculate saturation
        
$s = 100 * ($chroma / $max);

        
// calculate hue
        
[$r, $g, $b] = $values;
        
$h = match (true) {
            (
$r === $min) => 3 - (($g - $b) / $chroma),
            (
$b === $min) => 1 - (($r - $g) / $chroma),
            default => 
5 - (($b - $r) / $chroma),
        } * 
60;

        try {
            return new 
Color(
                
intval(round($h)),
                
intval(round($s)),
                
intval(round($v)),
                
$color->alpha()->normalized(),
            );
        } catch (
InvalidArgumentException $e) {
            throw new 
ColorException(
                
'Failed to import color ' . $color::class . ' to ' . $this::class,
                
previous: $e,
            );
        }
    }

    
/**
     * Import given HSL color to HSV colorspace.
     *
     * @throws InvalidArgumentException
     */
    
protected function importHslColor(ColorInterface $color): HsvColor
    
{
        if (!
$color instanceof HslColor) {
            throw new 
InvalidArgumentException('Color must be of type ' . HslColor::class);
        }

        
// normalized values of hsl channels
        
[$h, $s, $l] = array_map(
            
fn(ColorChannelInterface $channel): float => $channel->normalized(),
            
$color->channels(),
        );

        
$v = $l + $s * min($l, 1 - $l);
        
$s = ($v === 0.0) ? 0 : 2 * (1 - $l / $v);

        return 
$this->colorFromNormalized([$h, $s, $v, $color->alpha()->normalized()]);
    }

    
/**
     * Import given color to HSV color space by converting it to RGB first.
     *
     * @throws ColorException
     */
    
private function importViaRgbColor(NamedColor|CmykColor|OklchColor|OklabColor $color): HsvColor
    
{
        try {
            
$color = $color->toColorspace(RgbColorspace::class);
        } catch (
InvalidArgumentException $e) {
            throw new 
ColorException(
                
'Failed to import color ' . $color::class . ' to ' . $this::class,
                
previous: $e,
            );
        }

        if (!
$color instanceof RgbColor) {
            throw new 
ColorException('Failed to import color ' . $color::class . ' to ' . $this::class);
        }

        return 
$this->importRgbColor($color);
    }
}
Онлайн: 2
Реклама