From 3d1cd02f27518f1a04374c7c8320cd5d82ede6e9 Mon Sep 17 00:00:00 2001 From: Minteck Date: Thu, 23 Feb 2023 19:34:56 +0100 Subject: Updated 40 files, added 37 files, deleted 1103 files and renamed 3905 files (automated) --- includes/composer/composer.json | 5 + includes/composer/composer.lock | 79 +++ includes/composer/vendor/autoload.php | 25 + includes/composer/vendor/composer/ClassLoader.php | 585 +++++++++++++++++++++ .../composer/vendor/composer/InstalledVersions.php | 352 +++++++++++++ includes/composer/vendor/composer/LICENSE | 21 + .../composer/vendor/composer/autoload_classmap.php | 10 + .../vendor/composer/autoload_namespaces.php | 9 + .../composer/vendor/composer/autoload_psr4.php | 10 + .../composer/vendor/composer/autoload_real.php | 38 ++ .../composer/vendor/composer/autoload_static.php | 36 ++ includes/composer/vendor/composer/installed.json | 69 +++ includes/composer/vendor/composer/installed.php | 32 ++ .../composer/vendor/composer/platform_check.php | 26 + .../vendor/ksubileau/color-thief-php/LICENSE | 21 + .../vendor/ksubileau/color-thief-php/composer.json | 45 ++ .../color-thief-php/src/ColorThief/Color.php | 145 +++++ .../color-thief-php/src/ColorThief/ColorThief.php | 539 +++++++++++++++++++ .../src/ColorThief/Exception/Exception.php | 21 + .../Exception/InvalidArgumentException.php | 22 + .../ColorThief/Exception/NotReadableException.php | 22 + .../ColorThief/Exception/NotSupportedException.php | 22 + .../src/ColorThief/Exception/RuntimeException.php | 19 + .../ColorThief/Image/Adapter/AbstractAdapter.php | 78 +++ .../ColorThief/Image/Adapter/AdapterInterface.php | 74 +++ .../src/ColorThief/Image/Adapter/GdAdapter.php | 119 +++++ .../ColorThief/Image/Adapter/GmagickAdapter.php | 105 ++++ .../ColorThief/Image/Adapter/ImagickAdapter.php | 116 ++++ .../src/ColorThief/Image/ImageLoader.php | 195 +++++++ .../color-thief-php/src/ColorThief/PQueue.php | 129 +++++ .../color-thief-php/src/ColorThief/VBox.php | 219 ++++++++ 31 files changed, 3188 insertions(+) create mode 100644 includes/composer/composer.json create mode 100644 includes/composer/composer.lock create mode 100644 includes/composer/vendor/autoload.php create mode 100644 includes/composer/vendor/composer/ClassLoader.php create mode 100644 includes/composer/vendor/composer/InstalledVersions.php create mode 100644 includes/composer/vendor/composer/LICENSE create mode 100644 includes/composer/vendor/composer/autoload_classmap.php create mode 100644 includes/composer/vendor/composer/autoload_namespaces.php create mode 100644 includes/composer/vendor/composer/autoload_psr4.php create mode 100644 includes/composer/vendor/composer/autoload_real.php create mode 100644 includes/composer/vendor/composer/autoload_static.php create mode 100644 includes/composer/vendor/composer/installed.json create mode 100644 includes/composer/vendor/composer/installed.php create mode 100644 includes/composer/vendor/composer/platform_check.php create mode 100644 includes/composer/vendor/ksubileau/color-thief-php/LICENSE create mode 100644 includes/composer/vendor/ksubileau/color-thief-php/composer.json create mode 100644 includes/composer/vendor/ksubileau/color-thief-php/src/ColorThief/Color.php create mode 100644 includes/composer/vendor/ksubileau/color-thief-php/src/ColorThief/ColorThief.php create mode 100644 includes/composer/vendor/ksubileau/color-thief-php/src/ColorThief/Exception/Exception.php create mode 100644 includes/composer/vendor/ksubileau/color-thief-php/src/ColorThief/Exception/InvalidArgumentException.php create mode 100644 includes/composer/vendor/ksubileau/color-thief-php/src/ColorThief/Exception/NotReadableException.php create mode 100644 includes/composer/vendor/ksubileau/color-thief-php/src/ColorThief/Exception/NotSupportedException.php create mode 100644 includes/composer/vendor/ksubileau/color-thief-php/src/ColorThief/Exception/RuntimeException.php create mode 100644 includes/composer/vendor/ksubileau/color-thief-php/src/ColorThief/Image/Adapter/AbstractAdapter.php create mode 100644 includes/composer/vendor/ksubileau/color-thief-php/src/ColorThief/Image/Adapter/AdapterInterface.php create mode 100644 includes/composer/vendor/ksubileau/color-thief-php/src/ColorThief/Image/Adapter/GdAdapter.php create mode 100644 includes/composer/vendor/ksubileau/color-thief-php/src/ColorThief/Image/Adapter/GmagickAdapter.php create mode 100644 includes/composer/vendor/ksubileau/color-thief-php/src/ColorThief/Image/Adapter/ImagickAdapter.php create mode 100644 includes/composer/vendor/ksubileau/color-thief-php/src/ColorThief/Image/ImageLoader.php create mode 100644 includes/composer/vendor/ksubileau/color-thief-php/src/ColorThief/PQueue.php create mode 100644 includes/composer/vendor/ksubileau/color-thief-php/src/ColorThief/VBox.php (limited to 'includes/composer') diff --git a/includes/composer/composer.json b/includes/composer/composer.json new file mode 100644 index 0000000..0566196 --- /dev/null +++ b/includes/composer/composer.json @@ -0,0 +1,5 @@ +{ + "require": { + "ksubileau/color-thief-php": "^2.0" + } +} diff --git a/includes/composer/composer.lock b/includes/composer/composer.lock new file mode 100644 index 0000000..16edbe1 --- /dev/null +++ b/includes/composer/composer.lock @@ -0,0 +1,79 @@ +{ + "_readme": [ + "This file locks the dependencies of your project to a known state", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", + "This file is @generated automatically" + ], + "content-hash": "3458bdb49c5d50ced381c8336aa903c4", + "packages": [ + { + "name": "ksubileau/color-thief-php", + "version": "v2.0.1", + "source": { + "type": "git", + "url": "https://github.com/ksubileau/color-thief-php.git", + "reference": "a1378533433dae824c2e5b70359f8b6ae16b1deb" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ksubileau/color-thief-php/zipball/a1378533433dae824c2e5b70359f8b6ae16b1deb", + "reference": "a1378533433dae824c2e5b70359f8b6ae16b1deb", + "shasum": "" + }, + "require": { + "ext-fileinfo": "*", + "php": "^7.2|^8.0" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "^3.4", + "phpstan/phpstan": "^1.2.0", + "phpstan/phpstan-phpunit": "^1.0.0", + "phpunit/phpunit": "^8.5" + }, + "suggest": { + "ext-gd": "to use the GD image adapter.", + "ext-gmagick": "to use the Gmagick image adapter.", + "ext-imagick": "to use the Imagick image adapter." + }, + "type": "library", + "autoload": { + "psr-4": { + "ColorThief\\": "src/ColorThief" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Kevin Subileau", + "homepage": "http://www.kevinsubileau.fr" + } + ], + "description": "Grabs the dominant color or a representative color palette from an image.", + "homepage": "http://www.kevinsubileau.fr/projets/color-thief-php", + "keywords": [ + "color", + "dominant", + "palette", + "php", + "thief" + ], + "support": { + "issues": "https://github.com/ksubileau/color-thief-php/issues", + "source": "https://github.com/ksubileau/color-thief-php/tree/v2.0.1" + }, + "time": "2022-11-12T10:09:40+00:00" + } + ], + "packages-dev": [], + "aliases": [], + "minimum-stability": "stable", + "stability-flags": [], + "prefer-stable": false, + "prefer-lowest": false, + "platform": [], + "platform-dev": [], + "plugin-api-version": "2.3.0" +} diff --git a/includes/composer/vendor/autoload.php b/includes/composer/vendor/autoload.php new file mode 100644 index 0000000..5b16029 --- /dev/null +++ b/includes/composer/vendor/autoload.php @@ -0,0 +1,25 @@ + + * Jordi Boggiano + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Composer\Autoload; + +/** + * ClassLoader implements a PSR-0, PSR-4 and classmap class loader. + * + * $loader = new \Composer\Autoload\ClassLoader(); + * + * // register classes with namespaces + * $loader->add('Symfony\Component', __DIR__.'/component'); + * $loader->add('Symfony', __DIR__.'/framework'); + * + * // activate the autoloader + * $loader->register(); + * + * // to enable searching the include path (eg. for PEAR packages) + * $loader->setUseIncludePath(true); + * + * In this example, if you try to use a class in the Symfony\Component + * namespace or one of its children (Symfony\Component\Console for instance), + * the autoloader will first look for the class under the component/ + * directory, and it will then fallback to the framework/ directory if not + * found before giving up. + * + * This class is loosely based on the Symfony UniversalClassLoader. + * + * @author Fabien Potencier + * @author Jordi Boggiano + * @see https://www.php-fig.org/psr/psr-0/ + * @see https://www.php-fig.org/psr/psr-4/ + */ +class ClassLoader +{ + /** @var \Closure(string):void */ + private static $includeFile; + + /** @var ?string */ + private $vendorDir; + + // PSR-4 + /** + * @var array[] + * @psalm-var array> + */ + private $prefixLengthsPsr4 = array(); + /** + * @var array[] + * @psalm-var array> + */ + private $prefixDirsPsr4 = array(); + /** + * @var array[] + * @psalm-var array + */ + private $fallbackDirsPsr4 = array(); + + // PSR-0 + /** + * @var array[] + * @psalm-var array> + */ + private $prefixesPsr0 = array(); + /** + * @var array[] + * @psalm-var array + */ + private $fallbackDirsPsr0 = array(); + + /** @var bool */ + private $useIncludePath = false; + + /** + * @var string[] + * @psalm-var array + */ + private $classMap = array(); + + /** @var bool */ + private $classMapAuthoritative = false; + + /** + * @var bool[] + * @psalm-var array + */ + private $missingClasses = array(); + + /** @var ?string */ + private $apcuPrefix; + + /** + * @var self[] + */ + private static $registeredLoaders = array(); + + /** + * @param ?string $vendorDir + */ + public function __construct($vendorDir = null) + { + $this->vendorDir = $vendorDir; + self::initializeIncludeClosure(); + } + + /** + * @return string[] + */ + public function getPrefixes() + { + if (!empty($this->prefixesPsr0)) { + return call_user_func_array('array_merge', array_values($this->prefixesPsr0)); + } + + return array(); + } + + /** + * @return array[] + * @psalm-return array> + */ + public function getPrefixesPsr4() + { + return $this->prefixDirsPsr4; + } + + /** + * @return array[] + * @psalm-return array + */ + public function getFallbackDirs() + { + return $this->fallbackDirsPsr0; + } + + /** + * @return array[] + * @psalm-return array + */ + public function getFallbackDirsPsr4() + { + return $this->fallbackDirsPsr4; + } + + /** + * @return string[] Array of classname => path + * @psalm-return array + */ + public function getClassMap() + { + return $this->classMap; + } + + /** + * @param string[] $classMap Class to filename map + * @psalm-param array $classMap + * + * @return void + */ + public function addClassMap(array $classMap) + { + if ($this->classMap) { + $this->classMap = array_merge($this->classMap, $classMap); + } else { + $this->classMap = $classMap; + } + } + + /** + * Registers a set of PSR-0 directories for a given prefix, either + * appending or prepending to the ones previously set for this prefix. + * + * @param string $prefix The prefix + * @param string[]|string $paths The PSR-0 root directories + * @param bool $prepend Whether to prepend the directories + * + * @return void + */ + public function add($prefix, $paths, $prepend = false) + { + if (!$prefix) { + if ($prepend) { + $this->fallbackDirsPsr0 = array_merge( + (array) $paths, + $this->fallbackDirsPsr0 + ); + } else { + $this->fallbackDirsPsr0 = array_merge( + $this->fallbackDirsPsr0, + (array) $paths + ); + } + + return; + } + + $first = $prefix[0]; + if (!isset($this->prefixesPsr0[$first][$prefix])) { + $this->prefixesPsr0[$first][$prefix] = (array) $paths; + + return; + } + if ($prepend) { + $this->prefixesPsr0[$first][$prefix] = array_merge( + (array) $paths, + $this->prefixesPsr0[$first][$prefix] + ); + } else { + $this->prefixesPsr0[$first][$prefix] = array_merge( + $this->prefixesPsr0[$first][$prefix], + (array) $paths + ); + } + } + + /** + * Registers a set of PSR-4 directories for a given namespace, either + * appending or prepending to the ones previously set for this namespace. + * + * @param string $prefix The prefix/namespace, with trailing '\\' + * @param string[]|string $paths The PSR-4 base directories + * @param bool $prepend Whether to prepend the directories + * + * @throws \InvalidArgumentException + * + * @return void + */ + public function addPsr4($prefix, $paths, $prepend = false) + { + if (!$prefix) { + // Register directories for the root namespace. + if ($prepend) { + $this->fallbackDirsPsr4 = array_merge( + (array) $paths, + $this->fallbackDirsPsr4 + ); + } else { + $this->fallbackDirsPsr4 = array_merge( + $this->fallbackDirsPsr4, + (array) $paths + ); + } + } elseif (!isset($this->prefixDirsPsr4[$prefix])) { + // Register directories for a new namespace. + $length = strlen($prefix); + if ('\\' !== $prefix[$length - 1]) { + throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator."); + } + $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length; + $this->prefixDirsPsr4[$prefix] = (array) $paths; + } elseif ($prepend) { + // Prepend directories for an already registered namespace. + $this->prefixDirsPsr4[$prefix] = array_merge( + (array) $paths, + $this->prefixDirsPsr4[$prefix] + ); + } else { + // Append directories for an already registered namespace. + $this->prefixDirsPsr4[$prefix] = array_merge( + $this->prefixDirsPsr4[$prefix], + (array) $paths + ); + } + } + + /** + * Registers a set of PSR-0 directories for a given prefix, + * replacing any others previously set for this prefix. + * + * @param string $prefix The prefix + * @param string[]|string $paths The PSR-0 base directories + * + * @return void + */ + public function set($prefix, $paths) + { + if (!$prefix) { + $this->fallbackDirsPsr0 = (array) $paths; + } else { + $this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths; + } + } + + /** + * Registers a set of PSR-4 directories for a given namespace, + * replacing any others previously set for this namespace. + * + * @param string $prefix The prefix/namespace, with trailing '\\' + * @param string[]|string $paths The PSR-4 base directories + * + * @throws \InvalidArgumentException + * + * @return void + */ + public function setPsr4($prefix, $paths) + { + if (!$prefix) { + $this->fallbackDirsPsr4 = (array) $paths; + } else { + $length = strlen($prefix); + if ('\\' !== $prefix[$length - 1]) { + throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator."); + } + $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length; + $this->prefixDirsPsr4[$prefix] = (array) $paths; + } + } + + /** + * Turns on searching the include path for class files. + * + * @param bool $useIncludePath + * + * @return void + */ + public function setUseIncludePath($useIncludePath) + { + $this->useIncludePath = $useIncludePath; + } + + /** + * Can be used to check if the autoloader uses the include path to check + * for classes. + * + * @return bool + */ + public function getUseIncludePath() + { + return $this->useIncludePath; + } + + /** + * Turns off searching the prefix and fallback directories for classes + * that have not been registered with the class map. + * + * @param bool $classMapAuthoritative + * + * @return void + */ + public function setClassMapAuthoritative($classMapAuthoritative) + { + $this->classMapAuthoritative = $classMapAuthoritative; + } + + /** + * Should class lookup fail if not found in the current class map? + * + * @return bool + */ + public function isClassMapAuthoritative() + { + return $this->classMapAuthoritative; + } + + /** + * APCu prefix to use to cache found/not-found classes, if the extension is enabled. + * + * @param string|null $apcuPrefix + * + * @return void + */ + public function setApcuPrefix($apcuPrefix) + { + $this->apcuPrefix = function_exists('apcu_fetch') && filter_var(ini_get('apc.enabled'), FILTER_VALIDATE_BOOLEAN) ? $apcuPrefix : null; + } + + /** + * The APCu prefix in use, or null if APCu caching is not enabled. + * + * @return string|null + */ + public function getApcuPrefix() + { + return $this->apcuPrefix; + } + + /** + * Registers this instance as an autoloader. + * + * @param bool $prepend Whether to prepend the autoloader or not + * + * @return void + */ + public function register($prepend = false) + { + spl_autoload_register(array($this, 'loadClass'), true, $prepend); + + if (null === $this->vendorDir) { + return; + } + + if ($prepend) { + self::$registeredLoaders = array($this->vendorDir => $this) + self::$registeredLoaders; + } else { + unset(self::$registeredLoaders[$this->vendorDir]); + self::$registeredLoaders[$this->vendorDir] = $this; + } + } + + /** + * Unregisters this instance as an autoloader. + * + * @return void + */ + public function unregister() + { + spl_autoload_unregister(array($this, 'loadClass')); + + if (null !== $this->vendorDir) { + unset(self::$registeredLoaders[$this->vendorDir]); + } + } + + /** + * Loads the given class or interface. + * + * @param string $class The name of the class + * @return true|null True if loaded, null otherwise + */ + public function loadClass($class) + { + if ($file = $this->findFile($class)) { + $includeFile = self::$includeFile; + $includeFile($file); + + return true; + } + + return null; + } + + /** + * Finds the path to the file where the class is defined. + * + * @param string $class The name of the class + * + * @return string|false The path if found, false otherwise + */ + public function findFile($class) + { + // class map lookup + if (isset($this->classMap[$class])) { + return $this->classMap[$class]; + } + if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) { + return false; + } + if (null !== $this->apcuPrefix) { + $file = apcu_fetch($this->apcuPrefix.$class, $hit); + if ($hit) { + return $file; + } + } + + $file = $this->findFileWithExtension($class, '.php'); + + // Search for Hack files if we are running on HHVM + if (false === $file && defined('HHVM_VERSION')) { + $file = $this->findFileWithExtension($class, '.hh'); + } + + if (null !== $this->apcuPrefix) { + apcu_add($this->apcuPrefix.$class, $file); + } + + if (false === $file) { + // Remember that this class does not exist. + $this->missingClasses[$class] = true; + } + + return $file; + } + + /** + * Returns the currently registered loaders indexed by their corresponding vendor directories. + * + * @return self[] + */ + public static function getRegisteredLoaders() + { + return self::$registeredLoaders; + } + + /** + * @param string $class + * @param string $ext + * @return string|false + */ + private function findFileWithExtension($class, $ext) + { + // PSR-4 lookup + $logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext; + + $first = $class[0]; + if (isset($this->prefixLengthsPsr4[$first])) { + $subPath = $class; + while (false !== $lastPos = strrpos($subPath, '\\')) { + $subPath = substr($subPath, 0, $lastPos); + $search = $subPath . '\\'; + if (isset($this->prefixDirsPsr4[$search])) { + $pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1); + foreach ($this->prefixDirsPsr4[$search] as $dir) { + if (file_exists($file = $dir . $pathEnd)) { + return $file; + } + } + } + } + } + + // PSR-4 fallback dirs + foreach ($this->fallbackDirsPsr4 as $dir) { + if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) { + return $file; + } + } + + // PSR-0 lookup + if (false !== $pos = strrpos($class, '\\')) { + // namespaced class name + $logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1) + . strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR); + } else { + // PEAR-like class name + $logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext; + } + + if (isset($this->prefixesPsr0[$first])) { + foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) { + if (0 === strpos($class, $prefix)) { + foreach ($dirs as $dir) { + if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) { + return $file; + } + } + } + } + } + + // PSR-0 fallback dirs + foreach ($this->fallbackDirsPsr0 as $dir) { + if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) { + return $file; + } + } + + // PSR-0 include paths. + if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) { + return $file; + } + + return false; + } + + /** + * @return void + */ + private static function initializeIncludeClosure() + { + if (self::$includeFile !== null) { + return; + } + + /** + * Scope isolated include. + * + * Prevents access to $this/self from included files. + * + * @param string $file + * @return void + */ + self::$includeFile = \Closure::bind(static function($file) { + include $file; + }, null, null); + } +} diff --git a/includes/composer/vendor/composer/InstalledVersions.php b/includes/composer/vendor/composer/InstalledVersions.php new file mode 100644 index 0000000..c6b54af --- /dev/null +++ b/includes/composer/vendor/composer/InstalledVersions.php @@ -0,0 +1,352 @@ + + * Jordi Boggiano + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Composer; + +use Composer\Autoload\ClassLoader; +use Composer\Semver\VersionParser; + +/** + * This class is copied in every Composer installed project and available to all + * + * See also https://getcomposer.org/doc/07-runtime.md#installed-versions + * + * To require its presence, you can require `composer-runtime-api ^2.0` + * + * @final + */ +class InstalledVersions +{ + /** + * @var mixed[]|null + * @psalm-var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array}|array{}|null + */ + private static $installed; + + /** + * @var bool|null + */ + private static $canGetVendors; + + /** + * @var array[] + * @psalm-var array}> + */ + private static $installedByVendor = array(); + + /** + * Returns a list of all package names which are present, either by being installed, replaced or provided + * + * @return string[] + * @psalm-return list + */ + public static function getInstalledPackages() + { + $packages = array(); + foreach (self::getInstalled() as $installed) { + $packages[] = array_keys($installed['versions']); + } + + if (1 === \count($packages)) { + return $packages[0]; + } + + return array_keys(array_flip(\call_user_func_array('array_merge', $packages))); + } + + /** + * Returns a list of all package names with a specific type e.g. 'library' + * + * @param string $type + * @return string[] + * @psalm-return list + */ + public static function getInstalledPackagesByType($type) + { + $packagesByType = array(); + + foreach (self::getInstalled() as $installed) { + foreach ($installed['versions'] as $name => $package) { + if (isset($package['type']) && $package['type'] === $type) { + $packagesByType[] = $name; + } + } + } + + return $packagesByType; + } + + /** + * Checks whether the given package is installed + * + * This also returns true if the package name is provided or replaced by another package + * + * @param string $packageName + * @param bool $includeDevRequirements + * @return bool + */ + public static function isInstalled($packageName, $includeDevRequirements = true) + { + foreach (self::getInstalled() as $installed) { + if (isset($installed['versions'][$packageName])) { + return $includeDevRequirements || empty($installed['versions'][$packageName]['dev_requirement']); + } + } + + return false; + } + + /** + * Checks whether the given package satisfies a version constraint + * + * e.g. If you want to know whether version 2.3+ of package foo/bar is installed, you would call: + * + * Composer\InstalledVersions::satisfies(new VersionParser, 'foo/bar', '^2.3') + * + * @param VersionParser $parser Install composer/semver to have access to this class and functionality + * @param string $packageName + * @param string|null $constraint A version constraint to check for, if you pass one you have to make sure composer/semver is required by your package + * @return bool + */ + public static function satisfies(VersionParser $parser, $packageName, $constraint) + { + $constraint = $parser->parseConstraints($constraint); + $provided = $parser->parseConstraints(self::getVersionRanges($packageName)); + + return $provided->matches($constraint); + } + + /** + * Returns a version constraint representing all the range(s) which are installed for a given package + * + * It is easier to use this via isInstalled() with the $constraint argument if you need to check + * whether a given version of a package is installed, and not just whether it exists + * + * @param string $packageName + * @return string Version constraint usable with composer/semver + */ + public static function getVersionRanges($packageName) + { + foreach (self::getInstalled() as $installed) { + if (!isset($installed['versions'][$packageName])) { + continue; + } + + $ranges = array(); + if (isset($installed['versions'][$packageName]['pretty_version'])) { + $ranges[] = $installed['versions'][$packageName]['pretty_version']; + } + if (array_key_exists('aliases', $installed['versions'][$packageName])) { + $ranges = array_merge($ranges, $installed['versions'][$packageName]['aliases']); + } + if (array_key_exists('replaced', $installed['versions'][$packageName])) { + $ranges = array_merge($ranges, $installed['versions'][$packageName]['replaced']); + } + if (array_key_exists('provided', $installed['versions'][$packageName])) { + $ranges = array_merge($ranges, $installed['versions'][$packageName]['provided']); + } + + return implode(' || ', $ranges); + } + + throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); + } + + /** + * @param string $packageName + * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present + */ + public static function getVersion($packageName) + { + foreach (self::getInstalled() as $installed) { + if (!isset($installed['versions'][$packageName])) { + continue; + } + + if (!isset($installed['versions'][$packageName]['version'])) { + return null; + } + + return $installed['versions'][$packageName]['version']; + } + + throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); + } + + /** + * @param string $packageName + * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present + */ + public static function getPrettyVersion($packageName) + { + foreach (self::getInstalled() as $installed) { + if (!isset($installed['versions'][$packageName])) { + continue; + } + + if (!isset($installed['versions'][$packageName]['pretty_version'])) { + return null; + } + + return $installed['versions'][$packageName]['pretty_version']; + } + + throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); + } + + /** + * @param string $packageName + * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as reference + */ + public static function getReference($packageName) + { + foreach (self::getInstalled() as $installed) { + if (!isset($installed['versions'][$packageName])) { + continue; + } + + if (!isset($installed['versions'][$packageName]['reference'])) { + return null; + } + + return $installed['versions'][$packageName]['reference']; + } + + throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); + } + + /** + * @param string $packageName + * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as install path. Packages of type metapackages also have a null install path. + */ + public static function getInstallPath($packageName) + { + foreach (self::getInstalled() as $installed) { + if (!isset($installed['versions'][$packageName])) { + continue; + } + + return isset($installed['versions'][$packageName]['install_path']) ? $installed['versions'][$packageName]['install_path'] : null; + } + + throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); + } + + /** + * @return array + * @psalm-return array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool} + */ + public static function getRootPackage() + { + $installed = self::getInstalled(); + + return $installed[0]['root']; + } + + /** + * Returns the raw installed.php data for custom implementations + * + * @deprecated Use getAllRawData() instead which returns all datasets for all autoloaders present in the process. getRawData only returns the first dataset loaded, which may not be what you expect. + * @return array[] + * @psalm-return array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array} + */ + public static function getRawData() + { + @trigger_error('getRawData only returns the first dataset loaded, which may not be what you expect. Use getAllRawData() instead which returns all datasets for all autoloaders present in the process.', E_USER_DEPRECATED); + + if (null === self::$installed) { + // only require the installed.php file if this file is loaded from its dumped location, + // and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937 + if (substr(__DIR__, -8, 1) !== 'C') { + self::$installed = include __DIR__ . '/installed.php'; + } else { + self::$installed = array(); + } + } + + return self::$installed; + } + + /** + * Returns the raw data of all installed.php which are currently loaded for custom implementations + * + * @return array[] + * @psalm-return list}> + */ + public static function getAllRawData() + { + return self::getInstalled(); + } + + /** + * Lets you reload the static array from another file + * + * This is only useful for complex integrations in which a project needs to use + * this class but then also needs to execute another project's autoloader in process, + * and wants to ensure both projects have access to their version of installed.php. + * + * A typical case would be PHPUnit, where it would need to make sure it reads all + * the data it needs from this class, then call reload() with + * `require $CWD/vendor/composer/installed.php` (or similar) as input to make sure + * the project in which it runs can then also use this class safely, without + * interference between PHPUnit's dependencies and the project's dependencies. + * + * @param array[] $data A vendor/composer/installed.php data set + * @return void + * + * @psalm-param array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array} $data + */ + public static function reload($data) + { + self::$installed = $data; + self::$installedByVendor = array(); + } + + /** + * @return array[] + * @psalm-return list}> + */ + private static function getInstalled() + { + if (null === self::$canGetVendors) { + self::$canGetVendors = method_exists('Composer\Autoload\ClassLoader', 'getRegisteredLoaders'); + } + + $installed = array(); + + if (self::$canGetVendors) { + foreach (ClassLoader::getRegisteredLoaders() as $vendorDir => $loader) { + if (isset(self::$installedByVendor[$vendorDir])) { + $installed[] = self::$installedByVendor[$vendorDir]; + } elseif (is_file($vendorDir.'/composer/installed.php')) { + $installed[] = self::$installedByVendor[$vendorDir] = require $vendorDir.'/composer/installed.php'; + if (null === self::$installed && strtr($vendorDir.'/composer', '\\', '/') === strtr(__DIR__, '\\', '/')) { + self::$installed = $installed[count($installed) - 1]; + } + } + } + } + + if (null === self::$installed) { + // only require the installed.php file if this file is loaded from its dumped location, + // and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937 + if (substr(__DIR__, -8, 1) !== 'C') { + self::$installed = require __DIR__ . '/installed.php'; + } else { + self::$installed = array(); + } + } + $installed[] = self::$installed; + + return $installed; + } +} diff --git a/includes/composer/vendor/composer/LICENSE b/includes/composer/vendor/composer/LICENSE new file mode 100644 index 0000000..f27399a --- /dev/null +++ b/includes/composer/vendor/composer/LICENSE @@ -0,0 +1,21 @@ + +Copyright (c) Nils Adermann, Jordi Boggiano + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + diff --git a/includes/composer/vendor/composer/autoload_classmap.php b/includes/composer/vendor/composer/autoload_classmap.php new file mode 100644 index 0000000..0fb0a2c --- /dev/null +++ b/includes/composer/vendor/composer/autoload_classmap.php @@ -0,0 +1,10 @@ + $vendorDir . '/composer/InstalledVersions.php', +); diff --git a/includes/composer/vendor/composer/autoload_namespaces.php b/includes/composer/vendor/composer/autoload_namespaces.php new file mode 100644 index 0000000..15a2ff3 --- /dev/null +++ b/includes/composer/vendor/composer/autoload_namespaces.php @@ -0,0 +1,9 @@ + array($vendorDir . '/ksubileau/color-thief-php/src/ColorThief'), +); diff --git a/includes/composer/vendor/composer/autoload_real.php b/includes/composer/vendor/composer/autoload_real.php new file mode 100644 index 0000000..e570961 --- /dev/null +++ b/includes/composer/vendor/composer/autoload_real.php @@ -0,0 +1,38 @@ +register(true); + + return $loader; + } +} diff --git a/includes/composer/vendor/composer/autoload_static.php b/includes/composer/vendor/composer/autoload_static.php new file mode 100644 index 0000000..a31b292 --- /dev/null +++ b/includes/composer/vendor/composer/autoload_static.php @@ -0,0 +1,36 @@ + + array ( + 'ColorThief\\' => 11, + ), + ); + + public static $prefixDirsPsr4 = array ( + 'ColorThief\\' => + array ( + 0 => __DIR__ . '/..' . '/ksubileau/color-thief-php/src/ColorThief', + ), + ); + + public static $classMap = array ( + 'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php', + ); + + public static function getInitializer(ClassLoader $loader) + { + return \Closure::bind(function () use ($loader) { + $loader->prefixLengthsPsr4 = ComposerStaticInit7bef9e3ab3ffae606875b2457b7bf1cb::$prefixLengthsPsr4; + $loader->prefixDirsPsr4 = ComposerStaticInit7bef9e3ab3ffae606875b2457b7bf1cb::$prefixDirsPsr4; + $loader->classMap = ComposerStaticInit7bef9e3ab3ffae606875b2457b7bf1cb::$classMap; + + }, null, ClassLoader::class); + } +} diff --git a/includes/composer/vendor/composer/installed.json b/includes/composer/vendor/composer/installed.json new file mode 100644 index 0000000..e3ad241 --- /dev/null +++ b/includes/composer/vendor/composer/installed.json @@ -0,0 +1,69 @@ +{ + "packages": [ + { + "name": "ksubileau/color-thief-php", + "version": "v2.0.1", + "version_normalized": "2.0.1.0", + "source": { + "type": "git", + "url": "https://github.com/ksubileau/color-thief-php.git", + "reference": "a1378533433dae824c2e5b70359f8b6ae16b1deb" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ksubileau/color-thief-php/zipball/a1378533433dae824c2e5b70359f8b6ae16b1deb", + "reference": "a1378533433dae824c2e5b70359f8b6ae16b1deb", + "shasum": "" + }, + "require": { + "ext-fileinfo": "*", + "php": "^7.2|^8.0" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "^3.4", + "phpstan/phpstan": "^1.2.0", + "phpstan/phpstan-phpunit": "^1.0.0", + "phpunit/phpunit": "^8.5" + }, + "suggest": { + "ext-gd": "to use the GD image adapter.", + "ext-gmagick": "to use the Gmagick image adapter.", + "ext-imagick": "to use the Imagick image adapter." + }, + "time": "2022-11-12T10:09:40+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "ColorThief\\": "src/ColorThief" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Kevin Subileau", + "homepage": "http://www.kevinsubileau.fr" + } + ], + "description": "Grabs the dominant color or a representative color palette from an image.", + "homepage": "http://www.kevinsubileau.fr/projets/color-thief-php", + "keywords": [ + "color", + "dominant", + "palette", + "php", + "thief" + ], + "support": { + "issues": "https://github.com/ksubileau/color-thief-php/issues", + "source": "https://github.com/ksubileau/color-thief-php/tree/v2.0.1" + }, + "install-path": "../ksubileau/color-thief-php" + } + ], + "dev": true, + "dev-package-names": [] +} diff --git a/includes/composer/vendor/composer/installed.php b/includes/composer/vendor/composer/installed.php new file mode 100644 index 0000000..ade214e --- /dev/null +++ b/includes/composer/vendor/composer/installed.php @@ -0,0 +1,32 @@ + array( + 'name' => '__root__', + 'pretty_version' => 'dev-mane', + 'version' => 'dev-mane', + 'reference' => '8cc1f13c17fa2fb5a4410542d39e650e02945634', + 'type' => 'library', + 'install_path' => __DIR__ . '/../../', + 'aliases' => array(), + 'dev' => true, + ), + 'versions' => array( + '__root__' => array( + 'pretty_version' => 'dev-mane', + 'version' => 'dev-mane', + 'reference' => '8cc1f13c17fa2fb5a4410542d39e650e02945634', + 'type' => 'library', + 'install_path' => __DIR__ . '/../../', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'ksubileau/color-thief-php' => array( + 'pretty_version' => 'v2.0.1', + 'version' => '2.0.1.0', + 'reference' => 'a1378533433dae824c2e5b70359f8b6ae16b1deb', + 'type' => 'library', + 'install_path' => __DIR__ . '/../ksubileau/color-thief-php', + 'aliases' => array(), + 'dev_requirement' => false, + ), + ), +); diff --git a/includes/composer/vendor/composer/platform_check.php b/includes/composer/vendor/composer/platform_check.php new file mode 100644 index 0000000..589e9e7 --- /dev/null +++ b/includes/composer/vendor/composer/platform_check.php @@ -0,0 +1,26 @@ += 70200)) { + $issues[] = 'Your Composer dependencies require a PHP version ">= 7.2.0". You are running ' . PHP_VERSION . '.'; +} + +if ($issues) { + if (!headers_sent()) { + header('HTTP/1.1 500 Internal Server Error'); + } + if (!ini_get('display_errors')) { + if (PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') { + fwrite(STDERR, 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . implode(PHP_EOL, $issues) . PHP_EOL.PHP_EOL); + } elseif (!headers_sent()) { + echo 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . str_replace('You are running '.PHP_VERSION.'.', '', implode(PHP_EOL, $issues)) . PHP_EOL.PHP_EOL; + } + } + trigger_error( + 'Composer detected issues in your platform: ' . implode(' ', $issues), + E_USER_ERROR + ); +} diff --git a/includes/composer/vendor/ksubileau/color-thief-php/LICENSE b/includes/composer/vendor/ksubileau/color-thief-php/LICENSE new file mode 100644 index 0000000..3e13937 --- /dev/null +++ b/includes/composer/vendor/ksubileau/color-thief-php/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2020 Kevin Subileau + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/includes/composer/vendor/ksubileau/color-thief-php/composer.json b/includes/composer/vendor/ksubileau/color-thief-php/composer.json new file mode 100644 index 0000000..3b6d81a --- /dev/null +++ b/includes/composer/vendor/ksubileau/color-thief-php/composer.json @@ -0,0 +1,45 @@ +{ + "name": "ksubileau/color-thief-php", + "type": "library", + "homepage" : "http://www.kevinsubileau.fr/projets/color-thief-php", + "description": "Grabs the dominant color or a representative color palette from an image.", + "keywords": ["color", "thief", "php", "dominant", "palette"], + "license": "MIT", + + "authors": [ + { + "name": "Kevin Subileau", + "homepage": "http://www.kevinsubileau.fr" + } + ], + + "require": { + "php": "^7.2|^8.0", + "ext-fileinfo": "*" + }, + + "require-dev": { + "phpunit/phpunit": "^8.5", + "friendsofphp/php-cs-fixer": "^3.4", + "phpstan/phpstan": "^1.2.0", + "phpstan/phpstan-phpunit": "^1.0.0" + }, + + "suggest": { + "ext-gd": "to use the GD image adapter.", + "ext-imagick": "to use the Imagick image adapter.", + "ext-gmagick": "to use the Gmagick image adapter." + }, + + "autoload": { + "psr-4": { + "ColorThief\\": "src/ColorThief" + } + }, + + "autoload-dev": { + "psr-4": { + "ColorThief\\Tests\\": "tests/" + } + } +} diff --git a/includes/composer/vendor/ksubileau/color-thief-php/src/ColorThief/Color.php b/includes/composer/vendor/ksubileau/color-thief-php/src/ColorThief/Color.php new file mode 100644 index 0000000..f0c7ef0 --- /dev/null +++ b/includes/composer/vendor/ksubileau/color-thief-php/src/ColorThief/Color.php @@ -0,0 +1,145 @@ +red = $red; + $this->green = $green; + $this->blue = $blue; + } + + /** + * Get red value. + */ + public function getRed(): int + { + return $this->red; + } + + /** + * Get green value. + */ + public function getGreen(): int + { + return $this->green; + } + + /** + * Get blue value. + */ + public function getBlue(): int + { + return $this->blue; + } + + /** + * Calculates integer value of current color instance. + */ + public function getInt(): int + { + return ($this->red << 16) + ($this->green << 8) + $this->blue; + } + + /** + * Calculates hexadecimal value of current color instance. + */ + public function getHex(string $prefix = ''): string + { + return sprintf('%s%02x%02x%02x', $prefix, $this->red, $this->green, $this->blue); + } + + /** + * Calculates RGB in array format of current color instance. + * + * @phpstan-return ColorRGB + */ + public function getArray(): array + { + return [$this->red, $this->green, $this->blue]; + } + + /** + * Calculates RGB in string format of current color instance. + */ + public function getRgb(): string + { + return sprintf('rgb(%d, %d, %d)', $this->red, $this->green, $this->blue); + } + + /** + * Formats current color instance into given format. + * + * @return string|int|array|self + * @phpstan-return ColorRGB|string|int|self + */ + public function format(string $type) + { + switch (strtolower($type)) { + case 'rgb': + return $this->getRgb(); + + case 'hex': + return $this->getHex('#'); + + case 'int': + return $this->getInt(); + + case 'array': + return $this->getArray(); + + case 'obj': + return $this; + + default: + throw new NotSupportedException("Color format ({$type}) is not supported."); + } + } + + /** + * Get color as string. + */ + public function __toString(): string + { + return $this->getHex('#'); + } +} diff --git a/includes/composer/vendor/ksubileau/color-thief-php/src/ColorThief/ColorThief.php b/includes/composer/vendor/ksubileau/color-thief-php/src/ColorThief/ColorThief.php new file mode 100644 index 0000000..2cd658b --- /dev/null +++ b/includes/composer/vendor/ksubileau/color-thief-php/src/ColorThief/ColorThief.php @@ -0,0 +1,539 @@ +> (8 - $sigBits)) << (2 * $sigBits)) | (($green >> (8 - $sigBits)) << $sigBits) | ($blue >> (8 - $sigBits)); + } + + /** + * Get RGB values (0-255) or RGB Histogram Buckets from a combined color index (3 colors as one integer). + * + * @phpstan-return ColorRGB + */ + public static function getColorsFromIndex(int $index, int $sigBits = 8): array + { + $mask = (1 << $sigBits) - 1; + + $red = ($index >> (2 * $sigBits)) & $mask; + $green = ($index >> $sigBits) & $mask; + $blue = $index & $mask; + + return [$red, $green, $blue]; + } + + /** + * Gets the dominant color from the image using the median cut algorithm to cluster similar colors. + * + * @param mixed $sourceImage Path/URL to the image, GD resource, Imagick/Gmagick instance, or image as binary string + * @param int $quality 1 is the highest quality. There is a trade-off between quality and speed. + * It determines how many pixels are skipped before the next one is sampled. + * We rarely need to sample every single pixel in the image to get good results. + * The bigger the number, the faster the palette generation but the greater the + * likelihood that colors will be missed. + * @param array|null $area It allows you to specify a rectangular area in the image in order to get + * colors only for this area. It needs to be an associative array with the + * following keys: + * $area['x']: The x-coordinate of the top left corner of the area. Default to 0. + * $area['y']: The y-coordinate of the top left corner of the area. Default to 0. + * $area['w']: The width of the area. Default to image width minus x-coordinate. + * $area['h']: The height of the area. Default to image height minus y-coordinate. + * @param string $outputFormat By default, color is returned as an array of three integers representing + * red, green, and blue values. + * You can choose another output format by passing one of the following values: + * 'rgb' : RGB string notation (ex: rgb(253, 42, 152)). + * 'hex' : String of the hexadecimal representation (ex: #fd2a98). + * 'int' : Integer color value (ex: 16591512). + * 'array' : Default format (ex: [253, 42, 152]). + * 'obj' : Instance of ColorThief\Color, for custom processing. + * @param AdapterInterface|string|null $adapter Optional argument to choose a preferred image adapter to use for loading the image. + * By default, the adapter is automatically chosen depending on the available extensions + * and the type of $sourceImage (for example Imagick is used if $sourceImage is an Imagick instance). + * You can pass one of the 'Imagick', 'Gmagick' or 'Gd' string to use the corresponding + * underlying image extension, or you can pass an instance of any class implementing + * the AdapterInterface interface to use a custom image loader. + * @phpstan-param ?RectangularArea $area + * + * @phpstan-return ColorRGB|Color|int|string|null + */ + public static function getColor($sourceImage, int $quality = 10, ?array $area = null, string $outputFormat = 'array', $adapter = null) + { + $palette = self::getPalette($sourceImage, 5, $quality, $area, $outputFormat, $adapter); + + return $palette ? $palette[0] : null; + } + + /** + * Gets a palette of dominant colors from the image using the median cut algorithm to cluster similar colors. + * + * @param mixed $sourceImage Path/URL to the image, GD resource, Imagick/Gmagick instance, or image as binary string + * @param int $colorCount it determines the size of the palette; the number of colors returned + * @param int $quality 1 is the highest quality. There is a trade-off between quality and speed. + * It determines how many pixels are skipped before the next one is sampled. + * We rarely need to sample every single pixel in the image to get good results. + * The bigger the number, the faster the palette generation but the greater the + * likelihood that colors will be missed. + * @param array|null $area It allows you to specify a rectangular area in the image in order to get + * colors only for this area. It needs to be an associative array with the + * following keys: + * $area['x']: The x-coordinate of the top left corner of the area. Default to 0. + * $area['y']: The y-coordinate of the top left corner of the area. Default to 0. + * $area['w']: The width of the area. Default to image width minus x-coordinate. + * $area['h']: The height of the area. Default to image height minus y-coordinate. + * @param string $outputFormat By default, colors are returned as an array of three integers representing + * red, green, and blue values. + * You can choose another output format by passing one of the following values: + * 'rgb' : RGB string notation (ex: rgb(253, 42, 152)). + * 'hex' : String of the hexadecimal representation (ex: #fd2a98). + * 'int' : Integer color value (ex: 16591512). + * 'array' : Default format (ex: [253, 42, 152]). + * 'obj' : Instance of ColorThief\Color, for custom processing. + * @param AdapterInterface|string|null $adapter Optional argument to choose a preferred image adapter to use for loading the image. + * By default, the adapter is automatically chosen depending on the available extensions + * and the type of $sourceImage (e.g. Imagick is used if $sourceImage is an Imagick instance). + * You can pass one of the 'Imagick', 'Gmagick' or 'Gd' string to use the corresponding + * underlying image extension, or you can pass an instance of any class implementing + * the AdapterInterface interface to use a custom image loader. + * @phpstan-param ?RectangularArea $area + * + * @return array + * @phpstan-return ColorRGB[]|Color[]|int[]|string[]|null + */ + public static function getPalette( + $sourceImage, + int $colorCount = 10, + int $quality = 10, + ?array $area = null, + string $outputFormat = 'array', + $adapter = null + ): ?array { + if ($colorCount < 2 || $colorCount > 256) { + throw new InvalidArgumentException('The number of palette colors must be between 2 and 256 inclusive.'); + } + + if ($quality < 1) { + throw new InvalidArgumentException('The quality argument must be an integer greater than one.'); + } + + $histo = []; + $numPixelsAnalyzed = self::loadImage($sourceImage, $quality, $histo, $area, $adapter); + if (0 === $numPixelsAnalyzed) { + throw new NotSupportedException('Unable to compute the color palette of a blank or transparent image.'); + } + + // Send histogram to quantize function which clusters values + // using median cut algorithm + $palette = self::quantize($numPixelsAnalyzed, $colorCount, $histo); + + return array_map(function (Color $color) use ($outputFormat) { + return $color->format($outputFormat); + }, $palette); + } + + /** + * @param mixed $sourceImage Path/URL to the image, GD resource, Imagick instance, or image as binary string + * @param int $quality Analyze every $quality pixels + * @param array $histo Histogram + * @param AdapterInterface|string|null $adapter Image adapter to use for loading the image + * @phpstan-param ?RectangularArea $area + */ + private static function loadImage($sourceImage, int $quality, array &$histo, array $area = null, $adapter = null): int + { + $loader = new ImageLoader(); + if (null !== $adapter) { + $loader->setPreferredAdapter($adapter); + } + $image = $loader->load($sourceImage); + $startX = 0; + $startY = 0; + $width = $image->getWidth(); + $height = $image->getHeight(); + + if ($area) { + $startX = $area['x'] ?? 0; + $startY = $area['y'] ?? 0; + $width = $area['w'] ?? ($width - $startX); + $height = $area['h'] ?? ($height - $startY); + + if ((($startX + $width) > $image->getWidth()) || (($startY + $height) > $image->getHeight())) { + throw new InvalidArgumentException('Area is out of image bounds.'); + } + } + + // Fill a SplArray with zeroes to initialize the 5-bit buckets and avoid having to check isset in the pixel loop. + // There are 32768 buckets because each color is 5 bits (15 bits total for RGB values). + $totalBuckets = (1 << (3 * self::SIGBITS)); + $histoSpl = new SplFixedArray($totalBuckets); + for ($i = 0; $i < $totalBuckets; ++$i) { + $histoSpl[$i] = 0; + } + + $numUsefulPixels = 0; + $pixelCount = $width * $height; + + for ($i = 0; $i < $pixelCount; $i += $quality) { + $x = $startX + ($i % $width); + $y = (int) ($startY + $i / $width); + $color = $image->getPixelColor($x, $y); + + // Pixel is too transparent. Its alpha value is larger (more transparent) than THRESHOLD_ALPHA. + // PHP's transparency range (0-127 opaque-transparent) is reverse that of Javascript (0-255 tranparent-opaque). + if ($color->alpha > self::THRESHOLD_ALPHA) { + continue; + } + + // Pixel is too white to be useful. Its RGB values all exceed THRESHOLD_WHITE + if ($color->red > self::THRESHOLD_WHITE && $color->green > self::THRESHOLD_WHITE && $color->blue > self::THRESHOLD_WHITE) { + continue; + } + + // Count this pixel in its histogram bucket. + ++$numUsefulPixels; + $bucketIndex = self::getColorIndex($color->red, $color->green, $color->blue); + $histoSpl[$bucketIndex] = $histoSpl[$bucketIndex] + 1; + } + + // Copy the histogram buckets that had pixels back to a normal array. + $histo = []; + foreach ($histoSpl as $bucketInt => $numPixels) { + if ($numPixels > 0) { + $histo[$bucketInt] = $numPixels; + } + } + + // Don't destroy a resource passed by the user ! + // TODO Add a method in ImageLoader to know if the image should be destroy + // (or to know the detected image source type) + if (\is_string($sourceImage)) { + $image->destroy(); + } + + return $numUsefulPixels; + } + + /** + * @param array $histo + */ + private static function vboxFromHistogram(array $histo): VBox + { + $rgbMin = [\PHP_INT_MAX, \PHP_INT_MAX, \PHP_INT_MAX]; + $rgbMax = [-\PHP_INT_MAX, -\PHP_INT_MAX, -\PHP_INT_MAX]; + + // find min/max + foreach ($histo as $bucketIndex => $count) { + $rgb = self::getColorsFromIndex($bucketIndex, self::SIGBITS); + + // For each color components + for ($i = 0; $i < 3; ++$i) { + if ($rgb[$i] < $rgbMin[$i]) { + $rgbMin[$i] = $rgb[$i]; + } + if ($rgb[$i] > $rgbMax[$i]) { + $rgbMax[$i] = $rgb[$i]; + } + } + } + + return new VBox($rgbMin[0], $rgbMax[0], $rgbMin[1], $rgbMax[1], $rgbMin[2], $rgbMax[2], $histo); + } + + /** + * @param int[] $partialSum + * + * @return array{VBox, VBox}|null + */ + private static function doCut(string $color, VBox $vBox, array $partialSum, int $total): ?array + { + $dim1 = $color.'1'; + $dim2 = $color.'2'; + + for ($i = $vBox->$dim1; $i <= $vBox->$dim2; ++$i) { + if ($partialSum[$i] > $total / 2) { + $vBox1 = $vBox->copy(); + $vBox2 = $vBox->copy(); + $left = $i - $vBox->$dim1; + $right = $vBox->$dim2 - $i; + + // Choose the cut plane within the greater of the (left, right) sides + // of the bin in which the median pixel resides + if ($left <= $right) { + $d2 = min($vBox->$dim2 - 1, (int) ($i + $right / 2)); + } else { /* left > right */ + $d2 = max($vBox->$dim1, (int) ($i - 1 - $left / 2)); + } + + while (empty($partialSum[$d2])) { + ++$d2; + } + // Avoid 0-count boxes + while ($partialSum[$d2] >= $total && !empty($partialSum[$d2 - 1])) { + --$d2; + } + + // set dimensions + $vBox1->$dim2 = $d2; + $vBox2->$dim1 = $d2 + 1; + + return [$vBox1, $vBox2]; + } + } + + return null; + } + + /** + * @param array $histo + * + * @return VBox[]|null + */ + private static function medianCutApply(array $histo, VBox $vBox): ?array + { + if (!$vBox->count()) { + return null; + } + + // If the vbox occupies just one element in color space, it can't be split + if (1 == $vBox->count()) { + return [ + $vBox->copy(), + ]; + } + + // Select the longest axis for splitting + $cutColor = $vBox->longestAxis(); + + // Find the partial sum arrays along the selected axis. + [$total, $partialSum] = self::sumColors($cutColor, $histo, $vBox); + + return self::doCut($cutColor, $vBox, $partialSum, $total); + } + + /** + * Find the partial sum arrays along the selected axis. + * + * @param string $axis r|g|b + * @phpstan-param 'r'|'g'|'b' $axis + * + * @param array $histo + * + * @return array{int, array} [$total, $partialSum] + */ + private static function sumColors(string $axis, array $histo, VBox $vBox): array + { + $total = 0; + $partialSum = []; + + // The selected axis should be the first range + $colorIterateOrder = array_diff(['r', 'g', 'b'], [$axis]); + array_unshift($colorIterateOrder, $axis); + + // Retrieves iteration ranges + [$firstRange, $secondRange, $thirdRange] = self::getVBoxColorRanges($vBox, $colorIterateOrder); + + foreach ($firstRange as $firstColor) { + $sum = 0; + foreach ($secondRange as $secondColor) { + foreach ($thirdRange as $thirdColor) { + // Rearrange color components + $bucket = [ + $colorIterateOrder[0] => $firstColor, + $colorIterateOrder[1] => $secondColor, + $colorIterateOrder[2] => $thirdColor, + ]; + + // The getColorIndex function takes RGB values instead of buckets. The left shift converts our bucket into its RGB value. + $bucketIndex = self::getColorIndex( + $bucket['r'] << self::RSHIFT, + $bucket['g'] << self::RSHIFT, + $bucket['b'] << self::RSHIFT, + self::SIGBITS + ); + + if (isset($histo[$bucketIndex])) { + $sum += $histo[$bucketIndex]; + } + } + } + $total += $sum; + $partialSum[$firstColor] = $total; + } + + return [$total, $partialSum]; + } + + /** + * @phpstan-param array<'r'|'g'|'b'> $order + * + * @return int[][] + * @phpstan-return array{int[], int[], int[]} + */ + private static function getVBoxColorRanges(VBox $vBox, array $order): array + { + $ranges = [ + 'r' => range($vBox->r1, $vBox->r2), + 'g' => range($vBox->g1, $vBox->g2), + 'b' => range($vBox->b1, $vBox->b2), + ]; + + return [ + $ranges[$order[0]], + $ranges[$order[1]], + $ranges[$order[2]], + ]; + } + + /** + * Inner function to do the iteration. + * + * @param PQueue $priorityQueue + * @param array $histo + */ + private static function quantizeIter(PQueue &$priorityQueue, float $target, array $histo): void + { + $nColors = $priorityQueue->size(); + $nIterations = 0; + + while ($nIterations < self::MAX_ITERATIONS) { + if ($nColors >= $target) { + return; + } + + if ($nIterations++ > self::MAX_ITERATIONS) { + // echo "infinite loop; perhaps too few pixels!"."\n"; + return; + } + + $vBox = $priorityQueue->pop(); + if (null === $vBox) { + // Logic error: should not happen! + throw new RuntimeException('Failed to pop VBox from an empty queue.'); + } + + if (!$vBox->count()) { /* just put it back */ + $priorityQueue->push($vBox); + ++$nIterations; + continue; + } + // do the cut + $vBoxes = self::medianCutApply($histo, $vBox); + + if (!(\is_array($vBoxes) && isset($vBoxes[0]))) { + // Expect an array of VBox + throw new RuntimeException('Unexpected result from the medianCutApply function.'); + } + + $priorityQueue->push($vBoxes[0]); + + if (isset($vBoxes[1])) { /* vbox2 can be null */ + $priorityQueue->push($vBoxes[1]); + ++$nColors; + } + } + } + + /** + * @param int $numPixels Number of image pixels analyzed + * @param array $histo Histogram + * + * @return Color[] + */ + private static function quantize(int $numPixels, int $maxColors, array &$histo): array + { + // Short-Circuits + if (0 === $numPixels) { + throw new InvalidArgumentException('Zero usable pixels found in image.'); + } + if ($maxColors < 2 || $maxColors > 256) { + throw new InvalidArgumentException('The maxColors parameter must be between 2 and 256 inclusive.'); + } + if (0 === \count($histo)) { + throw new InvalidArgumentException('Image produced an empty histogram.'); + } + + // check that we aren't below maxcolors already + //if (count($histo) <= $maxcolors) { + // XXX: generate the new colors from the histo and return + //} + + $vBox = self::vboxFromHistogram($histo); + + /** @var PQueue $priorityQueue */ + $priorityQueue = new PQueue(function (VBox $a, VBox $b) { + return $a->count() <=> $b->count(); + }); + $priorityQueue->push($vBox); + + // first set of colors, sorted by population + self::quantizeIter($priorityQueue, self::FRACT_BY_POPULATIONS * $maxColors, $histo); + + // Re-sort by the product of pixel occupancy times the size in color space. + $priorityQueue->setComparator(function (VBox $a, VBox $b) { + return ($a->count() * $a->volume()) <=> ($b->count() * $b->volume()); + }); + + // next set - generate the median cuts using the (npix * vol) sorting. + self::quantizeIter($priorityQueue, $maxColors, $histo); + + // calculate the actual colors + $colors = $priorityQueue->map(function (VBox $vbox) { + return new Color(...$vbox->avg()); + }); + $colors = array_reverse($colors); + + return $colors; + } +} diff --git a/includes/composer/vendor/ksubileau/color-thief-php/src/ColorThief/Exception/Exception.php b/includes/composer/vendor/ksubileau/color-thief-php/src/ColorThief/Exception/Exception.php new file mode 100644 index 0000000..d843f61 --- /dev/null +++ b/includes/composer/vendor/ksubileau/color-thief-php/src/ColorThief/Exception/Exception.php @@ -0,0 +1,21 @@ +isAvailable()) { + throw new NotSupportedException('Image adapter is not available with this PHP installation. Required extension may be missing.'); + } + } + + public function load($resource): AdapterInterface + { + $this->resource = $resource; + + return $this; + } + + public function loadFromUrl(string $url): AdapterInterface + { + $options = [ + 'http' => [ + 'method' => 'GET', + 'protocol_version' => 1.1, // force use HTTP 1.1 for service mesh environment with envoy + 'header' => [ + 'Accept-language: en', + 'User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:95.0) Gecko/20100101 Firefox/95.0', + ], + ], + ]; + + $context = stream_context_create($options); + + $data = @file_get_contents($url, false, $context); + if (false === $data) { + throw new NotReadableException("Unable to load image from url ({$url})."); + } + + return $this->loadFromBinary($data); + } + + public function destroy(): void + { + $this->resource = null; + } + + public function getResource() + { + return $this->resource; + } +} diff --git a/includes/composer/vendor/ksubileau/color-thief-php/src/ColorThief/Image/Adapter/AdapterInterface.php b/includes/composer/vendor/ksubileau/color-thief-php/src/ColorThief/Image/Adapter/AdapterInterface.php new file mode 100644 index 0000000..7c08229 --- /dev/null +++ b/includes/composer/vendor/ksubileau/color-thief-php/src/ColorThief/Image/Adapter/AdapterInterface.php @@ -0,0 +1,74 @@ += 0) { + if (!($resource instanceof \GdImage)) { + throw new InvalidArgumentException('Argument is not an instance of GdImage.'); + } + } else { + if (!\is_resource($resource) || 'gd' != get_resource_type($resource)) { + throw new InvalidArgumentException('Argument is not a valid GD resource.'); + } + } + + return parent::load($resource); + } + + public function loadFromBinary(string $data): AdapterInterface + { + $resource = @imagecreatefromstring($data); + if (false === $resource) { + throw new NotReadableException('Unable to read image from binary data.'); + } + + return parent::load($resource); + } + + public function loadFromPath(string $file): AdapterInterface + { + if (!is_readable($file)) { + throw new NotReadableException("Unable to read image from path ({$file})."); + } + + [, , $type] = @getimagesize($file); + + switch ($type) { + case \IMAGETYPE_GIF: + $resource = @imagecreatefromgif($file); + break; + + case \IMAGETYPE_JPEG: + $resource = @imagecreatefromjpeg($file); + break; + + case \IMAGETYPE_PNG: + $resource = @imagecreatefrompng($file); + break; + + case \IMAGETYPE_WEBP: + if (!function_exists('imagecreatefromwebp')) { + throw new NotReadableException('Unsupported image type. GD/PHP installation does not support WebP format.'); + } + $resource = @imagecreatefromwebp($file); + break; + + default: + throw new NotReadableException('Unsupported image type for GD image adapter.'); + } + + if (false === $resource) { + throw new NotReadableException("Unable to decode image from file ({$file})."); + } + + return parent::load($resource); + } + + public function destroy(): void + { + if ($this->resource) { + // For PHP 7.x only, noop starting from PHP 8.0 + imagedestroy($this->resource); + } + parent::destroy(); + } + + public function getHeight(): int + { + return imagesy($this->resource); + } + + public function getWidth(): int + { + return imagesx($this->resource); + } + + public function getPixelColor(int $x, int $y): \stdClass + { + $rgba = imagecolorat($this->resource, $x, $y); + $color = imagecolorsforindex($this->resource, $rgba); + + return (object) $color; + } +} diff --git a/includes/composer/vendor/ksubileau/color-thief-php/src/ColorThief/Image/Adapter/GmagickAdapter.php b/includes/composer/vendor/ksubileau/color-thief-php/src/ColorThief/Image/Adapter/GmagickAdapter.php new file mode 100644 index 0000000..ca7063e --- /dev/null +++ b/includes/composer/vendor/ksubileau/color-thief-php/src/ColorThief/Image/Adapter/GmagickAdapter.php @@ -0,0 +1,105 @@ +getImageColorSpace()) { + // Leave original object unmodified + $resource = clone $resource; + $resource->setImageColorspace(Gmagick::COLORSPACE_RGB); + } + + return parent::load($resource); + } + + public function loadFromBinary(string $data): AdapterInterface + { + $resource = new Gmagick(); + try { + $resource->readImageBlob($data); + } catch (\GmagickException $e) { + throw new NotReadableException('Unable to read image from binary data.', 0, $e); + } + + return $this->load($resource); + } + + public function loadFromPath(string $file): AdapterInterface + { + $resource = null; + try { + $resource = new Gmagick($file); + } catch (\GmagickException $e) { + throw new NotReadableException("Unable to read image from path ({$file}).", 0, $e); + } + + return $this->load($resource); + } + + public function destroy(): void + { + if ($this->resource) { + $this->resource->clear(); + $this->resource->destroy(); + } + parent::destroy(); + } + + public function getHeight(): int + { + return $this->resource->getimageheight(); + } + + public function getWidth(): int + { + return $this->resource->getimagewidth(); + } + + public function getPixelColor(int $x, int $y): \stdClass + { + $cropped = clone $this->resource; // No need to modify the original object. + $histogram = $cropped->cropImage(1, 1, $x, $y)->getImageHistogram(); + $pixel = array_shift($histogram); + + // Un-normalized values don't give a full range 0-1 alpha channel + // So we ask for normalized values, and then we un-normalize it ourselves. + $colorArray = $pixel->getColor(true, true); + $color = new \stdClass(); + $color->red = (int) round($colorArray['r'] * 255); + $color->green = (int) round($colorArray['g'] * 255); + $color->blue = (int) round($colorArray['b'] * 255); + $color->alpha = (int) round($pixel->getcolorvalue(\Gmagick::COLOR_OPACITY) * 127); + + return $color; + } +} diff --git a/includes/composer/vendor/ksubileau/color-thief-php/src/ColorThief/Image/Adapter/ImagickAdapter.php b/includes/composer/vendor/ksubileau/color-thief-php/src/ColorThief/Image/Adapter/ImagickAdapter.php new file mode 100644 index 0000000..2ca15a9 --- /dev/null +++ b/includes/composer/vendor/ksubileau/color-thief-php/src/ColorThief/Image/Adapter/ImagickAdapter.php @@ -0,0 +1,116 @@ +getImageColorspace()) { + // Leave original object unmodified + $resource = clone $resource; + + $imagickVersion = phpversion('imagick'); + if ($imagickVersion && version_compare($imagickVersion, '3.0.0', '<')) { + throw new NotSupportedException('Imagick extension version 3.0.0 or later is required for sampling CMYK images.'); + } + + // With ImageMagick version 6.7.7, CMYK images converted to RGB color space work as expected, + // but for later versions (6.9.7 and 7.0.8 have been tested), conversion to SRGB seems to be required + $imageMagickVersion = $resource->getVersion(); + if ($imageMagickVersion['versionNumber'] > 1655) { + $resource->transformImageColorspace(Imagick::COLORSPACE_SRGB); + } else { + $resource->transformImageColorspace(Imagick::COLORSPACE_RGB); + } + } + + return parent::load($resource); + } + + public function loadFromBinary(string $data): AdapterInterface + { + $resource = new Imagick(); + try { + $resource->readImageBlob($data); + } catch (\ImagickException $e) { + throw new NotReadableException('Unable to read image from binary data.', 0, $e); + } + + return $this->load($resource); + } + + public function loadFromPath(string $file): AdapterInterface + { + try { + $resource = new Imagick($file); + } catch (\ImagickException $e) { + throw new NotReadableException("Unable to read image from path ({$file}).", 0, $e); + } + + return $this->load($resource); + } + + public function destroy(): void + { + if ($this->resource) { + $this->resource->clear(); + } + parent::destroy(); + } + + public function getHeight(): int + { + return $this->resource->getImageHeight(); + } + + public function getWidth(): int + { + return $this->resource->getImageWidth(); + } + + public function getPixelColor(int $x, int $y): \stdClass + { + /** @var \ImagickPixel $pixel */ + $pixel = $this->resource->getImagePixelColor($x, $y); + + // Un-normalized values don't give a full range 0-1 alpha channel + // So we ask for normalized values, and then we un-normalize it ourselves. + $colorArray = $pixel->getColor(1); + $color = new \stdClass(); + $color->red = (int) round($colorArray['r'] * 255); + $color->green = (int) round($colorArray['g'] * 255); + $color->blue = (int) round($colorArray['b'] * 255); + $color->alpha = (int) (127 - round($colorArray['a'] * 127)); + + return $color; + } +} diff --git a/includes/composer/vendor/ksubileau/color-thief-php/src/ColorThief/Image/ImageLoader.php b/includes/composer/vendor/ksubileau/color-thief-php/src/ColorThief/Image/ImageLoader.php new file mode 100644 index 0000000..9e82784 --- /dev/null +++ b/includes/composer/vendor/ksubileau/color-thief-php/src/ColorThief/Image/ImageLoader.php @@ -0,0 +1,195 @@ +preferredAdapter = $adapter; + + return $this; + } + + /** + * @param mixed $source Path/URL to the image, GD resource, Imagick/Gmagick instance, or image as binary string + */ + public function load($source): AdapterInterface + { + $image = null; + + $preferredAdapter = $this->preferredAdapter; + // Select appropriate adapter depending on source type if no preference given + if (null === $preferredAdapter) { + if ($this->isGdImage($source)) { + $preferredAdapter = 'Gd'; + } elseif ($this->isImagick($source)) { + $preferredAdapter = 'Imagick'; + } elseif ($this->isGmagick($source)) { + $preferredAdapter = 'Gmagick'; + } + } + + $image = $this->createAdapter($preferredAdapter); + + switch (true) { + case $this->isGdImage($source): + case $this->isImagick($source): + case $this->isGmagick($source): + return $image->load($source); + case $this->isBinary($source): + return $image->loadFromBinary($source); + case $this->isUrl($source): + return $image->loadFromUrl($source); + case $this->isFilePath($source): + return $image->loadFromPath($source); + default: + throw new NotReadableException('Image source does not exists or is not readable.'); + } + } + + /** + * Creates an adapter instance according to config settings. + * + * @param string|AdapterInterface|null $preferredAdapter + */ + public function createAdapter($preferredAdapter = null): AdapterInterface + { + if (null === $preferredAdapter) { + // Select first available adapter + if (\ColorThief\Image\Adapter\ImagickAdapter::isAvailable()) { + $preferredAdapter = 'Imagick'; + } elseif (\ColorThief\Image\Adapter\GmagickAdapter::isAvailable()) { + $preferredAdapter = 'Gmagick'; + } elseif (\ColorThief\Image\Adapter\GdAdapter::isAvailable()) { + $preferredAdapter = 'Gd'; + } else { + throw new NotSupportedException('At least one of GD, Imagick or Gmagick extension must be installed. None of them was found.'); + } + } + + if (is_string($preferredAdapter)) { + $adapterName = ucfirst($preferredAdapter); + $adapterClass = sprintf('\\ColorThief\\Image\\Adapter\\%sAdapter', $adapterName); + + if (!class_exists($adapterClass)) { + throw new NotSupportedException("Image adapter ({$adapterName}) could not be instantiated."); + } + + return new $adapterClass(); + } + + if ($preferredAdapter instanceof AdapterInterface) { + return $preferredAdapter; + } + + throw new NotSupportedException('Unknown image adapter type.'); + } + + /** + * Determines if given source data is a GD image. + * + * @param mixed $data + */ + public function isGdImage($data): bool + { + if (version_compare(\PHP_VERSION, '8.0.0') >= 0) { + return $data instanceof \GdImage; + } + + return \is_resource($data) && 'gd' == get_resource_type($data); + } + + /** + * Determines if given source data is an Imagick object. + * + * @param mixed $data + */ + public function isImagick($data): bool + { + return is_a($data, 'Imagick'); + } + + /** + * Determines if given source data is a Gmagick object. + * + * @param mixed $data + */ + public function isGmagick($data): bool + { + return is_a($data, 'Gmagick'); + } + + /** + * Determines if given source data is file path. + * + * @param mixed $data + */ + public function isFilePath($data): bool + { + if (is_string($data)) { + try { + return is_file($data); + } catch (\Exception $e) { + return false; + } + } + + return false; + } + + /** + * Determines if given source data is url. + * + * @param mixed $data + */ + public function isUrl($data): bool + { + return (bool) filter_var($data, FILTER_VALIDATE_URL); + } + + /** + * Determines if given source data is binary data. + * + * @param mixed $data + */ + public function isBinary($data): bool + { + if (is_string($data)) { + $finfo = finfo_open(FILEINFO_MIME_TYPE); + $mime = finfo_buffer($finfo, $data); + finfo_close($finfo); + + return 'text' != substr($mime, 0, 4) && 'application/x-empty' != $mime; + } + + return false; + } +} diff --git a/includes/composer/vendor/ksubileau/color-thief-php/src/ColorThief/PQueue.php b/includes/composer/vendor/ksubileau/color-thief-php/src/ColorThief/PQueue.php new file mode 100644 index 0000000..21981a6 --- /dev/null +++ b/includes/composer/vendor/ksubileau/color-thief-php/src/ColorThief/PQueue.php @@ -0,0 +1,129 @@ + + */ + private $contents = []; + + /** @var bool */ + private $sorted = false; + + /** + * @var callable + * @phpstan-var callable(T, T): int + */ + private $comparator = null; + + public function __construct(callable $comparator) + { + $this->setComparator($comparator); + } + + private function sort(): void + { + usort($this->contents, $this->comparator); + $this->sorted = true; + } + + /** + * @param mixed $object + * @phpstan-param T $object + */ + public function push($object): void + { + $this->contents[] = $object; + $this->sorted = false; + } + + /** + * @return mixed + * @phpstan-return T + */ + public function peek(?int $index = null) + { + if (!$this->sorted) { + $this->sort(); + } + + if (null === $index) { + $index = $this->size() - 1; + } + + return $this->contents[$index]; + } + + /** + * @return mixed|null + * @phpstan-return T|null + */ + public function pop() + { + if (!$this->sorted) { + $this->sort(); + } + + return array_pop($this->contents); + } + + public function size(): int + { + return \count($this->contents); + } + + /** + * @phpstan-template R + * @phpstan-param callable(T): R $function + * @phpstan-return array + */ + public function map(callable $function, bool $sorted = true): array + { + if ($sorted && !$this->sorted) { + $this->sort(); + } + + return array_map($function, $this->contents); + } + + /** + * @phpstan-param callable(T, T): int $function + */ + public function setComparator(callable $function): void + { + $this->comparator = $function; + $this->sorted = false; + } + + /** + * @return array + * @phpstan-return array + */ + public function getContent(bool $sorted = true) + { + if ($sorted && !$this->sorted) { + $this->sort(); + } + + return $this->contents; + } +} diff --git a/includes/composer/vendor/ksubileau/color-thief-php/src/ColorThief/VBox.php b/includes/composer/vendor/ksubileau/color-thief-php/src/ColorThief/VBox.php new file mode 100644 index 0000000..d8746ee --- /dev/null +++ b/includes/composer/vendor/ksubileau/color-thief-php/src/ColorThief/VBox.php @@ -0,0 +1,219 @@ + */ + public $histo; + + /** @var int */ + private $volume; + /** @var bool */ + private $volume_set = false; + + /** @var int */ + private $count; + /** @var bool */ + private $count_set = false; + + /** + * @var array + * @phpstan-var ColorRGB + */ + private $avg; + /** @var bool */ + private $avg_set = false; + + /** + * VBox constructor. + * + * @param array $histo + */ + public function __construct(int $r1, int $r2, int $g1, int $g2, int $b1, int $b2, array $histo) + { + $this->r1 = $r1; + $this->r2 = $r2; + $this->g1 = $g1; + $this->g2 = $g2; + $this->b1 = $b1; + $this->b2 = $b2; + $this->histo = $histo; + } + + public function volume(bool $force = false): int + { + if (true !== $this->volume_set || $force) { + $this->volume = (($this->r2 - $this->r1 + 1) * ($this->g2 - $this->g1 + 1) * ($this->b2 - $this->b1 + 1)); + $this->volume_set = true; + } + + return $this->volume; + } + + public function count(bool $force = false): int + { + if (true !== $this->count_set || $force) { + $npix = 0; + + // Select the fastest way (i.e. with the fewest iterations) to count + // the number of pixels contained in this vbox. + if ($this->volume() > \count($this->histo)) { + // Iterate over the histogram if the size of this histogram is lower than the vbox volume + foreach ($this->histo as $bucketIndex => $count) { + $rgbBuckets = ColorThief::getColorsFromIndex($bucketIndex, ColorThief::SIGBITS); + if ($this->contains($rgbBuckets, 0)) { + $npix += $count; + } + } + } else { + // Or iterate over points of the vbox if the size of the histogram is greater than the vbox volume + for ($redBucket = $this->r1; $redBucket <= $this->r2; ++$redBucket) { + for ($greenBucket = $this->g1; $greenBucket <= $this->g2; ++$greenBucket) { + for ($blueBucket = $this->b1; $blueBucket <= $this->b2; ++$blueBucket) { + // The getColorIndex function takes RGB values instead of buckets. The left shift converts our bucket into its RGB value. + $bucketIndex = ColorThief::getColorIndex( + $redBucket << ColorThief::RSHIFT, + $greenBucket << ColorThief::RSHIFT, + $blueBucket << ColorThief::RSHIFT, + ColorThief::SIGBITS + ); + if (isset($this->histo[$bucketIndex])) { + $npix += $this->histo[$bucketIndex]; + } + } + } + } + } + $this->count = $npix; + $this->count_set = true; + } + + return $this->count; + } + + public function copy(): self + { + return new self($this->r1, $this->r2, $this->g1, $this->g2, $this->b1, $this->b2, $this->histo); + } + + /** + * Calculates the average color represented by this VBox. + * + * @phpstan-return ColorRGB + */ + public function avg(bool $force = false): array + { + if (true !== $this->avg_set || $force) { + $ntot = 0; + $mult = 1 << ColorThief::RSHIFT; + $rsum = 0; + $gsum = 0; + $bsum = 0; + + for ($redBucket = $this->r1; $redBucket <= $this->r2; ++$redBucket) { + for ($greenBucket = $this->g1; $greenBucket <= $this->g2; ++$greenBucket) { + for ($blueBucket = $this->b1; $blueBucket <= $this->b2; ++$blueBucket) { + // getColorIndex takes RGB values instead of buckets, so left shift so we get a bucketIndex + $bucketIndex = ColorThief::getColorIndex( + $redBucket << ColorThief::RSHIFT, + $greenBucket << ColorThief::RSHIFT, + $blueBucket << ColorThief::RSHIFT, + ColorThief::SIGBITS + ); + + // The bucket values need to be multiplied by $mult to get the RGB values. + // Can't use a left shift here, as we're working with a floating point number to put the value at the bucket's midpoint. + $hval = $this->histo[$bucketIndex] ?? 0; + $ntot += $hval; + $rsum += ($hval * ($redBucket + 0.5) * $mult); + $gsum += ($hval * ($greenBucket + 0.5) * $mult); + $bsum += ($hval * ($blueBucket + 0.5) * $mult); + } + } + } + + if ($ntot) { + $this->avg = [ + (int) ($rsum / $ntot), + (int) ($gsum / $ntot), + (int) ($bsum / $ntot), + ]; + } else { + // echo 'empty box'."\n"; + $this->avg = [ + (int) ($mult * ($this->r1 + $this->r2 + 1) / 2), + (int) ($mult * ($this->g1 + $this->g2 + 1) / 2), + (int) ($mult * ($this->b1 + $this->b2 + 1) / 2), + ]; + + // Ensure all channel values are leather or equal 255 (Issue #24) + $this->avg = array_map(function ($val) { + return min($val, 255); + }, $this->avg); + } + + $this->avg_set = true; + } + + return $this->avg; + } + + /** + * @phpstan-param ColorRGB $rgbValue + */ + public function contains(array $rgbValue, int $rshift = ColorThief::RSHIFT): bool + { + // Get the buckets from the RGB values. + $redBucket = $rgbValue[0] >> $rshift; + $greenBucket = $rgbValue[1] >> $rshift; + $blueBucket = $rgbValue[2] >> $rshift; + + return + $redBucket >= $this->r1 && + $redBucket <= $this->r2 && + $greenBucket >= $this->g1 && + $greenBucket <= $this->g2 && + $blueBucket >= $this->b1 && + $blueBucket <= $this->b2; + } + + /** + * Determines the longest axis. + * + * @phpstan-return 'r'|'g'|'b' + */ + public function longestAxis(): string + { + // Color-Width for RGB + $red = $this->r2 - $this->r1; + $green = $this->g2 - $this->g1; + $blue = $this->b2 - $this->b1; + + return $red >= $green && $red >= $blue ? 'r' : ($green >= $red && $green >= $blue ? 'g' : 'b'); + } +} -- cgit