├── LICENSE ├── composer.json └── src ├── Options ├── AbstractOption.php ├── AutoRotate.php ├── Background.php ├── Blur.php ├── CacheBuster.php ├── Crop.php ├── Dpr.php ├── EnforceThumbnail.php ├── Enlarge.php ├── Expires.php ├── Extend.php ├── ExtendAspectRatio.php ├── Filename.php ├── Format.php ├── FormatQuality.php ├── Gravity.php ├── Height.php ├── KeepCopyright.php ├── MaxBytes.php ├── MinHeight.php ├── MinWidth.php ├── Option.php ├── Padding.php ├── Preset.php ├── Quality.php ├── Raw.php ├── Resize.php ├── ResizingType.php ├── ReturnAttachment.php ├── Rotate.php ├── Sharpen.php ├── Size.php ├── SkipProcessing.php ├── StripColorProfile.php ├── StripMetadata.php ├── Trim.php ├── Watermark.php ├── Width.php └── Zoom.php ├── Support ├── Color.php ├── GravityType.php ├── ImageFormat.php └── UrlSigner.php └── UrlBuilder.php /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) Onliner 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "onliner/imgproxy-php", 3 | "type": "library", 4 | "description": "ImgProxy url builder for PHP", 5 | "keywords": ["imgproxy", "imageproxy", "image", "resize"], 6 | "license": "MIT", 7 | "require": { 8 | "php": "^8.0" 9 | }, 10 | "require-dev": { 11 | "phpunit/phpunit": "^8.5.8|^9.3.3", 12 | "phpstan/phpstan": "^0.12" 13 | }, 14 | "autoload": { 15 | "psr-4": { 16 | "Onliner\\ImgProxy\\": "src/" 17 | } 18 | }, 19 | "autoload-dev": { 20 | "psr-4": { 21 | "Onliner\\ImgProxy\\": "tests/" 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/Options/AbstractOption.php: -------------------------------------------------------------------------------- 1 | $data 14 | * 15 | * @return static 16 | */ 17 | public static function __set_state(array $data): static 18 | { 19 | $class = new ReflectionClass(static::class); 20 | $self = $class->newInstanceWithoutConstructor(); 21 | 22 | $assigner = function () use ($self, $data) { 23 | foreach ($data as $key => $value) { 24 | $self->{$key} = $value; 25 | } 26 | }; 27 | $assigner->bindTo($self, static::class)(); 28 | 29 | return $self; 30 | } 31 | 32 | /** 33 | * @return string 34 | */ 35 | abstract public function name(): string; 36 | 37 | /** 38 | * @return array 39 | */ 40 | abstract public function data(): array; 41 | 42 | /** 43 | * @return string 44 | */ 45 | public function value(): string 46 | { 47 | $data = $this->data(); 48 | 49 | array_unshift($data, $this->name()); 50 | 51 | // Remove empty options from end. 52 | return rtrim(implode(':', $data), ':'); 53 | } 54 | 55 | /** 56 | * @return string 57 | */ 58 | public function __toString(): string 59 | { 60 | return $this->value(); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/Options/AutoRotate.php: -------------------------------------------------------------------------------- 1 | rotate = $rotate; 14 | } 15 | 16 | /** 17 | * @inheritDoc 18 | */ 19 | public function name(): string 20 | { 21 | return 'ar'; 22 | } 23 | 24 | /** 25 | * @inheritDoc 26 | */ 27 | public function data(): array 28 | { 29 | return [ 30 | (int) $this->rotate, 31 | ]; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/Options/Background.php: -------------------------------------------------------------------------------- 1 | color = new Color($color); 16 | } 17 | 18 | /** 19 | * @inheritDoc 20 | */ 21 | public function name(): string 22 | { 23 | return 'bg'; 24 | } 25 | 26 | /** 27 | * @inheritDoc 28 | */ 29 | public function data(): array 30 | { 31 | return [ 32 | $this->color->value(), 33 | ]; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/Options/Blur.php: -------------------------------------------------------------------------------- 1 | sigma = $sigma; 20 | } 21 | 22 | /** 23 | * @inheritDoc 24 | */ 25 | public function name(): string 26 | { 27 | return 'bl'; 28 | } 29 | 30 | /** 31 | * @inheritDoc 32 | */ 33 | public function data(): array 34 | { 35 | return [ 36 | $this->sigma, 37 | ]; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/Options/CacheBuster.php: -------------------------------------------------------------------------------- 1 | value = $value; 20 | } 21 | 22 | /** 23 | * @inheritDoc 24 | */ 25 | public function name(): string 26 | { 27 | return 'cb'; 28 | } 29 | 30 | /** 31 | * @inheritDoc 32 | */ 33 | public function data(): array 34 | { 35 | return [ 36 | $this->value, 37 | ]; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/Options/Crop.php: -------------------------------------------------------------------------------- 1 | width = new Width($width); 16 | $this->height = new Height($height); 17 | $this->gravity = is_string($gravity) ? Gravity::fromString($gravity) : $gravity; 18 | } 19 | 20 | /** 21 | * @inheritDoc 22 | */ 23 | public function name(): string 24 | { 25 | return 'c'; 26 | } 27 | 28 | /** 29 | * @inheritDoc 30 | */ 31 | public function data(): array 32 | { 33 | return array_merge( 34 | $this->width->data(), 35 | $this->height->data(), 36 | $this->gravity ? $this->gravity->data() : [] 37 | ); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/Options/Dpr.php: -------------------------------------------------------------------------------- 1 | dpr = $dpr; 20 | } 21 | 22 | /** 23 | * @inheritDoc 24 | */ 25 | public function name(): string 26 | { 27 | return 'dpr'; 28 | } 29 | 30 | /** 31 | * @inheritDoc 32 | */ 33 | public function data(): array 34 | { 35 | return [ 36 | $this->dpr, 37 | ]; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/Options/EnforceThumbnail.php: -------------------------------------------------------------------------------- 1 | format = $format; 14 | } 15 | 16 | /** 17 | * @inheritDoc 18 | */ 19 | public function name(): string 20 | { 21 | return 'eth'; 22 | } 23 | 24 | /** 25 | * @inheritDoc 26 | */ 27 | public function data(): array 28 | { 29 | return [ 30 | $this->format ?: true, 31 | ]; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/Options/Enlarge.php: -------------------------------------------------------------------------------- 1 | enlarge = $enlarge; 14 | } 15 | 16 | /** 17 | * @inheritDoc 18 | */ 19 | public function name(): string 20 | { 21 | return 'el'; 22 | } 23 | 24 | /** 25 | * @inheritDoc 26 | */ 27 | public function data(): array 28 | { 29 | return [ 30 | (int) $this->enlarge, 31 | ]; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/Options/Expires.php: -------------------------------------------------------------------------------- 1 | timestamp = $timestamp; 14 | } 15 | 16 | /** 17 | * @inheritDoc 18 | */ 19 | public function name(): string 20 | { 21 | return 'exp'; 22 | } 23 | 24 | /** 25 | * @inheritDoc 26 | */ 27 | public function data(): array 28 | { 29 | return [ 30 | $this->timestamp, 31 | ]; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/Options/Extend.php: -------------------------------------------------------------------------------- 1 | extend = $extend; 15 | $this->gravity = is_string($gravity) ? Gravity::fromString($gravity) : $gravity; 16 | } 17 | 18 | /** 19 | * @inheritDoc 20 | */ 21 | public function name(): string 22 | { 23 | return 'ex'; 24 | } 25 | 26 | /** 27 | * @inheritDoc 28 | */ 29 | public function data(): array 30 | { 31 | return array_merge( 32 | [(int) $this->extend], 33 | $this->gravity ? $this->gravity->data() : [] 34 | ); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/Options/ExtendAspectRatio.php: -------------------------------------------------------------------------------- 1 | extend = new Extend($extend, $gravity); 14 | } 15 | 16 | /** 17 | * @inheritDoc 18 | */ 19 | public function name(): string 20 | { 21 | return 'exar'; 22 | } 23 | 24 | /** 25 | * @inheritDoc 26 | */ 27 | public function data(): array 28 | { 29 | return $this->extend->data(); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/Options/Filename.php: -------------------------------------------------------------------------------- 1 | name = $name; 20 | } 21 | 22 | /** 23 | * @inheritDoc 24 | */ 25 | public function name(): string 26 | { 27 | return 'fn'; 28 | } 29 | 30 | /** 31 | * @inheritDoc 32 | */ 33 | public function data(): array 34 | { 35 | return [ 36 | $this->name, 37 | ]; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/Options/Format.php: -------------------------------------------------------------------------------- 1 | extension = $extension; 20 | } 21 | 22 | /** 23 | * @inheritDoc 24 | */ 25 | public function name(): string 26 | { 27 | return 'f'; 28 | } 29 | 30 | /** 31 | * @inheritDoc 32 | */ 33 | public function data(): array 34 | { 35 | return [ 36 | $this->extension, 37 | ]; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/Options/FormatQuality.php: -------------------------------------------------------------------------------- 1 | $options 18 | */ 19 | public function __construct(array $options) 20 | { 21 | foreach ($options as $format => $quality) { 22 | $data = (new Quality($quality))->data(); 23 | $this->options[] = [$format, ...$data]; 24 | } 25 | 26 | if (empty($this->options)) { 27 | throw new InvalidArgumentException('At least one format quality must be set'); 28 | } 29 | } 30 | 31 | /** 32 | * @inheritDoc 33 | */ 34 | public function name(): string 35 | { 36 | return 'fq'; 37 | } 38 | 39 | /** 40 | * @inheritDoc 41 | */ 42 | public function data(): array 43 | { 44 | return array_merge(...$this->options); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/Options/Gravity.php: -------------------------------------------------------------------------------- 1 | type = new GravityType($type); 24 | 25 | if ($x < 0) { 26 | throw new InvalidArgumentException(sprintf('Invalid gravity X: %s', $x)); 27 | } 28 | 29 | if ($y < 0) { 30 | throw new InvalidArgumentException(sprintf('Invalid gravity Y: %s', $y)); 31 | } 32 | 33 | $this->x = $x; 34 | $this->y = $y; 35 | } 36 | 37 | /** 38 | * @param string $gravity 39 | * 40 | * @return static 41 | */ 42 | public static function fromString(string $gravity): self 43 | { 44 | $params = explode(':', $gravity, 3); 45 | 46 | if (isset($params[1]) && !is_numeric($params[1])) { 47 | throw new InvalidArgumentException('Gravity X should be numeric'); 48 | } 49 | 50 | if (isset($params[2]) && !is_numeric($params[2])) { 51 | throw new InvalidArgumentException('Gravity Y should be numeric'); 52 | } 53 | 54 | return new self( 55 | $params[0], 56 | isset($params[1]) ? (float) $params[1] : null, 57 | isset($params[2]) ? (float) $params[2] : null 58 | ); 59 | } 60 | 61 | /** 62 | * @inheritDoc 63 | */ 64 | public function name(): string 65 | { 66 | return 'g'; 67 | } 68 | 69 | /** 70 | * @inheritDoc 71 | */ 72 | public function data(): array 73 | { 74 | return [ 75 | $this->type->value(), 76 | $this->x, 77 | $this->y, 78 | ]; 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/Options/Height.php: -------------------------------------------------------------------------------- 1 | height = $height; 20 | } 21 | 22 | /** 23 | * @inheritDoc 24 | */ 25 | public function name(): string 26 | { 27 | return 'h'; 28 | } 29 | 30 | /** 31 | * @inheritDoc 32 | */ 33 | public function data(): array 34 | { 35 | return [ 36 | $this->height, 37 | ]; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/Options/KeepCopyright.php: -------------------------------------------------------------------------------- 1 | keep = $keep; 14 | } 15 | 16 | /** 17 | * @inheritDoc 18 | */ 19 | public function name(): string 20 | { 21 | return 'kcr'; 22 | } 23 | 24 | /** 25 | * @inheritDoc 26 | */ 27 | public function data(): array 28 | { 29 | return [ 30 | (int) $this->keep, 31 | ]; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/Options/MaxBytes.php: -------------------------------------------------------------------------------- 1 | bytes = $bytes; 20 | } 21 | 22 | /** 23 | * @inheritDoc 24 | */ 25 | public function name(): string 26 | { 27 | return 'mb'; 28 | } 29 | 30 | /** 31 | * @inheritDoc 32 | */ 33 | public function data(): array 34 | { 35 | return [ 36 | $this->bytes, 37 | ]; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/Options/MinHeight.php: -------------------------------------------------------------------------------- 1 | height = new Height($height); 14 | } 15 | 16 | /** 17 | * @inheritDoc 18 | */ 19 | public function name(): string 20 | { 21 | return 'mh'; 22 | } 23 | 24 | /** 25 | * @inheritDoc 26 | */ 27 | public function data(): array 28 | { 29 | return $this->height->data(); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/Options/MinWidth.php: -------------------------------------------------------------------------------- 1 | width = new Width($width); 14 | } 15 | 16 | /** 17 | * @inheritDoc 18 | */ 19 | public function name(): string 20 | { 21 | return 'mw'; 22 | } 23 | 24 | /** 25 | * @inheritDoc 26 | */ 27 | public function data(): array 28 | { 29 | return $this->width->data(); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/Options/Option.php: -------------------------------------------------------------------------------- 1 | 12 | */ 13 | private array $data; 14 | 15 | /** 16 | * @param string $name 17 | * @param array $data 18 | */ 19 | public function __construct(string $name, array $data = []) 20 | { 21 | $this->name = $name; 22 | $this->data = $data; 23 | } 24 | 25 | /** 26 | * @inheritDoc 27 | */ 28 | public function name(): string 29 | { 30 | return $this->name; 31 | } 32 | 33 | /** 34 | * @inheritDoc 35 | */ 36 | public function data(): array 37 | { 38 | return $this->data; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/Options/Padding.php: -------------------------------------------------------------------------------- 1 | top = $top; 23 | $this->right = $right; 24 | $this->bottom = $bottom; 25 | $this->left = $left; 26 | } 27 | 28 | /** 29 | * @inheritDoc 30 | */ 31 | public function name(): string 32 | { 33 | return 'pd'; 34 | } 35 | 36 | /** 37 | * @inheritDoc 38 | */ 39 | public function data(): array 40 | { 41 | return [ 42 | $this->top, 43 | $this->right, 44 | $this->bottom, 45 | $this->left, 46 | ]; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/Options/Preset.php: -------------------------------------------------------------------------------- 1 | presets = array_filter($presets); 19 | 20 | if (empty($this->presets)) { 21 | throw new InvalidArgumentException('At least one preset must be set'); 22 | } 23 | } 24 | 25 | /** 26 | * @inheritDoc 27 | */ 28 | public function name(): string 29 | { 30 | return 'pr'; 31 | } 32 | 33 | /** 34 | * @inheritDoc 35 | */ 36 | public function data(): array 37 | { 38 | return $this->presets; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/Options/Quality.php: -------------------------------------------------------------------------------- 1 | 100) { 16 | throw new InvalidArgumentException(sprintf('Invalid quality: %s', $quality)); 17 | } 18 | 19 | $this->quality = $quality; 20 | } 21 | 22 | /** 23 | * @inheritDoc 24 | */ 25 | public function name(): string 26 | { 27 | return 'q'; 28 | } 29 | 30 | /** 31 | * @inheritDoc 32 | */ 33 | public function data(): array 34 | { 35 | return [ 36 | $this->quality, 37 | ]; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/Options/Raw.php: -------------------------------------------------------------------------------- 1 | raw = $raw; 14 | } 15 | 16 | /** 17 | * @inheritDoc 18 | */ 19 | public function name(): string 20 | { 21 | return 'raw'; 22 | } 23 | 24 | /** 25 | * @inheritDoc 26 | */ 27 | public function data(): array 28 | { 29 | return [ 30 | (int) $this->raw, 31 | ]; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/Options/Resize.php: -------------------------------------------------------------------------------- 1 | type = new ResizingType($type); 20 | 21 | if (!is_null($width ?? $height ?? $enlarge ?? $extend)) { 22 | $this->size = new Size($width, $height, $enlarge, $extend); 23 | } 24 | } 25 | 26 | /** 27 | * @inheritDoc 28 | */ 29 | public function name(): string 30 | { 31 | return 'rs'; 32 | } 33 | 34 | /** 35 | * @inheritDoc 36 | */ 37 | public function data(): array 38 | { 39 | return array_merge( 40 | $this->type->data(), 41 | $this->size ? $this->size->data() : [] 42 | ); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/Options/ResizingType.php: -------------------------------------------------------------------------------- 1 | type = $type; 36 | } 37 | 38 | /** 39 | * @inheritDoc 40 | */ 41 | public function name(): string 42 | { 43 | return 'rt'; 44 | } 45 | 46 | /** 47 | * @inheritDoc 48 | */ 49 | public function data(): array 50 | { 51 | return [ 52 | $this->type, 53 | ]; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/Options/ReturnAttachment.php: -------------------------------------------------------------------------------- 1 | value = $value; 14 | } 15 | 16 | /** 17 | * @inheritDoc 18 | */ 19 | public function name(): string 20 | { 21 | return 'att'; 22 | } 23 | 24 | /** 25 | * @inheritDoc 26 | */ 27 | public function data(): array 28 | { 29 | return [ 30 | (int) $this->value, 31 | ]; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/Options/Rotate.php: -------------------------------------------------------------------------------- 1 | angle = $angle; 20 | } 21 | 22 | /** 23 | * @inheritDoc 24 | */ 25 | public function name(): string 26 | { 27 | return 'rot'; 28 | } 29 | 30 | /** 31 | * @inheritDoc 32 | */ 33 | public function data(): array 34 | { 35 | return [ 36 | $this->angle, 37 | ]; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/Options/Sharpen.php: -------------------------------------------------------------------------------- 1 | sigma = $sigma; 20 | } 21 | 22 | /** 23 | * @inheritDoc 24 | */ 25 | public function name(): string 26 | { 27 | return 'sh'; 28 | } 29 | 30 | /** 31 | * @inheritDoc 32 | */ 33 | public function data(): array 34 | { 35 | return [ 36 | $this->sigma, 37 | ]; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/Options/Size.php: -------------------------------------------------------------------------------- 1 | width = new Width($width); 24 | } 25 | 26 | if (isset($height)) { 27 | $this->height = new Height($height); 28 | } 29 | 30 | $this->enlarge = $enlarge; 31 | $this->extend = $extend; 32 | } 33 | 34 | /** 35 | * @inheritDoc 36 | */ 37 | public function name(): string 38 | { 39 | return 's'; 40 | } 41 | 42 | /** 43 | * @inheritDoc 44 | */ 45 | public function data(): array 46 | { 47 | return [ 48 | $this->width ? $this->width->data()[0] : null, 49 | $this->height ? $this->height->data()[0]: null, 50 | isset($this->enlarge) ? (int) $this->enlarge : null, 51 | isset($this->extend) ? (int) $this->extend : null, 52 | ]; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/Options/SkipProcessing.php: -------------------------------------------------------------------------------- 1 | extensions = array_filter($extensions); 19 | 20 | if (empty($this->extensions)) { 21 | throw new InvalidArgumentException('At least one extension must be set'); 22 | } 23 | } 24 | 25 | /** 26 | * @inheritDoc 27 | */ 28 | public function name(): string 29 | { 30 | return 'skp'; 31 | } 32 | 33 | /** 34 | * @inheritDoc 35 | */ 36 | public function data(): array 37 | { 38 | return $this->extensions; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/Options/StripColorProfile.php: -------------------------------------------------------------------------------- 1 | strip = $strip; 14 | } 15 | 16 | /** 17 | * @inheritDoc 18 | */ 19 | public function name(): string 20 | { 21 | return 'scp'; 22 | } 23 | 24 | /** 25 | * @inheritDoc 26 | */ 27 | public function data(): array 28 | { 29 | return [ 30 | (int) $this->strip, 31 | ]; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/Options/StripMetadata.php: -------------------------------------------------------------------------------- 1 | strip = $strip; 14 | } 15 | 16 | /** 17 | * @inheritDoc 18 | */ 19 | public function name(): string 20 | { 21 | return 'sm'; 22 | } 23 | 24 | /** 25 | * @inheritDoc 26 | */ 27 | public function data(): array 28 | { 29 | return [ 30 | (int) $this->strip, 31 | ]; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/Options/Trim.php: -------------------------------------------------------------------------------- 1 | color = Color::fromHex($color); 25 | } 26 | 27 | $this->threshold = $threshold; 28 | $this->equalHor = $equalHor; 29 | $this->equalVer = $equalVer; 30 | } 31 | 32 | /** 33 | * @inheritDoc 34 | */ 35 | public function name(): string 36 | { 37 | return 't'; 38 | } 39 | 40 | /** 41 | * @inheritDoc 42 | */ 43 | public function data(): array 44 | { 45 | return [ 46 | $this->threshold, 47 | $this->color ? $this->color->value() : null, 48 | isset($this->equalHor) ? (int) $this->equalHor : null, 49 | isset($this->equalVer) ? (int) $this->equalVer : null, 50 | ]; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/Options/Watermark.php: -------------------------------------------------------------------------------- 1 | 1) { 28 | throw new InvalidArgumentException(sprintf('Invalid watermark opacity: %s', $opacity)); 29 | } 30 | 31 | if ($scale < 0) { 32 | throw new InvalidArgumentException(sprintf('Invalid watermark scale: %s', $scale)); 33 | } 34 | 35 | if ($position !== null && !in_array($position, $this->positions())) { 36 | throw new InvalidArgumentException(sprintf('Invalid watermark position: %s', $position)); 37 | } 38 | 39 | $this->opacity = $opacity; 40 | $this->position = $position; 41 | $this->x = $x; 42 | $this->y = $y; 43 | $this->scale = $scale; 44 | } 45 | 46 | /** 47 | * @inheritDoc 48 | */ 49 | public function name(): string 50 | { 51 | return 'wm'; 52 | } 53 | 54 | /** 55 | * @inheritDoc 56 | */ 57 | public function data(): array 58 | { 59 | return [ 60 | $this->opacity, 61 | $this->position, 62 | $this->x, 63 | $this->y, 64 | $this->scale, 65 | ]; 66 | } 67 | 68 | /** 69 | * @return array 70 | */ 71 | private function positions(): array 72 | { 73 | return array_merge(GravityType::TYPES, [self::REPLICATE_POSITION]); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/Options/Width.php: -------------------------------------------------------------------------------- 1 | width = $width; 20 | } 21 | 22 | /** 23 | * @inheritDoc 24 | */ 25 | public function name(): string 26 | { 27 | return 'w'; 28 | } 29 | 30 | /** 31 | * @inheritDoc 32 | */ 33 | public function data(): array 34 | { 35 | return [ 36 | $this->width, 37 | ]; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/Options/Zoom.php: -------------------------------------------------------------------------------- 1 | x = $x; 25 | $this->y = $y; 26 | } 27 | 28 | /** 29 | * @inheritDoc 30 | */ 31 | public function name(): string 32 | { 33 | return 'z'; 34 | } 35 | 36 | /** 37 | * @inheritDoc 38 | */ 39 | public function data(): array 40 | { 41 | return [ 42 | $this->x, 43 | $this->y, 44 | ]; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/Support/Color.php: -------------------------------------------------------------------------------- 1 | isValidHexColor($color) && !$this->isValidRgbColor($color)) { 16 | throw new InvalidArgumentException(sprintf('Invalid color: %s', $color)); 17 | } 18 | 19 | $this->color = strtolower($color); 20 | } 21 | 22 | /** 23 | * @param string $color 24 | * 25 | * @return self 26 | */ 27 | public static function fromHex(string $color): self 28 | { 29 | if (!self::isValidHexColor($color)) { 30 | throw new InvalidArgumentException(sprintf('Invalid color: %s', $color)); 31 | } 32 | 33 | return new self($color); 34 | } 35 | 36 | /** 37 | * @param array $data 38 | * 39 | * @return self 40 | */ 41 | public static function __set_state(array $data): self 42 | { 43 | return new self(...$data); 44 | } 45 | 46 | /** 47 | * @return string 48 | */ 49 | public function value(): string 50 | { 51 | return $this->color; 52 | } 53 | 54 | /** 55 | * @param string $color 56 | * 57 | * @return bool 58 | */ 59 | private static function isValidHexColor(string $color): bool 60 | { 61 | return (bool) preg_match('/^[a-f0-9]{6}$/i', $color); 62 | } 63 | 64 | /** 65 | * @param string $color 66 | * 67 | * @return bool 68 | */ 69 | private static function isValidRgbColor(string $color): bool 70 | { 71 | $rgb = explode(':', $color); 72 | 73 | return count($rgb) == 3 && ctype_digit(implode($rgb)) && max($rgb) <= 255; 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/Support/GravityType.php: -------------------------------------------------------------------------------- 1 | type = $type; 51 | } 52 | 53 | /** 54 | * @param array $data 55 | * 56 | * @return self 57 | */ 58 | public static function __set_state(array $data): self 59 | { 60 | return new self(...$data); 61 | } 62 | 63 | public function value(): string 64 | { 65 | return $this->type; 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/Support/ImageFormat.php: -------------------------------------------------------------------------------- 1 | extension = $this->cast($extension); 24 | 25 | if (!self::isSupported($this->extension)) { 26 | throw new InvalidArgumentException(sprintf('Invalid image format: %s', $extension)); 27 | } 28 | } 29 | 30 | /** 31 | * @param array $data 32 | * 33 | * @return self 34 | */ 35 | public static function __set_state(array $data): self 36 | { 37 | return new self(...$data); 38 | } 39 | 40 | /** 41 | * @param string $value 42 | * 43 | * @return bool 44 | */ 45 | public static function isSupported(string $value): bool 46 | { 47 | return in_array($value, self::SUPPORTED); 48 | } 49 | 50 | /** 51 | * @param string $extension 52 | * 53 | * @return bool 54 | */ 55 | public function isEquals(string $extension): bool 56 | { 57 | return $this->extension === $this->cast($extension); 58 | } 59 | 60 | /** 61 | * @return string 62 | */ 63 | public function value(): string 64 | { 65 | return $this->extension; 66 | } 67 | 68 | private function cast(string $extension): string 69 | { 70 | return strtolower(trim($extension)); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/Support/UrlSigner.php: -------------------------------------------------------------------------------- 1 | key = pack('H*', $key); 15 | $this->salt = pack('H*', $salt); 16 | } 17 | 18 | /** 19 | * @param string $str 20 | * 21 | * @return string 22 | */ 23 | public function sign(string $str): string 24 | { 25 | return hash_hmac('sha256', $this->salt . $str, $this->key, true); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/UrlBuilder.php: -------------------------------------------------------------------------------- 1 | 20 | */ 21 | private array $options = []; 22 | 23 | /** 24 | * @param UrlSigner|null $signer 25 | */ 26 | public function __construct(?UrlSigner $signer = null) 27 | { 28 | $this->signer = $signer; 29 | } 30 | 31 | /** 32 | * @param string $key 33 | * @param string $salt 34 | * 35 | * @return self 36 | */ 37 | public static function signed(string $key, string $salt): self 38 | { 39 | return new self(new UrlSigner($key, $salt)); 40 | } 41 | 42 | /** 43 | * @return array 44 | */ 45 | public function options(): array 46 | { 47 | return $this->options; 48 | } 49 | 50 | /** 51 | * @param AbstractOption ...$options 52 | * 53 | * @return $this 54 | */ 55 | public function with(AbstractOption ...$options): self 56 | { 57 | $self = clone $this; 58 | $self->options = array_merge($this->options, $options); 59 | 60 | return $self; 61 | } 62 | 63 | /** 64 | * @param bool $encoded 65 | * 66 | * @return $this 67 | */ 68 | public function encoded(bool $encoded): self 69 | { 70 | $self = clone $this; 71 | $self->encoded = $encoded; 72 | 73 | return $self; 74 | } 75 | 76 | /** 77 | * @param int $size 78 | * 79 | * @return self 80 | */ 81 | public function split(int $size): self 82 | { 83 | $self = clone $this; 84 | $self->splitSize = $size; 85 | 86 | return $self; 87 | } 88 | 89 | /** 90 | * @param string $src 91 | * @param string|null $extension 92 | * 93 | * @return string 94 | */ 95 | public function url(string $src, ?string $extension = null): string 96 | { 97 | $format = $extension ? new ImageFormat($extension) : null; 98 | 99 | $opt = implode('/', $this->options); 100 | $path = sprintf('/%s/%s', $opt, $this->source($src, $format)); 101 | 102 | return sprintf('/%s%s', $this->signature($path), $path); 103 | } 104 | 105 | /** 106 | * @param string $src 107 | * @param ImageFormat|null $format 108 | * 109 | * @return string 110 | */ 111 | private function source(string $src, ?ImageFormat $format): string 112 | { 113 | if ($this->encoded) { 114 | $sep = '.'; 115 | $source = $this->encode($src); 116 | 117 | if ($this->splitSize > 0) { 118 | $source = wordwrap($source, $this->splitSize, '/', true); 119 | } 120 | } else { 121 | $sep = '@'; 122 | $source = str_replace($sep, '%40', 'plain/' . $src); 123 | } 124 | 125 | $extension = null; 126 | if ($format && ($this->encoded || !$format->isEquals($this->extension($src)))) { 127 | $extension = $format->value(); 128 | } 129 | 130 | return implode($sep, array_filter([$source, $extension])); 131 | } 132 | 133 | /** 134 | * @param string $url 135 | * 136 | * @return string 137 | */ 138 | private function encode(string $url): string 139 | { 140 | return rtrim(strtr(base64_encode($url), '+/', '-_'), '='); 141 | } 142 | 143 | /** 144 | * @param string $path 145 | * 146 | * @return string 147 | */ 148 | private function signature(string $path): string 149 | { 150 | if ($this->signer !== null) { 151 | return $this->encode($this->signer->sign($path)); 152 | } 153 | 154 | return self::INSECURE_SIGN; 155 | } 156 | 157 | /** 158 | * @param string $src 159 | * 160 | * @return string 161 | */ 162 | private function extension(string $src): string 163 | { 164 | return pathinfo(parse_url($src, PHP_URL_PATH) ?: '', PATHINFO_EXTENSION); 165 | } 166 | } 167 | --------------------------------------------------------------------------------