mirror of
https://github.com/Intervention/image.git
synced 2025-01-16 19:58:14 +01:00
Version 3 prototype
This commit is contained in:
parent
a1abc986fd
commit
95e72b877b
36
.travis.yml
36
.travis.yml
@ -1,36 +0,0 @@
|
||||
language: php
|
||||
|
||||
sudo: false
|
||||
|
||||
jobs:
|
||||
include:
|
||||
- dist: trusty
|
||||
php: 5.4
|
||||
- dist: trusty
|
||||
php: 5.5
|
||||
- dist: xenial
|
||||
php: 5.6
|
||||
- dist: xenial
|
||||
php: 7.0
|
||||
- dist: xenial
|
||||
php: 7.1
|
||||
- dist: xenial
|
||||
php: 7.2
|
||||
- dist: xenial
|
||||
php: 7.3
|
||||
- dist: xenial
|
||||
php: 7.4
|
||||
- dist: xenial
|
||||
php: nightly
|
||||
- dist: xenial
|
||||
php: hhvm
|
||||
allow_failures:
|
||||
- php: nightly
|
||||
- php: hhvm
|
||||
|
||||
before_script:
|
||||
- printf "\n" | pecl install imagick
|
||||
- composer self-update || true
|
||||
- composer install --prefer-dist --no-interaction --no-progress --no-suggest --optimize-autoloader
|
||||
|
||||
script: vendor/bin/phpunit
|
9
LICENSE
9
LICENSE
@ -1,9 +0,0 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2014 Oliver Vogel
|
||||
|
||||
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.
|
55
README.md
55
README.md
@ -1,55 +0,0 @@
|
||||
# Intervention Image
|
||||
|
||||
Intervention Image is a **PHP image handling and manipulation** library providing an easier and expressive way to create, edit, and compose images. The package includes ServiceProviders and Facades for easy **Laravel** integration.
|
||||
|
||||
[![Latest Version](https://img.shields.io/packagist/v/intervention/image.svg)](https://packagist.org/packages/intervention/image)
|
||||
[![Build Status](https://travis-ci.org/Intervention/image.png?branch=master)](https://travis-ci.org/Intervention/image)
|
||||
[![Monthly Downloads](https://img.shields.io/packagist/dm/intervention/image.svg)](https://packagist.org/packages/intervention/image/stats)
|
||||
|
||||
## Requirements
|
||||
|
||||
- PHP >=5.4
|
||||
- Fileinfo Extension
|
||||
|
||||
## Supported Image Libraries
|
||||
|
||||
- GD Library (>=2.0)
|
||||
- Imagick PHP extension (>=6.5.7)
|
||||
|
||||
## Getting started
|
||||
|
||||
- [Installation](http://image.intervention.io/getting_started/installation)
|
||||
- [Laravel Framework Integration](http://image.intervention.io/getting_started/installation#laravel)
|
||||
- [Basic Usage](http://image.intervention.io/use/basics)
|
||||
|
||||
## Code Examples
|
||||
|
||||
```php
|
||||
// open an image file
|
||||
$img = Image::make('public/foo.jpg');
|
||||
|
||||
// resize image instance
|
||||
$img->resize(320, 240);
|
||||
|
||||
// insert a watermark
|
||||
$img->insert('public/watermark.png');
|
||||
|
||||
// save image in desired format
|
||||
$img->save('public/bar.jpg');
|
||||
```
|
||||
|
||||
Refer to the [official documentation](http://image.intervention.io/) to learn more about Intervention Image.
|
||||
|
||||
## Contributing
|
||||
|
||||
Contributions to the Intervention Image library are welcome. Please note the following guidelines before submitting your pull request.
|
||||
|
||||
- Follow [PSR-2](http://www.php-fig.org/psr/psr-2/) coding standards.
|
||||
- Write tests for new functions and added features
|
||||
- API calls should work consistently with both GD and Imagick drivers
|
||||
|
||||
## License
|
||||
|
||||
Intervention Image is licensed under the [MIT License](http://opensource.org/licenses/MIT).
|
||||
|
||||
Copyright 2017 [Oliver Vogel](http://olivervogel.com/)
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "intervention/image",
|
||||
"description": "Image handling and manipulation library with support for Laravel integration",
|
||||
"description": "PHP image manipulation",
|
||||
"homepage": "http://image.intervention.io/",
|
||||
"keywords": ["image", "gd", "imagick", "laravel", "watermark", "thumbnail"],
|
||||
"license": "MIT",
|
||||
@ -8,40 +8,25 @@
|
||||
{
|
||||
"name": "Oliver Vogel",
|
||||
"email": "oliver@olivervogel.com",
|
||||
"homepage": "http://olivervogel.com/"
|
||||
"homepage": "http://intervention.io/"
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"php": ">=5.4.0",
|
||||
"ext-fileinfo": "*",
|
||||
"guzzlehttp/psr7": "~1.1 || ^2.0"
|
||||
"php": "^8",
|
||||
"intervention/gif": "dev-master",
|
||||
"intervention/mimesniffer": "^0.4.2"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^4.8 || ^5.7 || ^7.5.15",
|
||||
"mockery/mockery": "~0.9.2"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-gd": "to use GD library based image processing.",
|
||||
"ext-imagick": "to use Imagick based image processing.",
|
||||
"intervention/imagecache": "Caching extension for the Intervention Image library"
|
||||
"phpunit/phpunit": "^9"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Intervention\\Image\\": "src/Intervention/Image"
|
||||
"Intervention\\Image\\": "src"
|
||||
}
|
||||
},
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "2.4-dev"
|
||||
},
|
||||
"laravel": {
|
||||
"providers": [
|
||||
"Intervention\\Image\\ImageServiceProvider"
|
||||
],
|
||||
"aliases": {
|
||||
"Image": "Intervention\\Image\\Facades\\Image"
|
||||
}
|
||||
"autoload-dev": {
|
||||
"psr-4": {
|
||||
"Intervention\\Image\\Tests\\": "tests"
|
||||
}
|
||||
},
|
||||
"minimum-stability": "stable"
|
||||
}
|
||||
}
|
||||
|
@ -8,7 +8,6 @@
|
||||
convertWarningsToExceptions="true"
|
||||
processIsolation="false"
|
||||
stopOnFailure="false"
|
||||
syntaxCheck="false"
|
||||
>
|
||||
<testsuites>
|
||||
<testsuite name="Package Test Suite">
|
||||
|
@ -1,11 +0,0 @@
|
||||
{
|
||||
"providers": [
|
||||
"Intervention\\Image\\ImageServiceProvider"
|
||||
],
|
||||
"aliases": [
|
||||
{
|
||||
"alias": "Image",
|
||||
"facade": "Intervention\\Image\\Facades\\Image"
|
||||
}
|
||||
]
|
||||
}
|
137
src/Collection.php
Normal file
137
src/Collection.php
Normal file
@ -0,0 +1,137 @@
|
||||
<?php
|
||||
|
||||
namespace Intervention\Image;
|
||||
|
||||
use Intervention\Image\Exceptions\RuntimeException;
|
||||
use Intervention\Image\Interfaces\CollectionInterface;
|
||||
use ArrayIterator;
|
||||
use Countable;
|
||||
use IteratorAggregate;
|
||||
|
||||
class Collection implements CollectionInterface, IteratorAggregate, Countable
|
||||
{
|
||||
/**
|
||||
* Create a collection.
|
||||
*
|
||||
* @param array $items
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(protected array $items = [])
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Static constructor
|
||||
*
|
||||
* @param array $items
|
||||
* @return self
|
||||
*/
|
||||
public static function create(array $items = []): self
|
||||
{
|
||||
return new self($items);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns Iterator
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getIterator()
|
||||
{
|
||||
return new ArrayIterator($this->items);
|
||||
}
|
||||
|
||||
public function toArray(): array
|
||||
{
|
||||
return $this->items;
|
||||
}
|
||||
|
||||
/**
|
||||
* Count items in collection
|
||||
*
|
||||
* @return integer
|
||||
*/
|
||||
public function count(): int
|
||||
{
|
||||
return count($this->items);
|
||||
}
|
||||
|
||||
/**
|
||||
* Append new item to collection
|
||||
*
|
||||
* @param mixed $item
|
||||
* @return CollectionInterface
|
||||
*/
|
||||
public function push($item): CollectionInterface
|
||||
{
|
||||
$this->items[] = $item;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return first item in collection
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function first()
|
||||
{
|
||||
if ($item = reset($this->items)) {
|
||||
return $item;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns last item in collection
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function last()
|
||||
{
|
||||
if ($item = end($this->items)) {
|
||||
return $item;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return item with given key
|
||||
*
|
||||
* @param integer $key
|
||||
* @return mixed
|
||||
*/
|
||||
public function get(int $key = 0)
|
||||
{
|
||||
if (! array_key_exists($key, $this->items)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $this->items[$key];
|
||||
}
|
||||
|
||||
public function map(callable $callback): self
|
||||
{
|
||||
$items = array_map(function ($item) use ($callback) {
|
||||
return $callback($item);
|
||||
}, $this->items);
|
||||
|
||||
return new self($items);
|
||||
}
|
||||
|
||||
public function pushEach(array $data, ?callable $callback = null): CollectionInterface
|
||||
{
|
||||
if (! is_iterable($data)) {
|
||||
throw new RuntimeException('Unable to iterate given data.');
|
||||
}
|
||||
|
||||
foreach ($data as $item) {
|
||||
$this->push(is_callable($callback) ? $callback($item) : $item);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
17
src/Drivers/Abstract/AbstractColor.php
Normal file
17
src/Drivers/Abstract/AbstractColor.php
Normal file
@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
namespace Intervention\Image\Drivers\Abstract;
|
||||
|
||||
abstract class AbstractColor
|
||||
{
|
||||
public function toHex(string $prefix = ''): string
|
||||
{
|
||||
return sprintf(
|
||||
'%s%02x%02x%02x',
|
||||
$prefix,
|
||||
$this->red(),
|
||||
$this->green(),
|
||||
$this->blue()
|
||||
);
|
||||
}
|
||||
}
|
8
src/Drivers/Abstract/AbstractFrame.php
Normal file
8
src/Drivers/Abstract/AbstractFrame.php
Normal file
@ -0,0 +1,8 @@
|
||||
<?php
|
||||
|
||||
namespace Intervention\Image\Drivers\Abstract;
|
||||
|
||||
abstract class AbstractFrame
|
||||
{
|
||||
//
|
||||
}
|
81
src/Drivers/Abstract/AbstractImage.php
Normal file
81
src/Drivers/Abstract/AbstractImage.php
Normal file
@ -0,0 +1,81 @@
|
||||
<?php
|
||||
|
||||
namespace Intervention\Image\Drivers\Abstract;
|
||||
|
||||
use Intervention\Image\Collection;
|
||||
use Intervention\Image\Exceptions\NotWritableException;
|
||||
use Intervention\Image\Geometry\Size;
|
||||
use Intervention\Image\Interfaces\EncoderInterface;
|
||||
use Intervention\Image\Interfaces\FrameInterface;
|
||||
use Intervention\Image\Interfaces\ImageInterface;
|
||||
use Intervention\Image\Interfaces\SizeInterface;
|
||||
use Intervention\Image\Traits\CanResolveDriverClass;
|
||||
|
||||
abstract class AbstractImage
|
||||
{
|
||||
use CanResolveDriverClass;
|
||||
|
||||
public function getIterator(): Collection
|
||||
{
|
||||
return $this->frames;
|
||||
}
|
||||
|
||||
public function getFrames(): Collection
|
||||
{
|
||||
return $this->frames;
|
||||
}
|
||||
|
||||
public function addFrame(FrameInterface $frame): ImageInterface
|
||||
{
|
||||
$this->frames->push($frame);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function size(): SizeInterface
|
||||
{
|
||||
return new Size($this->width(), $this->height());
|
||||
}
|
||||
|
||||
public function isAnimated(): bool
|
||||
{
|
||||
return $this->getFrames()->count() > 1;
|
||||
}
|
||||
|
||||
public function modify(ModifierInterface $modifier): ImageInterface
|
||||
{
|
||||
return $modifier->apply($this);
|
||||
}
|
||||
|
||||
public function encode(EncoderInterface $encoder, ?string $path = null): string
|
||||
{
|
||||
$encoded = $encoder->encode($this);
|
||||
|
||||
if ($path) {
|
||||
$saved = @file_put_contents($path, $encoded);
|
||||
if ($saved === false) {
|
||||
throw new NotWritableException(
|
||||
"Can't write image data to path ({$path})."
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return $encoded;
|
||||
}
|
||||
|
||||
public function toJpeg(?int $quality = null, ?string $path = null): string
|
||||
{
|
||||
return $this->encode(
|
||||
$this->resolveDriverClass('Encoders\JpegEncoder', $quality),
|
||||
$path
|
||||
);
|
||||
}
|
||||
|
||||
public function toGif(?string $path = null): string
|
||||
{
|
||||
return $this->encode(
|
||||
$this->resolveDriverClass('Encoders\GifEncoder'),
|
||||
$path
|
||||
);
|
||||
}
|
||||
}
|
17
src/Drivers/Abstract/AbstractInputHandler.php
Normal file
17
src/Drivers/Abstract/AbstractInputHandler.php
Normal file
@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
namespace Intervention\Image\Drivers\Abstract;
|
||||
|
||||
use Intervention\Image\Drivers\Abstract\Decoders\AbstractDecoder;
|
||||
use Intervention\Image\Interfaces\ColorInterface;
|
||||
use Intervention\Image\Interfaces\ImageInterface;
|
||||
|
||||
abstract class AbstractInputHandler
|
||||
{
|
||||
abstract protected function chain(): AbstractDecoder;
|
||||
|
||||
public function handle($input): ImageInterface|ColorInterface
|
||||
{
|
||||
return $this->chain()->handle($input);
|
||||
}
|
||||
}
|
47
src/Drivers/Abstract/Decoders/AbstractDecoder.php
Normal file
47
src/Drivers/Abstract/Decoders/AbstractDecoder.php
Normal file
@ -0,0 +1,47 @@
|
||||
<?php
|
||||
|
||||
namespace Intervention\Image\Drivers\Abstract\Decoders;
|
||||
|
||||
use Intervention\Image\Exceptions\DecoderException;
|
||||
use Intervention\Image\Interfaces\ColorInterface;
|
||||
use Intervention\Image\Interfaces\ImageInterface;
|
||||
use Intervention\MimeSniffer\MimeSniffer;
|
||||
use Intervention\MimeSniffer\AbstractType;
|
||||
|
||||
abstract class AbstractDecoder
|
||||
{
|
||||
public function __construct(protected ?AbstractDecoder $successor = null)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
final public function handle($input): null|ImageInterface|ColorInterface
|
||||
{
|
||||
try {
|
||||
$decoded = $this->decode($input);
|
||||
} catch (DecoderException $e) {
|
||||
if ($this->hasSuccessor()) {
|
||||
return $this->successor->handle($input);
|
||||
}
|
||||
|
||||
$this->fail();
|
||||
}
|
||||
|
||||
return $decoded;
|
||||
}
|
||||
|
||||
protected function hasSuccessor(): bool
|
||||
{
|
||||
return $this->successor !== null;
|
||||
}
|
||||
|
||||
protected function fail(): void
|
||||
{
|
||||
throw new DecoderException("Unable to decode given input.");
|
||||
}
|
||||
|
||||
protected function inputType($input): AbstractType
|
||||
{
|
||||
return MimeSniffer::createFromString($input)->getType();
|
||||
}
|
||||
}
|
41
src/Drivers/Abstract/Encoders/AbstractEncoder.php
Normal file
41
src/Drivers/Abstract/Encoders/AbstractEncoder.php
Normal file
@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
namespace Intervention\Image\Drivers\Abstract\Encoders;
|
||||
|
||||
use Intervention\Image\Interfaces\EncoderInterface;
|
||||
|
||||
abstract class AbstractEncoder
|
||||
{
|
||||
public function __construct(protected ?int $quality = null)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Get return value of callback through output buffer
|
||||
*
|
||||
* @param callable $callback
|
||||
* @return string
|
||||
*/
|
||||
protected function getBuffered(callable $callback): string
|
||||
{
|
||||
ob_start();
|
||||
$callback();
|
||||
$buffer = ob_get_contents();
|
||||
ob_end_clean();
|
||||
|
||||
return $buffer;
|
||||
}
|
||||
|
||||
public function setQuality(int $quality): EncoderInterface
|
||||
{
|
||||
$this->quality = $quality;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getQuality(): int
|
||||
{
|
||||
return $this->quality;
|
||||
}
|
||||
}
|
57
src/Drivers/Gd/Color.php
Normal file
57
src/Drivers/Gd/Color.php
Normal file
@ -0,0 +1,57 @@
|
||||
<?php
|
||||
|
||||
namespace Intervention\Image\Drivers\Gd;
|
||||
|
||||
use Intervention\Image\Drivers\Abstract\AbstractColor;
|
||||
use Intervention\Image\Interfaces\ColorInterface;
|
||||
|
||||
class Color extends AbstractColor implements ColorInterface
|
||||
{
|
||||
/**
|
||||
* GD library integer value of color
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $value;
|
||||
|
||||
/**
|
||||
* Create new color instance
|
||||
*
|
||||
* @param int $value
|
||||
*/
|
||||
public function __construct(int $value = 0)
|
||||
{
|
||||
$this->value = $value;
|
||||
}
|
||||
|
||||
public function red(): int
|
||||
{
|
||||
return $this->toArray()[0];
|
||||
}
|
||||
|
||||
public function green(): int
|
||||
{
|
||||
return $this->toArray()[1];
|
||||
}
|
||||
|
||||
public function blue(): int
|
||||
{
|
||||
return $this->toArray()[2];
|
||||
}
|
||||
|
||||
public function alpha(): float
|
||||
{
|
||||
return $this->toArray()[3];
|
||||
}
|
||||
|
||||
public function toArray(): array
|
||||
{
|
||||
$a = ($this->value >> 24) & 0xFF;
|
||||
$r = ($this->value >> 16) & 0xFF;
|
||||
$g = ($this->value >> 8) & 0xFF;
|
||||
$b = $this->value & 0xFF;
|
||||
$a = (float) round(1 - $a / 127, 2);
|
||||
|
||||
return [$r, $g, $b, $a];
|
||||
}
|
||||
}
|
33
src/Drivers/Gd/Decoders/ArrayColorDecoder.php
Normal file
33
src/Drivers/Gd/Decoders/ArrayColorDecoder.php
Normal file
@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
namespace Intervention\Image\Drivers\Gd\Decoders;
|
||||
|
||||
use Intervention\Image\Drivers\Abstract\Decoders\AbstractDecoder;
|
||||
use Intervention\Image\Drivers\Gd\Color;
|
||||
use Intervention\Image\Interfaces\ColorInterface;
|
||||
use Intervention\Image\Interfaces\DecoderInterface;
|
||||
use Intervention\Image\Interfaces\ImageInterface;
|
||||
use Intervention\Image\Traits\CanValidateColorArray;
|
||||
|
||||
class ArrayColorDecoder extends AbstractDecoder implements DecoderInterface
|
||||
{
|
||||
use CanValidateColorArray;
|
||||
|
||||
public function decode($input): ImageInterface|ColorInterface
|
||||
{
|
||||
if (! $this->isValidColorArray($input)) {
|
||||
$this->fail();
|
||||
}
|
||||
|
||||
list($r, $g, $b, $a) = $input;
|
||||
|
||||
return new Color(
|
||||
($this->opacityToGdAlpha($a) << 24) + ($r << 16) + ($g << 8) + $b
|
||||
);
|
||||
}
|
||||
|
||||
protected function opacityToGdAlpha(float $opacity): int
|
||||
{
|
||||
return intval(round($opacity * 127 * -1 + 127));
|
||||
}
|
||||
}
|
22
src/Drivers/Gd/Decoders/Base64ImageDecoder.php
Normal file
22
src/Drivers/Gd/Decoders/Base64ImageDecoder.php
Normal file
@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
namespace Intervention\Image\Drivers\Gd\Decoders;
|
||||
|
||||
use Intervention\Image\Interfaces\ColorInterface;
|
||||
use Intervention\Image\Interfaces\DecoderInterface;
|
||||
use Intervention\Image\Interfaces\ImageInterface;
|
||||
use Intervention\Image\Traits\CanValidateBase64;
|
||||
|
||||
class Base64ImageDecoder extends BinaryImageDecoder implements DecoderInterface
|
||||
{
|
||||
use CanValidateBase64;
|
||||
|
||||
public function decode($input): ImageInterface|ColorInterface
|
||||
{
|
||||
if (! $this->isValidBase64($input)) {
|
||||
$this->fail();
|
||||
}
|
||||
|
||||
return parent::decode(base64_decode($input));
|
||||
}
|
||||
}
|
55
src/Drivers/Gd/Decoders/BinaryImageDecoder.php
Normal file
55
src/Drivers/Gd/Decoders/BinaryImageDecoder.php
Normal file
@ -0,0 +1,55 @@
|
||||
<?php
|
||||
|
||||
namespace Intervention\Image\Drivers\Gd\Decoders;
|
||||
|
||||
use Intervention\Image\Collection;
|
||||
use Intervention\Image\Drivers\Abstract\Decoders\AbstractDecoder;
|
||||
use Intervention\Image\Drivers\Gd\Frame;
|
||||
use Intervention\Image\Drivers\Gd\Image;
|
||||
use Intervention\Image\Interfaces\ColorInterface;
|
||||
use Intervention\Image\Interfaces\DecoderInterface;
|
||||
use Intervention\Image\Interfaces\ImageInterface;
|
||||
use Intervention\MimeSniffer\MimeSniffer;
|
||||
use Intervention\MimeSniffer\Types\ImageGif;
|
||||
use Intervention\Gif\Decoder as GifDecoder;
|
||||
use Intervention\Gif\Splitter as GifSplitter;
|
||||
|
||||
class BinaryImageDecoder extends AbstractDecoder implements DecoderInterface
|
||||
{
|
||||
public function decode($input): ImageInterface|ColorInterface
|
||||
{
|
||||
if (! $this->inputType($input)->isBinary()) {
|
||||
$this->fail();
|
||||
}
|
||||
|
||||
if (is_a($this->inputType($input), ImageGif::class)) {
|
||||
return $this->decodeGif($input); // decode (animated) gif
|
||||
}
|
||||
|
||||
$resource = @imagecreatefromstring($input);
|
||||
|
||||
if ($resource === false) {
|
||||
$this->fail();
|
||||
}
|
||||
|
||||
return new Image(new Collection([new Frame($resource)]));
|
||||
}
|
||||
|
||||
protected function decodeGif($input): ImageInterface
|
||||
{
|
||||
$image = new Image(new Collection());
|
||||
$gif = GifDecoder::decode($input);
|
||||
|
||||
if (!$gif->isAnimated()) {
|
||||
return $image->addFrame(new Frame(@imagecreatefromstring($input)));
|
||||
}
|
||||
|
||||
$splitter = GifSplitter::create($gif)->split();
|
||||
$delays = $splitter->getDelays();
|
||||
foreach ($splitter->coalesceToResources() as $key => $gd) {
|
||||
$image->addFrame((new Frame($gd))->setDelay($delays[$key]));
|
||||
}
|
||||
|
||||
return $image;
|
||||
}
|
||||
}
|
33
src/Drivers/Gd/Decoders/DataUriImageDecoder.php
Normal file
33
src/Drivers/Gd/Decoders/DataUriImageDecoder.php
Normal file
@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
namespace Intervention\Image\Drivers\Gd\Decoders;
|
||||
|
||||
use Intervention\Image\Interfaces\ColorInterface;
|
||||
use Intervention\Image\Interfaces\DecoderInterface;
|
||||
use Intervention\Image\Interfaces\ImageInterface;
|
||||
use Intervention\Image\Traits\CanDecodeDataUri;
|
||||
use Intervention\MimeSniffer\MimeSniffer;
|
||||
|
||||
class DataUriImageDecoder extends BinaryImageDecoder implements DecoderInterface
|
||||
{
|
||||
use CanDecodeDataUri;
|
||||
|
||||
public function decode($input): ImageInterface|ColorInterface
|
||||
{
|
||||
if (!is_string($input)) {
|
||||
$this->fail();
|
||||
}
|
||||
|
||||
$uri = $this->decodeDataUri($input);
|
||||
|
||||
if (! $uri->isValid()) {
|
||||
$this->fail();
|
||||
}
|
||||
|
||||
if ($uri->isBase64Encoded()) {
|
||||
return parent::decode(base64_decode($uri->data()));
|
||||
}
|
||||
|
||||
return parent::decode(urldecode($uri->data()));
|
||||
}
|
||||
}
|
28
src/Drivers/Gd/Decoders/FilePathImageDecoder.php
Normal file
28
src/Drivers/Gd/Decoders/FilePathImageDecoder.php
Normal file
@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
namespace Intervention\Image\Drivers\Gd\Decoders;
|
||||
|
||||
use Exception;
|
||||
use Intervention\Image\Interfaces\ColorInterface;
|
||||
use Intervention\Image\Interfaces\DecoderInterface;
|
||||
use Intervention\Image\Interfaces\ImageInterface;
|
||||
|
||||
class FilePathImageDecoder extends BinaryImageDecoder implements DecoderInterface
|
||||
{
|
||||
public function decode($input): ImageInterface|ColorInterface
|
||||
{
|
||||
if (! is_string($input)) {
|
||||
$this->fail();
|
||||
}
|
||||
|
||||
try {
|
||||
if (! @is_file($input)) {
|
||||
$this->fail();
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
$this->fail();
|
||||
}
|
||||
|
||||
return parent::decode(file_get_contents($input));
|
||||
}
|
||||
}
|
33
src/Drivers/Gd/Encoders/GifEncoder.php
Normal file
33
src/Drivers/Gd/Encoders/GifEncoder.php
Normal file
@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
namespace Intervention\Image\Drivers\Gd\Encoders;
|
||||
|
||||
use Intervention\Image\Drivers\Abstract\Encoders\AbstractEncoder;
|
||||
use Intervention\Image\Interfaces\EncoderInterface;
|
||||
use Intervention\Image\Interfaces\ImageInterface;
|
||||
use Intervention\Gif\Builder as GifBuilder;
|
||||
|
||||
class GifEncoder extends AbstractEncoder implements EncoderInterface
|
||||
{
|
||||
public function encode(ImageInterface $image): string
|
||||
{
|
||||
if ($image->isAnimated()) {
|
||||
return $this->encodeAnimated($image);
|
||||
}
|
||||
|
||||
return $this->getBuffered(function () use ($image) {
|
||||
imagegif($image->getFrames()->first()->getCore());
|
||||
});
|
||||
}
|
||||
|
||||
protected function encodeAnimated($image): string
|
||||
{
|
||||
$builder = GifBuilder::canvas($image->width(), $image->height(), 2);
|
||||
foreach ($image as $key => $frame) {
|
||||
$source = $this->encode($frame->toImage());
|
||||
$builder->addFrame($source, $frame->getDelay());
|
||||
}
|
||||
|
||||
return $builder->encode();
|
||||
}
|
||||
}
|
17
src/Drivers/Gd/Encoders/JpegEncoder.php
Normal file
17
src/Drivers/Gd/Encoders/JpegEncoder.php
Normal file
@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
namespace Intervention\Image\Drivers\Gd\Encoders;
|
||||
|
||||
use Intervention\Image\Drivers\Abstract\Encoders\AbstractEncoder;
|
||||
use Intervention\Image\Interfaces\EncoderInterface;
|
||||
use Intervention\Image\Interfaces\ImageInterface;
|
||||
|
||||
class JpegEncoder extends AbstractEncoder implements EncoderInterface
|
||||
{
|
||||
public function encode(ImageInterface $image): string
|
||||
{
|
||||
return $this->getBuffered(function () use ($image) {
|
||||
imagejpeg($image->getFrames()->first()->getCore(), null, $this->quality);
|
||||
});
|
||||
}
|
||||
}
|
111
src/Drivers/Gd/Frame.php
Normal file
111
src/Drivers/Gd/Frame.php
Normal file
@ -0,0 +1,111 @@
|
||||
<?php
|
||||
|
||||
namespace Intervention\Image\Drivers\Gd;
|
||||
|
||||
use GdImage;
|
||||
use Intervention\Image\Collection;
|
||||
use Intervention\Image\Drivers\Abstract\AbstractFrame;
|
||||
use Intervention\Image\Interfaces\FrameInterface;
|
||||
use Intervention\Image\Interfaces\ImageInterface;
|
||||
|
||||
class Frame extends AbstractFrame implements FrameInterface
|
||||
{
|
||||
/**
|
||||
* Delay time in miliseconds after next frame is shown
|
||||
*
|
||||
* @var integer
|
||||
*/
|
||||
protected $delay = 0;
|
||||
|
||||
/**
|
||||
* Disposal method of frame
|
||||
*
|
||||
* @var integer
|
||||
*/
|
||||
protected $dispose = 1;
|
||||
|
||||
/**
|
||||
* Left offset in pixel
|
||||
*
|
||||
* @var integer
|
||||
*/
|
||||
protected $offset_left = 0;
|
||||
|
||||
/**
|
||||
* Top offset in pixel
|
||||
*
|
||||
* @var integer
|
||||
*/
|
||||
protected $offset_top = 0;
|
||||
|
||||
public function __construct(protected GdImage $core)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
public function getCore(): GdImage
|
||||
{
|
||||
return $this->core;
|
||||
}
|
||||
|
||||
public function getDelay(): int
|
||||
{
|
||||
return $this->delay;
|
||||
}
|
||||
|
||||
public function setDelay(int $delay): FrameInterface
|
||||
{
|
||||
$this->delay = $delay;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getDispose(): int
|
||||
{
|
||||
return $this->dispose;
|
||||
}
|
||||
|
||||
public function setDispose(int $dispose): FrameInterface
|
||||
{
|
||||
$this->dispose = $dispose;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setOffset(int $left, int $top): FrameInterface
|
||||
{
|
||||
$this->offset_left = $left;
|
||||
$this->offset_top = $top;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getOffsetLeft(): int
|
||||
{
|
||||
return $this->offset_left;
|
||||
}
|
||||
|
||||
public function setOffsetLeft(int $offset): FrameInterface
|
||||
{
|
||||
$this->offset_left = $offset;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getOffsetTop(): int
|
||||
{
|
||||
return $this->offset_top;
|
||||
}
|
||||
|
||||
public function setOffsetTop(int $offset): FrameInterface
|
||||
{
|
||||
$this->offset_top = $offset;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function toImage(): ImageInterface
|
||||
{
|
||||
return new Image(new Collection([$this]));
|
||||
}
|
||||
}
|
36
src/Drivers/Gd/Image.php
Normal file
36
src/Drivers/Gd/Image.php
Normal file
@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
namespace Intervention\Image\Drivers\Gd;
|
||||
|
||||
use GdImage;
|
||||
use Intervention\Image\Collection;
|
||||
use Intervention\Image\Drivers\Abstract\AbstractImage;
|
||||
use Intervention\Image\Drivers\Gd\Frame;
|
||||
use Intervention\Image\Geometry\Size;
|
||||
use Intervention\Image\Interfaces\EncoderInterface;
|
||||
use Intervention\Image\Interfaces\ImageInterface;
|
||||
use Intervention\Image\Interfaces\SizeInterface;
|
||||
use IteratorAggregate;
|
||||
|
||||
class Image extends AbstractImage implements ImageInterface, IteratorAggregate
|
||||
{
|
||||
public function __construct(protected Collection $frames)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
public function width(): int
|
||||
{
|
||||
return imagesx($this->frames->first()->getCore());
|
||||
}
|
||||
|
||||
public function height(): int
|
||||
{
|
||||
return imagesy($this->frames->first()->getCore());
|
||||
}
|
||||
|
||||
public function greyscale(): ImageInterface
|
||||
{
|
||||
return $this->modify(new Modifiers\GreyscaleModifier());
|
||||
}
|
||||
}
|
19
src/Drivers/Gd/ImageFactory.php
Normal file
19
src/Drivers/Gd/ImageFactory.php
Normal file
@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
namespace Intervention\Image\Drivers\Gd;
|
||||
|
||||
use Intervention\Image\Collection;
|
||||
use Intervention\Image\Interfaces\FactoryInterface;
|
||||
use Intervention\Image\Interfaces\ImageInterface;
|
||||
|
||||
class ImageFactory implements FactoryInterface
|
||||
{
|
||||
public function newImage(int $width, int $height): ImageInterface
|
||||
{
|
||||
$gd = imagecreatetruecolor($width, $height);
|
||||
|
||||
return new Image(new Collection([
|
||||
new Frame($gd)
|
||||
]));
|
||||
}
|
||||
}
|
22
src/Drivers/Gd/InputHandler.php
Normal file
22
src/Drivers/Gd/InputHandler.php
Normal file
@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
namespace Intervention\Image\Drivers\Gd;
|
||||
|
||||
use Intervention\Image\Drivers\Abstract\AbstractInputHandler;
|
||||
use Intervention\Image\Drivers\Abstract\Decoders\AbstractDecoder;
|
||||
|
||||
class InputHandler extends AbstractInputHandler
|
||||
{
|
||||
protected function chain(): AbstractDecoder
|
||||
{
|
||||
return new Decoders\ArrayColorDecoder(
|
||||
new Decoders\FilePathImageDecoder(
|
||||
new Decoders\BinaryImageDecoder(
|
||||
new Decoders\DataUriImageDecoder(
|
||||
new Decoders\Base64ImageDecoder()
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
18
src/Drivers/Gd/Modifiers/GreyscaleModifier.php
Normal file
18
src/Drivers/Gd/Modifiers/GreyscaleModifier.php
Normal file
@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
namespace Intervention\Image\Drivers\Gd\Modifiers;
|
||||
|
||||
use Intervention\Image\Interfaces\ImageInterface;
|
||||
use Intervention\Image\Interfaces\ModifierInterface;
|
||||
|
||||
class GreyscaleModifier implements ModifierInterface
|
||||
{
|
||||
public function apply(ImageInterface $image): ImageInterface
|
||||
{
|
||||
foreach ($image as $frame) {
|
||||
imagefilter($frame->getCore(), IMG_FILTER_GRAYSCALE);
|
||||
}
|
||||
|
||||
return $image;
|
||||
}
|
||||
}
|
53
src/Drivers/Imagick/Color.php
Normal file
53
src/Drivers/Imagick/Color.php
Normal file
@ -0,0 +1,53 @@
|
||||
<?php
|
||||
|
||||
namespace Intervention\Image\Drivers\Imagick;
|
||||
|
||||
use Imagick;
|
||||
use ImagickPixel;
|
||||
use Intervention\Image\Drivers\Abstract\AbstractColor;
|
||||
use Intervention\Image\Interfaces\ColorInterface;
|
||||
|
||||
class Color extends AbstractColor implements ColorInterface
|
||||
{
|
||||
/**
|
||||
* Imagick pixel to represent color
|
||||
*
|
||||
* @var ImagickPixel
|
||||
*/
|
||||
protected $pixel;
|
||||
|
||||
public function __construct(ImagickPixel $pixel)
|
||||
{
|
||||
$this->pixel = $pixel;
|
||||
}
|
||||
|
||||
public function red(): int
|
||||
{
|
||||
return round($this->pixel->getColorValue(Imagick::COLOR_RED) * 255);
|
||||
}
|
||||
|
||||
public function green(): int
|
||||
{
|
||||
return round($this->pixel->getColorValue(Imagick::COLOR_GREEN) * 255);
|
||||
}
|
||||
|
||||
public function blue(): int
|
||||
{
|
||||
return round($this->pixel->getColorValue(Imagick::COLOR_BLUE) * 255);
|
||||
}
|
||||
|
||||
public function alpha(): float
|
||||
{
|
||||
return round($this->pixel->getColorValue(Imagick::COLOR_ALPHA), 2);
|
||||
}
|
||||
|
||||
public function toArray(): array
|
||||
{
|
||||
return [
|
||||
$this->red(),
|
||||
$this->green(),
|
||||
$this->blue(),
|
||||
$this->alpha()
|
||||
];
|
||||
}
|
||||
}
|
31
src/Drivers/Imagick/Decoders/ArrayColorDecoder.php
Normal file
31
src/Drivers/Imagick/Decoders/ArrayColorDecoder.php
Normal file
@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
namespace Intervention\Image\Drivers\Imagick\Decoders;
|
||||
|
||||
use ImagickPixel;
|
||||
use Intervention\Image\Drivers\Abstract\Decoders\AbstractDecoder;
|
||||
use Intervention\Image\Drivers\Imagick\Color;
|
||||
use Intervention\Image\Interfaces\ColorInterface;
|
||||
use Intervention\Image\Interfaces\DecoderInterface;
|
||||
use Intervention\Image\Interfaces\ImageInterface;
|
||||
use Intervention\Image\Traits\CanValidateColorArray;
|
||||
|
||||
class ArrayColorDecoder extends AbstractDecoder implements DecoderInterface
|
||||
{
|
||||
use CanValidateColorArray;
|
||||
|
||||
public function decode($input): ImageInterface|ColorInterface
|
||||
{
|
||||
if (! $this->isValidColorArray($input)) {
|
||||
$this->fail();
|
||||
}
|
||||
|
||||
list($r, $g, $b, $a) = $input;
|
||||
|
||||
$pixel = new ImagickPixel(
|
||||
sprintf('rgba(%d, %d, %d, %.2F)', $r, $g, $b, $a)
|
||||
);
|
||||
|
||||
return new Color($pixel);
|
||||
}
|
||||
}
|
22
src/Drivers/Imagick/Decoders/Base64ImageDecoder.php
Normal file
22
src/Drivers/Imagick/Decoders/Base64ImageDecoder.php
Normal file
@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
namespace Intervention\Image\Drivers\Imagick\Decoders;
|
||||
|
||||
use Intervention\Image\Interfaces\ColorInterface;
|
||||
use Intervention\Image\Interfaces\DecoderInterface;
|
||||
use Intervention\Image\Interfaces\ImageInterface;
|
||||
use Intervention\Image\Traits\CanValidateBase64;
|
||||
|
||||
class Base64ImageDecoder extends BinaryImageDecoder implements DecoderInterface
|
||||
{
|
||||
use CanValidateBase64;
|
||||
|
||||
public function decode($input): ImageInterface|ColorInterface
|
||||
{
|
||||
if (! $this->isValidBase64($input)) {
|
||||
$this->fail();
|
||||
}
|
||||
|
||||
return parent::decode(base64_decode($input));
|
||||
}
|
||||
}
|
34
src/Drivers/Imagick/Decoders/BinaryImageDecoder.php
Normal file
34
src/Drivers/Imagick/Decoders/BinaryImageDecoder.php
Normal file
@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
namespace Intervention\Image\Drivers\Imagick\Decoders;
|
||||
|
||||
use Imagick;
|
||||
use Intervention\Image\Collection;
|
||||
use Intervention\Image\Drivers\Abstract\Decoders\AbstractDecoder;
|
||||
use Intervention\Image\Drivers\Imagick\Frame;
|
||||
use Intervention\Image\Drivers\Imagick\Image;
|
||||
use Intervention\Image\Interfaces\ColorInterface;
|
||||
use Intervention\Image\Interfaces\DecoderInterface;
|
||||
use Intervention\Image\Interfaces\ImageInterface;
|
||||
|
||||
class BinaryImageDecoder extends AbstractDecoder implements DecoderInterface
|
||||
{
|
||||
public function decode($input): ImageInterface|ColorInterface
|
||||
{
|
||||
if (! $this->inputType($input)->isBinary()) {
|
||||
$this->fail();
|
||||
}
|
||||
|
||||
$imagick = new Imagick();
|
||||
$imagick->readImageBlob($input);
|
||||
$imagick = $imagick->coalesceImages();
|
||||
|
||||
$image = new Image(new Collection());
|
||||
|
||||
foreach ($imagick as $frame_content) {
|
||||
$image->addFrame(new Frame($frame_content));
|
||||
}
|
||||
|
||||
return $image;
|
||||
}
|
||||
}
|
33
src/Drivers/Imagick/Decoders/DataUriImageDecoder.php
Normal file
33
src/Drivers/Imagick/Decoders/DataUriImageDecoder.php
Normal file
@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
namespace Intervention\Image\Drivers\Imagick\Decoders;
|
||||
|
||||
use Intervention\Image\Interfaces\ColorInterface;
|
||||
use Intervention\Image\Interfaces\DecoderInterface;
|
||||
use Intervention\Image\Interfaces\ImageInterface;
|
||||
use Intervention\Image\Traits\CanDecodeDataUri;
|
||||
use Intervention\MimeSniffer\MimeSniffer;
|
||||
|
||||
class DataUriImageDecoder extends BinaryImageDecoder implements DecoderInterface
|
||||
{
|
||||
use CanDecodeDataUri;
|
||||
|
||||
public function decode($input): ImageInterface|ColorInterface
|
||||
{
|
||||
if (!is_string($input)) {
|
||||
$this->fail();
|
||||
}
|
||||
|
||||
$uri = $this->decodeDataUri($input);
|
||||
|
||||
if (! $uri->isValid()) {
|
||||
$this->fail();
|
||||
}
|
||||
|
||||
if ($uri->isBase64Encoded()) {
|
||||
return parent::decode(base64_decode($uri->data()));
|
||||
}
|
||||
|
||||
return parent::decode(urldecode($uri->data()));
|
||||
}
|
||||
}
|
28
src/Drivers/Imagick/Decoders/FilePathImageDecoder.php
Normal file
28
src/Drivers/Imagick/Decoders/FilePathImageDecoder.php
Normal file
@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
namespace Intervention\Image\Drivers\Imagick\Decoders;
|
||||
|
||||
use Exception;
|
||||
use Intervention\Image\Interfaces\ColorInterface;
|
||||
use Intervention\Image\Interfaces\DecoderInterface;
|
||||
use Intervention\Image\Interfaces\ImageInterface;
|
||||
|
||||
class FilePathImageDecoder extends BinaryImageDecoder implements DecoderInterface
|
||||
{
|
||||
public function decode($input): ImageInterface|ColorInterface
|
||||
{
|
||||
if (! is_string($input)) {
|
||||
$this->fail();
|
||||
}
|
||||
|
||||
try {
|
||||
if (! @is_file($input)) {
|
||||
$this->fail();
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
$this->fail();
|
||||
}
|
||||
|
||||
return parent::decode(file_get_contents($input));
|
||||
}
|
||||
}
|
29
src/Drivers/Imagick/Encoders/GifEncoder.php
Normal file
29
src/Drivers/Imagick/Encoders/GifEncoder.php
Normal file
@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
namespace Intervention\Image\Drivers\Imagick\Encoders;
|
||||
|
||||
use Imagick;
|
||||
use Intervention\Image\Drivers\Abstract\Encoders\AbstractEncoder;
|
||||
use Intervention\Image\Interfaces\EncoderInterface;
|
||||
use Intervention\Image\Interfaces\ImageInterface;
|
||||
|
||||
class GifEncoder extends AbstractEncoder implements EncoderInterface
|
||||
{
|
||||
public function encode(ImageInterface $image): string
|
||||
{
|
||||
$format = 'gif';
|
||||
$compression = Imagick::COMPRESSION_LZW;
|
||||
|
||||
$gif = new Imagick() ;
|
||||
foreach ($image->getFrames() as $frame) {
|
||||
$gif->addImage($frame->getCore());
|
||||
}
|
||||
|
||||
$gif->setFormat($format);
|
||||
$gif->setImageFormat($format);
|
||||
$gif->setCompression($compression);
|
||||
$gif->setImageCompression($compression);
|
||||
|
||||
return $gif->getImagesBlob();
|
||||
}
|
||||
}
|
29
src/Drivers/Imagick/Encoders/JpegEncoder.php
Normal file
29
src/Drivers/Imagick/Encoders/JpegEncoder.php
Normal file
@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
namespace Intervention\Image\Drivers\Imagick\Encoders;
|
||||
|
||||
use Imagick;
|
||||
use Intervention\Image\Drivers\Abstract\Encoders\AbstractEncoder;
|
||||
use Intervention\Image\Interfaces\EncoderInterface;
|
||||
use Intervention\Image\Interfaces\ImageInterface;
|
||||
|
||||
class JpegEncoder extends AbstractEncoder implements EncoderInterface
|
||||
{
|
||||
public function encode(ImageInterface $image): string
|
||||
{
|
||||
$format = 'jpeg';
|
||||
$compression = Imagick::COMPRESSION_JPEG;
|
||||
|
||||
$imagick = $image->getFrames()->first()->getCore();
|
||||
$imagick->setImageBackgroundColor('white');
|
||||
$imagick->setBackgroundColor('white');
|
||||
$imagick->setFormat($format);
|
||||
$imagick->setImageFormat($format);
|
||||
$imagick->setCompression($compression);
|
||||
$imagick->setImageCompression($compression);
|
||||
$imagick->setCompressionQuality($this->quality);
|
||||
$imagick->setImageCompressionQuality($this->quality);
|
||||
|
||||
return $imagick->getImagesBlob();
|
||||
}
|
||||
}
|
83
src/Drivers/Imagick/Frame.php
Normal file
83
src/Drivers/Imagick/Frame.php
Normal file
@ -0,0 +1,83 @@
|
||||
<?php
|
||||
|
||||
namespace Intervention\Image\Drivers\Imagick;
|
||||
|
||||
use Imagick;
|
||||
use Intervention\Image\Collection;
|
||||
use Intervention\Image\Drivers\Abstract\AbstractFrame;
|
||||
use Intervention\Image\Interfaces\FrameInterface;
|
||||
use Intervention\Image\Interfaces\ImageInterface;
|
||||
|
||||
class Frame extends AbstractFrame implements FrameInterface
|
||||
{
|
||||
public function __construct(protected Imagick $core)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
public function getCore(): Imagick
|
||||
{
|
||||
return $this->core;
|
||||
}
|
||||
|
||||
public function getDelay(): int
|
||||
{
|
||||
return $this->core->getImageDelay();
|
||||
}
|
||||
|
||||
public function setDelay(int $delay): FrameInterface
|
||||
{
|
||||
$this->core->setImageDelay($delay);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getDispose(): int
|
||||
{
|
||||
return $this->core->getImageDispose();
|
||||
}
|
||||
|
||||
public function setDispose(int $dispose): FrameInterface
|
||||
{
|
||||
$this->core->setImageDispose($dispose);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setOffset(int $left, int $top): FrameInterface
|
||||
{
|
||||
$this->core->setImagePage(
|
||||
$this->core->getImageWidth(),
|
||||
$this->core->getImageHeight(),
|
||||
$left,
|
||||
$top
|
||||
);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getOffsetLeft(): int
|
||||
{
|
||||
return $this->core->getImagePage()['x'];
|
||||
}
|
||||
|
||||
public function setOffsetLeft(int $offset): FrameInterface
|
||||
{
|
||||
return $this->setOffset($offset, $this->getOffsetTop());
|
||||
}
|
||||
|
||||
public function getOffsetTop(): int
|
||||
{
|
||||
return $this->core->getImagePage()['y'];
|
||||
}
|
||||
|
||||
public function setOffsetTop(int $offset): FrameInterface
|
||||
{
|
||||
return $this->setOffset($this->getOffsetLeft(), $offset);
|
||||
}
|
||||
|
||||
public function toImage(): ImageInterface
|
||||
{
|
||||
return new Image(new Collection([$this]));
|
||||
}
|
||||
}
|
35
src/Drivers/Imagick/Image.php
Normal file
35
src/Drivers/Imagick/Image.php
Normal file
@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
namespace Intervention\Image\Drivers\Imagick;
|
||||
|
||||
use Imagick;
|
||||
use Intervention\Image\Collection;
|
||||
use Intervention\Image\Drivers\Abstract\AbstractImage;
|
||||
use Intervention\Image\Drivers\Imagick\Frame;
|
||||
use Intervention\Image\Geometry\Size;
|
||||
use Intervention\Image\Interfaces\ImageInterface;
|
||||
use Intervention\Image\Interfaces\SizeInterface;
|
||||
use IteratorAggregate;
|
||||
|
||||
class Image extends AbstractImage implements ImageInterface, IteratorAggregate
|
||||
{
|
||||
public function __construct(protected Collection $frames)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
public function width(): int
|
||||
{
|
||||
return $this->frames->first()->getCore()->getImageWidth();
|
||||
}
|
||||
|
||||
public function height(): int
|
||||
{
|
||||
return $this->frames->first()->getCore()->getImageHeight();
|
||||
}
|
||||
|
||||
public function greyscale(): ImageInterface
|
||||
{
|
||||
return $this->modify(new Modifiers\GreyscaleModifier());
|
||||
}
|
||||
}
|
22
src/Drivers/Imagick/InputHandler.php
Normal file
22
src/Drivers/Imagick/InputHandler.php
Normal file
@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
namespace Intervention\Image\Drivers\Imagick;
|
||||
|
||||
use Intervention\Image\Drivers\Abstract\AbstractInputHandler;
|
||||
use Intervention\Image\Drivers\Abstract\Decoders\AbstractDecoder;
|
||||
|
||||
class InputHandler extends AbstractInputHandler
|
||||
{
|
||||
protected function chain(): AbstractDecoder
|
||||
{
|
||||
return new Decoders\ArrayColorDecoder(
|
||||
new Decoders\FilePathImageDecoder(
|
||||
new Decoders\BinaryImageDecoder(
|
||||
new Decoders\DataUriImageDecoder(
|
||||
new Decoders\Base64ImageDecoder()
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
18
src/Drivers/Imagick/Modifiers/GreyscaleModifier.php
Normal file
18
src/Drivers/Imagick/Modifiers/GreyscaleModifier.php
Normal file
@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
namespace Intervention\Image\Drivers\Imagick\Modifiers;
|
||||
|
||||
use Intervention\Image\Interfaces\ImageInterface;
|
||||
use Intervention\Image\Interfaces\ModifierInterface;
|
||||
|
||||
class GreyscaleModifier implements ModifierInterface
|
||||
{
|
||||
public function apply(ImageInterface $image): ImageInterface
|
||||
{
|
||||
foreach ($this->image as $frame) {
|
||||
$frame->getCore()->modulateImage(100, 0, 100);
|
||||
}
|
||||
|
||||
return $this->image;
|
||||
}
|
||||
}
|
8
src/Exceptions/DecoderException.php
Normal file
8
src/Exceptions/DecoderException.php
Normal file
@ -0,0 +1,8 @@
|
||||
<?php
|
||||
|
||||
namespace Intervention\Image\Exceptions;
|
||||
|
||||
class DecoderException extends \RuntimeException
|
||||
{
|
||||
//
|
||||
}
|
8
src/Exceptions/NotWritableException.php
Normal file
8
src/Exceptions/NotWritableException.php
Normal file
@ -0,0 +1,8 @@
|
||||
<?php
|
||||
|
||||
namespace Intervention\Image\Exceptions;
|
||||
|
||||
class NotWritableException extends \RuntimeException
|
||||
{
|
||||
# nothing to override
|
||||
}
|
8
src/Exceptions/RuntimeException.php
Normal file
8
src/Exceptions/RuntimeException.php
Normal file
@ -0,0 +1,8 @@
|
||||
<?php
|
||||
|
||||
namespace Intervention\Image\Exceptions;
|
||||
|
||||
class RuntimeException extends \RuntimeException
|
||||
{
|
||||
//
|
||||
}
|
135
src/Geometry/Point.php
Normal file
135
src/Geometry/Point.php
Normal file
@ -0,0 +1,135 @@
|
||||
<?php
|
||||
|
||||
namespace Intervention\Image\Geometry;
|
||||
|
||||
use Intervention\Image\Interfaces\PointInterface;
|
||||
|
||||
class Point implements PointInterface
|
||||
{
|
||||
/**
|
||||
* X coordinate
|
||||
*
|
||||
* @var integer
|
||||
*/
|
||||
protected $x;
|
||||
|
||||
/**
|
||||
* Y coordinate
|
||||
*
|
||||
* @var integer
|
||||
*/
|
||||
protected $y;
|
||||
|
||||
/**
|
||||
* Creates a new instance
|
||||
*
|
||||
* @param integer $x
|
||||
* @param integer $y
|
||||
*/
|
||||
public function __construct(int $x = 0, int $y = 0)
|
||||
{
|
||||
$this->x = $x;
|
||||
$this->y = $y;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets X coordinate
|
||||
*
|
||||
* @param integer $x
|
||||
*/
|
||||
public function setX(int $x): self
|
||||
{
|
||||
$this->x = $x;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get X coordinate
|
||||
*
|
||||
* @return integer
|
||||
*/
|
||||
public function getX(): int
|
||||
{
|
||||
return $this->x;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets Y coordinate
|
||||
*
|
||||
* @param integer $y
|
||||
*/
|
||||
public function setY(int $y): self
|
||||
{
|
||||
$this->y = $y;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Y coordinate
|
||||
*
|
||||
* @return integer
|
||||
*/
|
||||
public function getY(): int
|
||||
{
|
||||
return $this->y;
|
||||
}
|
||||
|
||||
/**
|
||||
* Move X coordinate
|
||||
*
|
||||
* @param integer $x
|
||||
*/
|
||||
public function moveX(int $value): self
|
||||
{
|
||||
$this->x += $value;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Move Y coordinate
|
||||
*
|
||||
* @param integer $y
|
||||
*/
|
||||
public function moveY(int $value): self
|
||||
{
|
||||
$this->y += $value;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets both X and Y coordinate
|
||||
*
|
||||
* @param integer $x
|
||||
* @param integer $y
|
||||
* @return Point
|
||||
*/
|
||||
public function setPosition(int $x, int $y): self
|
||||
{
|
||||
$this->setX($x);
|
||||
$this->setY($y);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Rotate point ccw around pivot
|
||||
*
|
||||
* @param float $angle
|
||||
* @param Point $pivot
|
||||
* @return Point
|
||||
*/
|
||||
public function rotate(float $angle, Point $pivot): self
|
||||
{
|
||||
$sin = round(sin(deg2rad($angle)), 6);
|
||||
$cos = round(cos(deg2rad($angle)), 6);
|
||||
|
||||
return $this->setPosition(
|
||||
$cos * ($this->x - $pivot->x) - $sin * ($this->y - $pivot->y) + $pivot->x,
|
||||
$sin * ($this->x - $pivot->x) + $cos * ($this->y - $pivot->y) + $pivot->y
|
||||
);
|
||||
}
|
||||
}
|
92
src/Geometry/Size.php
Normal file
92
src/Geometry/Size.php
Normal file
@ -0,0 +1,92 @@
|
||||
<?php
|
||||
|
||||
namespace Intervention\Image\Geometry;
|
||||
|
||||
use Intervention\Image\Interfaces\PointInterface;
|
||||
use Intervention\Image\Interfaces\SizeInterface;
|
||||
|
||||
class Size implements SizeInterface
|
||||
{
|
||||
protected $width;
|
||||
protected $height;
|
||||
protected $pivot;
|
||||
|
||||
public function __construct(int $width, int $height, Point $pivot = null)
|
||||
{
|
||||
$this->width = $width;
|
||||
$this->height = $height;
|
||||
$this->pivot = $pivot ? $pivot : new Point();
|
||||
}
|
||||
|
||||
public function getWidth(): int
|
||||
{
|
||||
return $this->width;
|
||||
}
|
||||
|
||||
public function getHeight(): int
|
||||
{
|
||||
return $this->height;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get current pivot point
|
||||
*
|
||||
* @return Point
|
||||
*/
|
||||
public function getPivot(): PointInterface
|
||||
{
|
||||
return $this->pivot;
|
||||
}
|
||||
|
||||
public function setWidth(int $width): SizeInterface
|
||||
{
|
||||
$this->width = $width;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setHeight(int $height): SizeInterface
|
||||
{
|
||||
$this->height = $height;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getAspectRatio(): float
|
||||
{
|
||||
return $this->width / $this->height;
|
||||
}
|
||||
|
||||
public function fitsInto(SizeInterface $size): bool
|
||||
{
|
||||
if ($this->getWidth() > $size->getWidth()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($this->getHeight() > $size->getHeight()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if size is landscape format
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function isLandscape(): bool
|
||||
{
|
||||
return $this->getWidth() > $this->getHeight();
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if size is portrait format
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function isPortrait(): bool
|
||||
{
|
||||
return $this->getWidth() < $this->getHeight();
|
||||
}
|
||||
}
|
96
src/ImageManager.php
Normal file
96
src/ImageManager.php
Normal file
@ -0,0 +1,96 @@
|
||||
<?php
|
||||
|
||||
namespace Intervention\Image;
|
||||
|
||||
use Exception;
|
||||
use ReflectionClass;
|
||||
use Intervention\Image\Interfaces\ImageInterface;
|
||||
|
||||
class ImageManager
|
||||
{
|
||||
/**
|
||||
* Configuration data
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $config = [
|
||||
'driver' => 'gd',
|
||||
];
|
||||
|
||||
/**
|
||||
* Create new instance
|
||||
*
|
||||
* @param array $config
|
||||
*/
|
||||
public function __construct(array $config = [])
|
||||
{
|
||||
$this->configure($config);
|
||||
}
|
||||
|
||||
/**
|
||||
* Override configuration settings
|
||||
*
|
||||
* @param array $config
|
||||
*/
|
||||
public function configure(array $config = []): self
|
||||
{
|
||||
$this->config = array_replace($this->config, $config);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return given value of configuration
|
||||
*
|
||||
* @param string $key
|
||||
* @param mixed $default
|
||||
* @return mixed
|
||||
*/
|
||||
public function getConfig($key, $default = null)
|
||||
{
|
||||
return array_key_exists($key, $this->config) ? $this->config[$key] : $default;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create new image instance from scratch
|
||||
*
|
||||
* @param int $width
|
||||
* @param int $height
|
||||
* @return ImageInterface
|
||||
*/
|
||||
public function create(int $width, int $height): ImageInterface
|
||||
{
|
||||
return $this->resolve('ImageFactory')->newImage($width, $height);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create new image instance from input
|
||||
*
|
||||
* @param mixed $input
|
||||
* @return ImageInterface
|
||||
*/
|
||||
public function make($input): ImageInterface
|
||||
{
|
||||
return $this->resolve('InputHandler')->handle($input);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve given classname according to current configuration
|
||||
*
|
||||
* @param string $classname
|
||||
* @param array $arguments
|
||||
* @return mixed
|
||||
*/
|
||||
private function resolve(string $classname, ...$arguments)
|
||||
{
|
||||
$classname = sprintf(
|
||||
"Intervention\\Image\\Drivers\\%s\\%s",
|
||||
ucfirst($this->config['driver']),
|
||||
$classname
|
||||
);
|
||||
|
||||
$reflection = new ReflectionClass($classname);
|
||||
|
||||
return $reflection->newInstanceArgs($arguments);
|
||||
}
|
||||
}
|
12
src/Interfaces/CollectionInterface.php
Normal file
12
src/Interfaces/CollectionInterface.php
Normal file
@ -0,0 +1,12 @@
|
||||
<?php
|
||||
|
||||
namespace Intervention\Image\Interfaces;
|
||||
|
||||
interface CollectionInterface
|
||||
{
|
||||
public function push($item): CollectionInterface;
|
||||
public function get(int $key);
|
||||
public function first();
|
||||
public function last();
|
||||
public function count(): int;
|
||||
}
|
13
src/Interfaces/ColorInterface.php
Normal file
13
src/Interfaces/ColorInterface.php
Normal file
@ -0,0 +1,13 @@
|
||||
<?php
|
||||
|
||||
namespace Intervention\Image\Interfaces;
|
||||
|
||||
interface ColorInterface
|
||||
{
|
||||
public function red(): int;
|
||||
public function green(): int;
|
||||
public function blue(): int;
|
||||
public function alpha(): float;
|
||||
public function toArray(): array;
|
||||
public function toHex(): string;
|
||||
}
|
8
src/Interfaces/DecoderInterface.php
Normal file
8
src/Interfaces/DecoderInterface.php
Normal file
@ -0,0 +1,8 @@
|
||||
<?php
|
||||
|
||||
namespace Intervention\Image\Interfaces;
|
||||
|
||||
interface DecoderInterface
|
||||
{
|
||||
public function decode($input): ImageInterface|ColorInterface;
|
||||
}
|
8
src/Interfaces/EncoderInterface.php
Normal file
8
src/Interfaces/EncoderInterface.php
Normal file
@ -0,0 +1,8 @@
|
||||
<?php
|
||||
|
||||
namespace Intervention\Image\Interfaces;
|
||||
|
||||
interface EncoderInterface
|
||||
{
|
||||
public function encode(ImageInterface $image): string;
|
||||
}
|
8
src/Interfaces/FactoryInterface.php
Normal file
8
src/Interfaces/FactoryInterface.php
Normal file
@ -0,0 +1,8 @@
|
||||
<?php
|
||||
|
||||
namespace Intervention\Image\Interfaces;
|
||||
|
||||
interface FactoryInterface
|
||||
{
|
||||
public function newImage(int $width, int $height): ImageInterface;
|
||||
}
|
18
src/Interfaces/FrameInterface.php
Normal file
18
src/Interfaces/FrameInterface.php
Normal file
@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
namespace Intervention\Image\Interfaces;
|
||||
|
||||
interface FrameInterface
|
||||
{
|
||||
public function toImage(): ImageInterface;
|
||||
public function getCore();
|
||||
public function getDelay(): int;
|
||||
public function setDelay(int $delay): FrameInterface;
|
||||
public function getDispose(): int;
|
||||
public function setDispose(int $dispose): FrameInterface;
|
||||
public function setOffset(int $left, int $top): FrameInterface;
|
||||
public function getOffsetLeft(): int;
|
||||
public function setOffsetLeft(int $offset): FrameInterface;
|
||||
public function getOffsetTop(): int;
|
||||
public function setOffsetTop(int $offset): FrameInterface;
|
||||
}
|
12
src/Interfaces/ImageInterface.php
Normal file
12
src/Interfaces/ImageInterface.php
Normal file
@ -0,0 +1,12 @@
|
||||
<?php
|
||||
|
||||
namespace Intervention\Image\Interfaces;
|
||||
|
||||
interface ImageInterface
|
||||
{
|
||||
public function size(): SizeInterface;
|
||||
public function width(): int;
|
||||
public function height(): int;
|
||||
public function isAnimated(): bool;
|
||||
public function greyscale(): ImageInterface;
|
||||
}
|
8
src/Interfaces/ModifierInterface.php
Normal file
8
src/Interfaces/ModifierInterface.php
Normal file
@ -0,0 +1,8 @@
|
||||
<?php
|
||||
|
||||
namespace Intervention\Image\Interfaces;
|
||||
|
||||
interface ModifierInterface
|
||||
{
|
||||
public function apply(ImageInterface $image): ImageInterface;
|
||||
}
|
9
src/Interfaces/PointInterface.php
Normal file
9
src/Interfaces/PointInterface.php
Normal file
@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
namespace Intervention\Image\Interfaces;
|
||||
|
||||
interface PointInterface
|
||||
{
|
||||
public function getX(): int;
|
||||
public function getY(): int;
|
||||
}
|
16
src/Interfaces/SizeInterface.php
Normal file
16
src/Interfaces/SizeInterface.php
Normal file
@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
namespace Intervention\Image\Interfaces;
|
||||
|
||||
interface SizeInterface
|
||||
{
|
||||
public function getWidth(): int;
|
||||
public function getHeight(): int;
|
||||
public function getPivot(): PointInterface;
|
||||
public function setWidth(int $width): SizeInterface;
|
||||
public function setHeight(int $height): SizeInterface;
|
||||
public function getAspectRatio(): float;
|
||||
public function fitsInto(SizeInterface $size): bool;
|
||||
public function isLandscape(): bool;
|
||||
public function isPortrait(): bool;
|
||||
}
|
@ -1,229 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Intervention\Image;
|
||||
|
||||
use Intervention\Image\Exception\NotReadableException;
|
||||
use Intervention\Image\Exception\NotSupportedException;
|
||||
|
||||
abstract class AbstractColor
|
||||
{
|
||||
/**
|
||||
* Initiates color object from integer
|
||||
*
|
||||
* @param int $value
|
||||
* @return \Intervention\Image\AbstractColor
|
||||
*/
|
||||
abstract public function initFromInteger($value);
|
||||
|
||||
/**
|
||||
* Initiates color object from given array
|
||||
*
|
||||
* @param array $value
|
||||
* @return \Intervention\Image\AbstractColor
|
||||
*/
|
||||
abstract public function initFromArray($value);
|
||||
|
||||
/**
|
||||
* Initiates color object from given string
|
||||
*
|
||||
* @param string $value
|
||||
* @return \Intervention\Image\AbstractColor
|
||||
*/
|
||||
abstract public function initFromString($value);
|
||||
|
||||
/**
|
||||
* Initiates color object from given ImagickPixel object
|
||||
*
|
||||
* @param ImagickPixel $value
|
||||
* @return \Intervention\Image\AbstractColor
|
||||
*/
|
||||
abstract public function initFromObject($value);
|
||||
|
||||
/**
|
||||
* Initiates color object from given R, G and B values
|
||||
*
|
||||
* @param int $r
|
||||
* @param int $g
|
||||
* @param int $b
|
||||
* @return \Intervention\Image\AbstractColor
|
||||
*/
|
||||
abstract public function initFromRgb($r, $g, $b);
|
||||
|
||||
/**
|
||||
* Initiates color object from given R, G, B and A values
|
||||
*
|
||||
* @param int $r
|
||||
* @param int $g
|
||||
* @param int $b
|
||||
* @param float $a
|
||||
* @return \Intervention\Image\AbstractColor
|
||||
*/
|
||||
abstract public function initFromRgba($r, $g, $b, $a);
|
||||
|
||||
/**
|
||||
* Calculates integer value of current color instance
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
abstract public function getInt();
|
||||
|
||||
/**
|
||||
* Calculates hexadecimal value of current color instance
|
||||
*
|
||||
* @param string $prefix
|
||||
* @return string
|
||||
*/
|
||||
abstract public function getHex($prefix);
|
||||
|
||||
/**
|
||||
* Calculates RGB(A) in array format of current color instance
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
abstract public function getArray();
|
||||
|
||||
/**
|
||||
* Calculates RGBA in string format of current color instance
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
abstract public function getRgba();
|
||||
|
||||
/**
|
||||
* Determines if current color is different from given color
|
||||
*
|
||||
* @param AbstractColor $color
|
||||
* @param int $tolerance
|
||||
* @return boolean
|
||||
*/
|
||||
abstract public function differs(AbstractColor $color, $tolerance = 0);
|
||||
|
||||
/**
|
||||
* Creates new instance
|
||||
*
|
||||
* @param mixed $value
|
||||
*/
|
||||
public function __construct($value = null)
|
||||
{
|
||||
$this->parse($value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses given value as color
|
||||
*
|
||||
* @param mixed $value
|
||||
* @return \Intervention\Image\AbstractColor
|
||||
*/
|
||||
public function parse($value)
|
||||
{
|
||||
switch (true) {
|
||||
|
||||
case is_string($value):
|
||||
$this->initFromString($value);
|
||||
break;
|
||||
|
||||
case is_int($value):
|
||||
$this->initFromInteger($value);
|
||||
break;
|
||||
|
||||
case is_array($value):
|
||||
$this->initFromArray($value);
|
||||
break;
|
||||
|
||||
case is_object($value):
|
||||
$this->initFromObject($value);
|
||||
break;
|
||||
|
||||
case is_null($value):
|
||||
$this->initFromArray([255, 255, 255, 0]);
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new NotReadableException(
|
||||
"Color format ({$value}) cannot be read."
|
||||
);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats current color instance into given format
|
||||
*
|
||||
* @param string $type
|
||||
* @return mixed
|
||||
*/
|
||||
public function format($type)
|
||||
{
|
||||
switch (strtolower($type)) {
|
||||
|
||||
case 'rgba':
|
||||
return $this->getRgba();
|
||||
|
||||
case 'hex':
|
||||
return $this->getHex('#');
|
||||
|
||||
case 'int':
|
||||
case 'integer':
|
||||
return $this->getInt();
|
||||
|
||||
case 'array':
|
||||
return $this->getArray();
|
||||
|
||||
case 'obj':
|
||||
case 'object':
|
||||
return $this;
|
||||
|
||||
default:
|
||||
throw new NotSupportedException(
|
||||
"Color format ({$type}) is not supported."
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads RGBA values from string into array
|
||||
*
|
||||
* @param string $value
|
||||
* @return array
|
||||
*/
|
||||
protected function rgbaFromString($value)
|
||||
{
|
||||
$result = false;
|
||||
|
||||
// parse color string in hexidecimal format like #cccccc or cccccc or ccc
|
||||
$hexPattern = '/^#?([a-f0-9]{1,2})([a-f0-9]{1,2})([a-f0-9]{1,2})$/i';
|
||||
|
||||
// parse color string in format rgb(140, 140, 140)
|
||||
$rgbPattern = '/^rgb ?\(([0-9]{1,3}), ?([0-9]{1,3}), ?([0-9]{1,3})\)$/i';
|
||||
|
||||
// parse color string in format rgba(255, 0, 0, 0.5)
|
||||
$rgbaPattern = '/^rgba ?\(([0-9]{1,3}), ?([0-9]{1,3}), ?([0-9]{1,3}), ?([0-9.]{1,4})\)$/i';
|
||||
|
||||
if (preg_match($hexPattern, $value, $matches)) {
|
||||
$result = [];
|
||||
$result[0] = strlen($matches[1]) == '1' ? hexdec($matches[1].$matches[1]) : hexdec($matches[1]);
|
||||
$result[1] = strlen($matches[2]) == '1' ? hexdec($matches[2].$matches[2]) : hexdec($matches[2]);
|
||||
$result[2] = strlen($matches[3]) == '1' ? hexdec($matches[3].$matches[3]) : hexdec($matches[3]);
|
||||
$result[3] = 1;
|
||||
} elseif (preg_match($rgbPattern, $value, $matches)) {
|
||||
$result = [];
|
||||
$result[0] = ($matches[1] >= 0 && $matches[1] <= 255) ? intval($matches[1]) : 0;
|
||||
$result[1] = ($matches[2] >= 0 && $matches[2] <= 255) ? intval($matches[2]) : 0;
|
||||
$result[2] = ($matches[3] >= 0 && $matches[3] <= 255) ? intval($matches[3]) : 0;
|
||||
$result[3] = 1;
|
||||
} elseif (preg_match($rgbaPattern, $value, $matches)) {
|
||||
$result = [];
|
||||
$result[0] = ($matches[1] >= 0 && $matches[1] <= 255) ? intval($matches[1]) : 0;
|
||||
$result[1] = ($matches[2] >= 0 && $matches[2] <= 255) ? intval($matches[2]) : 0;
|
||||
$result[2] = ($matches[3] >= 0 && $matches[3] <= 255) ? intval($matches[3]) : 0;
|
||||
$result[3] = ($matches[4] >= 0 && $matches[4] <= 1) ? $matches[4] : 0;
|
||||
} else {
|
||||
throw new NotReadableException(
|
||||
"Unable to read color ({$value})."
|
||||
);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
@ -1,364 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Intervention\Image;
|
||||
|
||||
use GuzzleHttp\Psr7\Stream;
|
||||
use Intervention\Image\Exception\NotReadableException;
|
||||
use Psr\Http\Message\StreamInterface;
|
||||
|
||||
abstract class AbstractDecoder
|
||||
{
|
||||
/**
|
||||
* Initiates new image from path in filesystem
|
||||
*
|
||||
* @param string $path
|
||||
* @return \Intervention\Image\Image
|
||||
*/
|
||||
abstract public function initFromPath($path);
|
||||
|
||||
/**
|
||||
* Initiates new image from binary data
|
||||
*
|
||||
* @param string $data
|
||||
* @return \Intervention\Image\Image
|
||||
*/
|
||||
abstract public function initFromBinary($data);
|
||||
|
||||
/**
|
||||
* Initiates new image from GD resource
|
||||
*
|
||||
* @param Resource $resource
|
||||
* @return \Intervention\Image\Image
|
||||
*/
|
||||
abstract public function initFromGdResource($resource);
|
||||
|
||||
/**
|
||||
* Initiates new image from Imagick object
|
||||
*
|
||||
* @param \Imagick $object
|
||||
* @return \Intervention\Image\Image
|
||||
*/
|
||||
abstract public function initFromImagick(\Imagick $object);
|
||||
|
||||
/**
|
||||
* Buffer of input data
|
||||
*
|
||||
* @var mixed
|
||||
*/
|
||||
private $data;
|
||||
|
||||
/**
|
||||
* Creates new Decoder with data
|
||||
*
|
||||
* @param mixed $data
|
||||
*/
|
||||
public function __construct($data = null)
|
||||
{
|
||||
$this->data = $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Init from given URL
|
||||
*
|
||||
* @param string $url
|
||||
* @return \Intervention\Image\Image
|
||||
*/
|
||||
public function initFromUrl($url)
|
||||
{
|
||||
|
||||
$options = [
|
||||
'http' => [
|
||||
'method'=>"GET",
|
||||
'protocol_version'=>1.1, // force use HTTP 1.1 for service mesh environment with envoy
|
||||
'header'=>"Accept-language: en\r\n".
|
||||
"User-Agent: Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.2 (KHTML, like Gecko) Chrome/22.0.1216.0 Safari/537.2\r\n"
|
||||
]
|
||||
];
|
||||
|
||||
$context = stream_context_create($options);
|
||||
|
||||
|
||||
if ($data = @file_get_contents($url, false, $context)) {
|
||||
return $this->initFromBinary($data);
|
||||
}
|
||||
|
||||
throw new NotReadableException(
|
||||
"Unable to init from given url (".$url.")."
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Init from given stream
|
||||
*
|
||||
* @param StreamInterface|resource $stream
|
||||
* @return \Intervention\Image\Image
|
||||
*/
|
||||
public function initFromStream($stream)
|
||||
{
|
||||
if (!$stream instanceof StreamInterface) {
|
||||
$stream = new Stream($stream);
|
||||
}
|
||||
|
||||
try {
|
||||
$offset = $stream->tell();
|
||||
} catch (\RuntimeException $e) {
|
||||
$offset = 0;
|
||||
}
|
||||
|
||||
$shouldAndCanSeek = $offset !== 0 && $stream->isSeekable();
|
||||
|
||||
if ($shouldAndCanSeek) {
|
||||
$stream->rewind();
|
||||
}
|
||||
|
||||
try {
|
||||
$data = $stream->getContents();
|
||||
} catch (\RuntimeException $e) {
|
||||
$data = null;
|
||||
}
|
||||
|
||||
if ($shouldAndCanSeek) {
|
||||
$stream->seek($offset);
|
||||
}
|
||||
|
||||
if ($data) {
|
||||
return $this->initFromBinary($data);
|
||||
}
|
||||
|
||||
throw new NotReadableException(
|
||||
"Unable to init from given stream"
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if current source data is GD resource
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function isGdResource()
|
||||
{
|
||||
if (is_resource($this->data)) {
|
||||
return (get_resource_type($this->data) == 'gd');
|
||||
}
|
||||
|
||||
if ($this->data instanceof \GdImage) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if current source data is Imagick object
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function isImagick()
|
||||
{
|
||||
return is_a($this->data, 'Imagick');
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if current source data is Intervention\Image\Image object
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function isInterventionImage()
|
||||
{
|
||||
return is_a($this->data, '\Intervention\Image\Image');
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if current data is SplFileInfo object
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function isSplFileInfo()
|
||||
{
|
||||
return is_a($this->data, 'SplFileInfo');
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if current data is Symfony UploadedFile component
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function isSymfonyUpload()
|
||||
{
|
||||
return is_a($this->data, 'Symfony\Component\HttpFoundation\File\UploadedFile');
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if current source data is file path
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function isFilePath()
|
||||
{
|
||||
if (is_string($this->data)) {
|
||||
try {
|
||||
return is_file($this->data);
|
||||
} catch (\Exception $e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if current source data is url
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function isUrl()
|
||||
{
|
||||
return (bool) filter_var($this->data, FILTER_VALIDATE_URL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if current source data is a stream resource
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function isStream()
|
||||
{
|
||||
if ($this->data instanceof StreamInterface) return true;
|
||||
if (!is_resource($this->data)) return false;
|
||||
if (get_resource_type($this->data) !== 'stream') return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if current source data is binary data
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function isBinary()
|
||||
{
|
||||
if (is_string($this->data)) {
|
||||
$mime = finfo_buffer(finfo_open(FILEINFO_MIME_TYPE), $this->data);
|
||||
return (substr($mime, 0, 4) != 'text' && $mime != 'application/x-empty');
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if current source data is data-url
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function isDataUrl()
|
||||
{
|
||||
$data = $this->decodeDataUrl($this->data);
|
||||
|
||||
return is_null($data) ? false : true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if current source data is base64 encoded
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function isBase64()
|
||||
{
|
||||
if (!is_string($this->data)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return base64_encode(base64_decode($this->data)) === str_replace(["\n", "\r"], '', $this->data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initiates new Image from Intervention\Image\Image
|
||||
*
|
||||
* @param Image $object
|
||||
* @return \Intervention\Image\Image
|
||||
*/
|
||||
public function initFromInterventionImage($object)
|
||||
{
|
||||
return $object;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses and decodes binary image data from data-url
|
||||
*
|
||||
* @param string $data_url
|
||||
* @return string
|
||||
*/
|
||||
private function decodeDataUrl($data_url)
|
||||
{
|
||||
if (!is_string($data_url)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$pattern = "/^data:(?:image\/[a-zA-Z\-\.]+)(?:charset=\".+\")?;base64,(?P<data>.+)$/";
|
||||
preg_match($pattern, str_replace(["\n", "\r"], '', $data_url), $matches);
|
||||
|
||||
if (is_array($matches) && array_key_exists('data', $matches)) {
|
||||
return base64_decode($matches['data']);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initiates new image from mixed data
|
||||
*
|
||||
* @param mixed $data
|
||||
* @return \Intervention\Image\Image
|
||||
*/
|
||||
public function init($data)
|
||||
{
|
||||
$this->data = $data;
|
||||
|
||||
switch (true) {
|
||||
|
||||
case $this->isGdResource():
|
||||
return $this->initFromGdResource($this->data);
|
||||
|
||||
case $this->isImagick():
|
||||
return $this->initFromImagick($this->data);
|
||||
|
||||
case $this->isInterventionImage():
|
||||
return $this->initFromInterventionImage($this->data);
|
||||
|
||||
case $this->isSplFileInfo():
|
||||
return $this->initFromPath($this->data->getRealPath());
|
||||
|
||||
case $this->isBinary():
|
||||
return $this->initFromBinary($this->data);
|
||||
|
||||
case $this->isUrl():
|
||||
return $this->initFromUrl($this->data);
|
||||
|
||||
case $this->isStream():
|
||||
return $this->initFromStream($this->data);
|
||||
|
||||
case $this->isDataUrl():
|
||||
return $this->initFromBinary($this->decodeDataUrl($this->data));
|
||||
|
||||
case $this->isFilePath():
|
||||
return $this->initFromPath($this->data);
|
||||
|
||||
// isBase64 has to be after isFilePath to prevent false positives
|
||||
case $this->isBase64():
|
||||
return $this->initFromBinary(base64_decode($this->data));
|
||||
|
||||
default:
|
||||
throw new NotReadableException("Image source not readable");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Decoder object transforms to string source data
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
return (string) $this->data;
|
||||
}
|
||||
}
|
@ -1,140 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Intervention\Image;
|
||||
|
||||
use Intervention\Image\Exception\NotSupportedException;
|
||||
|
||||
abstract class AbstractDriver
|
||||
{
|
||||
/**
|
||||
* Decoder instance to init images from
|
||||
*
|
||||
* @var \Intervention\Image\AbstractDecoder
|
||||
*/
|
||||
public $decoder;
|
||||
|
||||
/**
|
||||
* Image encoder instance
|
||||
*
|
||||
* @var \Intervention\Image\AbstractEncoder
|
||||
*/
|
||||
public $encoder;
|
||||
|
||||
/**
|
||||
* Creates new image instance
|
||||
*
|
||||
* @param int $width
|
||||
* @param int $height
|
||||
* @param string $background
|
||||
* @return \Intervention\Image\Image
|
||||
*/
|
||||
abstract public function newImage($width, $height, $background);
|
||||
|
||||
/**
|
||||
* Reads given string into color object
|
||||
*
|
||||
* @param string $value
|
||||
* @return AbstractColor
|
||||
*/
|
||||
abstract public function parseColor($value);
|
||||
|
||||
/**
|
||||
* Checks if core module installation is available
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
abstract protected function coreAvailable();
|
||||
|
||||
/**
|
||||
* Returns clone of given core
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function cloneCore($core)
|
||||
{
|
||||
return clone $core;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initiates new image from given input
|
||||
*
|
||||
* @param mixed $data
|
||||
* @return \Intervention\Image\Image
|
||||
*/
|
||||
public function init($data)
|
||||
{
|
||||
return $this->decoder->init($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes given image
|
||||
*
|
||||
* @param Image $image
|
||||
* @param string $format
|
||||
* @param int $quality
|
||||
* @return \Intervention\Image\Image
|
||||
*/
|
||||
public function encode($image, $format, $quality)
|
||||
{
|
||||
return $this->encoder->process($image, $format, $quality);
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes named command on given image
|
||||
*
|
||||
* @param Image $image
|
||||
* @param string $name
|
||||
* @param array $arguments
|
||||
* @return \Intervention\Image\Commands\AbstractCommand
|
||||
*/
|
||||
public function executeCommand($image, $name, $arguments)
|
||||
{
|
||||
$commandName = $this->getCommandClassName($name);
|
||||
$command = new $commandName($arguments);
|
||||
$command->execute($image);
|
||||
|
||||
return $command;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns classname of given command name
|
||||
*
|
||||
* @param string $name
|
||||
* @return string
|
||||
*/
|
||||
private function getCommandClassName($name)
|
||||
{
|
||||
if (extension_loaded('mbstring')) {
|
||||
$name = mb_strtoupper(mb_substr($name, 0, 1)) . mb_substr($name, 1);
|
||||
} else {
|
||||
$name = strtoupper(substr($name, 0, 1)) . substr($name, 1);
|
||||
}
|
||||
|
||||
$drivername = $this->getDriverName();
|
||||
$classnameLocal = sprintf('\Intervention\Image\%s\Commands\%sCommand', $drivername, ucfirst($name));
|
||||
$classnameGlobal = sprintf('\Intervention\Image\Commands\%sCommand', ucfirst($name));
|
||||
|
||||
if (class_exists($classnameLocal)) {
|
||||
return $classnameLocal;
|
||||
} elseif (class_exists($classnameGlobal)) {
|
||||
return $classnameGlobal;
|
||||
}
|
||||
|
||||
throw new NotSupportedException(
|
||||
"Command ({$name}) is not available for driver ({$drivername})."
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns name of current driver instance
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getDriverName()
|
||||
{
|
||||
$reflect = new \ReflectionClass($this);
|
||||
$namespace = $reflect->getNamespaceName();
|
||||
|
||||
return substr(strrchr($namespace, "\\"), 1);
|
||||
}
|
||||
}
|
@ -1,271 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Intervention\Image;
|
||||
|
||||
use Intervention\Image\Exception\InvalidArgumentException;
|
||||
use Intervention\Image\Exception\NotSupportedException;
|
||||
|
||||
abstract class AbstractEncoder
|
||||
{
|
||||
/**
|
||||
* Buffer of encode result data
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $result;
|
||||
|
||||
/**
|
||||
* Image object to encode
|
||||
*
|
||||
* @var Image
|
||||
*/
|
||||
public $image;
|
||||
|
||||
/**
|
||||
* Output format of encoder instance
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $format;
|
||||
|
||||
/**
|
||||
* Output quality of encoder instance
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $quality;
|
||||
|
||||
/**
|
||||
* Processes and returns encoded image as JPEG string
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
abstract protected function processJpeg();
|
||||
|
||||
/**
|
||||
* Processes and returns encoded image as PNG string
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
abstract protected function processPng();
|
||||
|
||||
/**
|
||||
* Processes and returns encoded image as GIF string
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
abstract protected function processGif();
|
||||
|
||||
/**
|
||||
* Processes and returns encoded image as TIFF string
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
abstract protected function processTiff();
|
||||
|
||||
/**
|
||||
* Processes and returns encoded image as BMP string
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
abstract protected function processBmp();
|
||||
|
||||
/**
|
||||
* Processes and returns encoded image as ICO string
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
abstract protected function processIco();
|
||||
|
||||
/**
|
||||
* Processes and returns image as WebP encoded string
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
abstract protected function processWebp();
|
||||
|
||||
/**
|
||||
* Processes and returns image as Avif encoded string
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
abstract protected function processAvif();
|
||||
|
||||
/**
|
||||
* Processes and returns image as Heic encoded string
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
abstract protected function processHeic();
|
||||
|
||||
/**
|
||||
* Process a given image
|
||||
*
|
||||
* @param Image $image
|
||||
* @param string $format
|
||||
* @param int $quality
|
||||
* @return Image
|
||||
*/
|
||||
public function process(Image $image, $format = null, $quality = null)
|
||||
{
|
||||
$this->setImage($image);
|
||||
$this->setFormat($format);
|
||||
$this->setQuality($quality);
|
||||
|
||||
switch (strtolower($this->format)) {
|
||||
|
||||
case 'data-url':
|
||||
$this->result = $this->processDataUrl();
|
||||
break;
|
||||
|
||||
case 'gif':
|
||||
case 'image/gif':
|
||||
$this->result = $this->processGif();
|
||||
break;
|
||||
|
||||
case 'png':
|
||||
case 'image/png':
|
||||
case 'image/x-png':
|
||||
$this->result = $this->processPng();
|
||||
break;
|
||||
|
||||
case 'jpg':
|
||||
case 'jpeg':
|
||||
case 'jfif':
|
||||
case 'image/jp2':
|
||||
case 'image/jpg':
|
||||
case 'image/jpeg':
|
||||
case 'image/pjpeg':
|
||||
case 'image/jfif':
|
||||
$this->result = $this->processJpeg();
|
||||
break;
|
||||
|
||||
case 'tif':
|
||||
case 'tiff':
|
||||
case 'image/tiff':
|
||||
case 'image/tif':
|
||||
case 'image/x-tif':
|
||||
case 'image/x-tiff':
|
||||
$this->result = $this->processTiff();
|
||||
break;
|
||||
|
||||
case 'bmp':
|
||||
case 'ms-bmp':
|
||||
case 'x-bitmap':
|
||||
case 'x-bmp':
|
||||
case 'x-ms-bmp':
|
||||
case 'x-win-bitmap':
|
||||
case 'x-windows-bmp':
|
||||
case 'x-xbitmap':
|
||||
case 'image/ms-bmp':
|
||||
case 'image/x-bitmap':
|
||||
case 'image/x-bmp':
|
||||
case 'image/x-ms-bmp':
|
||||
case 'image/x-win-bitmap':
|
||||
case 'image/x-windows-bmp':
|
||||
case 'image/x-xbitmap':
|
||||
$this->result = $this->processBmp();
|
||||
break;
|
||||
|
||||
case 'ico':
|
||||
case 'image/x-ico':
|
||||
case 'image/x-icon':
|
||||
case 'image/vnd.microsoft.icon':
|
||||
$this->result = $this->processIco();
|
||||
break;
|
||||
|
||||
case 'psd':
|
||||
case 'image/vnd.adobe.photoshop':
|
||||
$this->result = $this->processPsd();
|
||||
break;
|
||||
|
||||
case 'webp':
|
||||
case 'image/webp':
|
||||
case 'image/x-webp':
|
||||
$this->result = $this->processWebp();
|
||||
break;
|
||||
|
||||
case 'avif':
|
||||
case 'image/avif':
|
||||
$this->result = $this->processAvif();
|
||||
break;
|
||||
|
||||
case 'heic':
|
||||
case 'image/heic':
|
||||
case 'image/heif':
|
||||
$this->result = $this->processHeic();
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new NotSupportedException(
|
||||
"Encoding format ({$this->format}) is not supported."
|
||||
);
|
||||
}
|
||||
|
||||
$this->setImage(null);
|
||||
|
||||
return $image->setEncoded($this->result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes and returns encoded image as data-url string
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function processDataUrl()
|
||||
{
|
||||
$mime = $this->image->mime ? $this->image->mime : 'image/png';
|
||||
|
||||
return sprintf('data:%s;base64,%s',
|
||||
$mime,
|
||||
base64_encode($this->process($this->image, $mime, $this->quality))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets image to process
|
||||
*
|
||||
* @param Image $image
|
||||
*/
|
||||
protected function setImage($image)
|
||||
{
|
||||
$this->image = $image;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines output format
|
||||
*
|
||||
* @param string $format
|
||||
*/
|
||||
protected function setFormat($format = null)
|
||||
{
|
||||
if ($format == '' && $this->image instanceof Image) {
|
||||
$format = $this->image->mime;
|
||||
}
|
||||
|
||||
$this->format = $format ? $format : 'jpg';
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines output quality
|
||||
*
|
||||
* @param int $quality
|
||||
*/
|
||||
protected function setQuality($quality)
|
||||
{
|
||||
$quality = is_null($quality) ? 90 : $quality;
|
||||
$quality = $quality === 0 ? 1 : $quality;
|
||||
|
||||
if ($quality < 0 || $quality > 100) {
|
||||
throw new InvalidArgumentException(
|
||||
'Quality must range from 0 to 100.'
|
||||
);
|
||||
}
|
||||
|
||||
$this->quality = intval($quality);
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
@ -1,295 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Intervention\Image;
|
||||
|
||||
abstract class AbstractFont
|
||||
{
|
||||
/**
|
||||
* Text to be written
|
||||
*
|
||||
* @var String
|
||||
*/
|
||||
public $text;
|
||||
|
||||
/**
|
||||
* Text size in pixels
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $size = 12;
|
||||
|
||||
/**
|
||||
* Color of the text
|
||||
*
|
||||
* @var mixed
|
||||
*/
|
||||
public $color = '000000';
|
||||
|
||||
/**
|
||||
* Rotation angle of the text
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $angle = 0;
|
||||
|
||||
/**
|
||||
* Horizontal alignment of the text
|
||||
*
|
||||
* @var String
|
||||
*/
|
||||
public $align;
|
||||
|
||||
/**
|
||||
* Vertical alignment of the text
|
||||
*
|
||||
* @var String
|
||||
*/
|
||||
public $valign;
|
||||
|
||||
/**
|
||||
* Space between text characters
|
||||
*
|
||||
* @var float
|
||||
*/
|
||||
public $kerning = 0;
|
||||
|
||||
/**
|
||||
* Path to TTF or GD library internal font file of the text
|
||||
*
|
||||
* @var mixed
|
||||
*/
|
||||
public $file;
|
||||
|
||||
/**
|
||||
* Draws font to given image on given position
|
||||
*
|
||||
* @param Image $image
|
||||
* @param int $posx
|
||||
* @param int $posy
|
||||
* @return boolean
|
||||
*/
|
||||
abstract public function applyToImage(Image $image, $posx = 0, $posy = 0);
|
||||
|
||||
/**
|
||||
* Calculates bounding box of current font setting
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
abstract public function getBoxSize();
|
||||
|
||||
/**
|
||||
* Create a new instance of Font
|
||||
*
|
||||
* @param String $text Text to be written
|
||||
*/
|
||||
public function __construct($text = null)
|
||||
{
|
||||
$this->text = $text;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set text to be written
|
||||
*
|
||||
* @param String $text
|
||||
* @return self
|
||||
*/
|
||||
public function text($text)
|
||||
{
|
||||
$this->text = $text;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get text to be written
|
||||
*
|
||||
* @return String
|
||||
*/
|
||||
public function getText()
|
||||
{
|
||||
return $this->text;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set font size in pixels
|
||||
*
|
||||
* @param int $size
|
||||
* @return self
|
||||
*/
|
||||
public function size($size)
|
||||
{
|
||||
$this->size = $size;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get font size in pixels
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getSize()
|
||||
{
|
||||
return $this->size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set color of text to be written
|
||||
*
|
||||
* @param mixed $color
|
||||
* @return self
|
||||
*/
|
||||
public function color($color)
|
||||
{
|
||||
$this->color = $color;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get color of text
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function getColor()
|
||||
{
|
||||
return $this->color;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set rotation angle of text
|
||||
*
|
||||
* @param int $angle
|
||||
* @return self
|
||||
*/
|
||||
public function angle($angle)
|
||||
{
|
||||
$this->angle = $angle;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get rotation angle of text
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getAngle()
|
||||
{
|
||||
return $this->angle;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set horizontal text alignment
|
||||
*
|
||||
* @param string $align
|
||||
* @return self
|
||||
*/
|
||||
public function align($align)
|
||||
{
|
||||
$this->align = $align;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get horizontal text alignment
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getAlign()
|
||||
{
|
||||
return $this->align;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set vertical text alignment
|
||||
*
|
||||
* @param string $valign
|
||||
* @return self
|
||||
*/
|
||||
public function valign($valign)
|
||||
{
|
||||
$this->valign = $valign;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get vertical text alignment
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getValign()
|
||||
{
|
||||
return $this->valign;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set text kerning
|
||||
*
|
||||
* @param string $kerning
|
||||
* @return void
|
||||
*/
|
||||
public function kerning($kerning)
|
||||
{
|
||||
$this->kerning = $kerning;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get kerning
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
public function getKerning()
|
||||
{
|
||||
return $this->kerning;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set path to font file
|
||||
*
|
||||
* @param string $file
|
||||
* @return self
|
||||
*/
|
||||
public function file($file)
|
||||
{
|
||||
$this->file = $file;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get path to font file
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getFile()
|
||||
{
|
||||
return $this->file;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if current font has access to an applicable font file
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
protected function hasApplicableFontFile()
|
||||
{
|
||||
if (is_string($this->file)) {
|
||||
return file_exists($this->file);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Counts lines of text to be written
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function countLines()
|
||||
{
|
||||
return count(explode(PHP_EOL, $this->text));
|
||||
}
|
||||
}
|
@ -1,71 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Intervention\Image;
|
||||
|
||||
abstract class AbstractShape
|
||||
{
|
||||
/**
|
||||
* Background color of shape
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $background;
|
||||
|
||||
/**
|
||||
* Border color of current shape
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $border_color;
|
||||
|
||||
/**
|
||||
* Border width of shape
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $border_width = 0;
|
||||
|
||||
/**
|
||||
* Draws shape to given image on given position
|
||||
*
|
||||
* @param Image $image
|
||||
* @param int $posx
|
||||
* @param int $posy
|
||||
* @return boolean
|
||||
*/
|
||||
abstract public function applyToImage(Image $image, $posx = 0, $posy = 0);
|
||||
|
||||
/**
|
||||
* Set text to be written
|
||||
*
|
||||
* @param string $text
|
||||
* @return void
|
||||
*/
|
||||
public function background($color)
|
||||
{
|
||||
$this->background = $color;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set border width and color of current shape
|
||||
*
|
||||
* @param int $width
|
||||
* @param string $color
|
||||
* @return void
|
||||
*/
|
||||
public function border($width, $color = null)
|
||||
{
|
||||
$this->border_width = is_numeric($width) ? intval($width) : 0;
|
||||
$this->border_color = is_null($color) ? '#000000' : $color;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if current shape has border
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function hasBorder()
|
||||
{
|
||||
return ($this->border_width >= 1);
|
||||
}
|
||||
}
|
@ -1,81 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Intervention\Image\Commands;
|
||||
|
||||
use Intervention\Image\Commands\Argument;
|
||||
|
||||
abstract class AbstractCommand
|
||||
{
|
||||
/**
|
||||
* Arguments of command
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $arguments;
|
||||
|
||||
/**
|
||||
* Output of command
|
||||
*
|
||||
* @var mixed
|
||||
*/
|
||||
protected $output;
|
||||
|
||||
/**
|
||||
* Executes current command on given image
|
||||
*
|
||||
* @param \Intervention\Image\Image $image
|
||||
* @return mixed
|
||||
*/
|
||||
abstract public function execute($image);
|
||||
|
||||
/**
|
||||
* Creates new command instance
|
||||
*
|
||||
* @param array $arguments
|
||||
*/
|
||||
public function __construct($arguments)
|
||||
{
|
||||
$this->arguments = $arguments;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new argument instance from given argument key
|
||||
*
|
||||
* @param int $key
|
||||
* @return \Intervention\Image\Commands\Argument
|
||||
*/
|
||||
public function argument($key)
|
||||
{
|
||||
return new Argument($this, $key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns output data of current command
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function getOutput()
|
||||
{
|
||||
return $this->output ? $this->output : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if current instance has output data
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function hasOutput()
|
||||
{
|
||||
return ! is_null($this->output);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets output data of current command
|
||||
*
|
||||
* @param mixed $value
|
||||
*/
|
||||
public function setOutput($value)
|
||||
{
|
||||
$this->output = $value;
|
||||
}
|
||||
}
|
@ -1,225 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Intervention\Image\Commands;
|
||||
|
||||
use Intervention\Image\Exception\InvalidArgumentException;
|
||||
|
||||
class Argument
|
||||
{
|
||||
/**
|
||||
* Command with arguments
|
||||
*
|
||||
* @var AbstractCommand
|
||||
*/
|
||||
public $command;
|
||||
|
||||
/**
|
||||
* Key of argument in array
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $key;
|
||||
|
||||
/**
|
||||
* Creates new instance from given command and key
|
||||
*
|
||||
* @param AbstractCommand $command
|
||||
* @param int $key
|
||||
*/
|
||||
public function __construct(AbstractCommand $command, $key = 0)
|
||||
{
|
||||
$this->command = $command;
|
||||
$this->key = $key;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns name of current arguments command
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getCommandName()
|
||||
{
|
||||
preg_match("/\\\\([\w]+)Command$/", get_class($this->command), $matches);
|
||||
return isset($matches[1]) ? lcfirst($matches[1]).'()' : 'Method';
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns value of current argument
|
||||
*
|
||||
* @param mixed $default
|
||||
* @return mixed
|
||||
*/
|
||||
public function value($default = null)
|
||||
{
|
||||
$arguments = $this->command->arguments;
|
||||
|
||||
if (is_array($arguments)) {
|
||||
return isset($arguments[$this->key]) ? $arguments[$this->key] : $default;
|
||||
}
|
||||
|
||||
return $default;
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines current argument as required
|
||||
*
|
||||
* @return \Intervention\Image\Commands\Argument
|
||||
*/
|
||||
public function required()
|
||||
{
|
||||
if ( ! array_key_exists($this->key, $this->command->arguments)) {
|
||||
throw new InvalidArgumentException(
|
||||
sprintf("Missing argument %d for %s", $this->key + 1, $this->getCommandName())
|
||||
);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines that current argument must be of given type
|
||||
*
|
||||
* @return \Intervention\Image\Commands\Argument
|
||||
*/
|
||||
public function type($type)
|
||||
{
|
||||
$valid = true;
|
||||
$value = $this->value();
|
||||
|
||||
if ($value === null) {
|
||||
return $this;
|
||||
}
|
||||
|
||||
switch (strtolower($type)) {
|
||||
case 'bool':
|
||||
case 'boolean':
|
||||
$valid = \is_bool($value);
|
||||
$message = '%s accepts only boolean values as argument %d.';
|
||||
break;
|
||||
case 'int':
|
||||
case 'integer':
|
||||
$valid = \is_int($value);
|
||||
$message = '%s accepts only integer values as argument %d.';
|
||||
break;
|
||||
case 'num':
|
||||
case 'numeric':
|
||||
$valid = is_numeric($value);
|
||||
$message = '%s accepts only numeric values as argument %d.';
|
||||
break;
|
||||
case 'str':
|
||||
case 'string':
|
||||
$valid = \is_string($value);
|
||||
$message = '%s accepts only string values as argument %d.';
|
||||
break;
|
||||
case 'array':
|
||||
$valid = \is_array($value);
|
||||
$message = '%s accepts only array as argument %d.';
|
||||
break;
|
||||
case 'closure':
|
||||
$valid = is_a($value, '\Closure');
|
||||
$message = '%s accepts only Closure as argument %d.';
|
||||
break;
|
||||
case 'digit':
|
||||
$valid = $this->isDigit($value);
|
||||
$message = '%s accepts only integer values as argument %d.';
|
||||
break;
|
||||
}
|
||||
|
||||
if (! $valid) {
|
||||
$commandName = $this->getCommandName();
|
||||
$argument = $this->key + 1;
|
||||
|
||||
if (isset($message)) {
|
||||
$message = sprintf($message, $commandName, $argument);
|
||||
} else {
|
||||
$message = sprintf('Missing argument for %d.', $argument);
|
||||
}
|
||||
|
||||
throw new InvalidArgumentException(
|
||||
$message
|
||||
);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines that current argument value must be numeric between given values
|
||||
*
|
||||
* @return \Intervention\Image\Commands\Argument
|
||||
*/
|
||||
public function between($x, $y)
|
||||
{
|
||||
$value = $this->type('numeric')->value();
|
||||
|
||||
if (is_null($value)) {
|
||||
return $this;
|
||||
}
|
||||
|
||||
$alpha = min($x, $y);
|
||||
$omega = max($x, $y);
|
||||
|
||||
if ($value < $alpha || $value > $omega) {
|
||||
throw new InvalidArgumentException(
|
||||
sprintf('Argument %d must be between %s and %s.', $this->key, $x, $y)
|
||||
);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines that current argument must be over a minimum value
|
||||
*
|
||||
* @return \Intervention\Image\Commands\Argument
|
||||
*/
|
||||
public function min($value)
|
||||
{
|
||||
$v = $this->type('numeric')->value();
|
||||
|
||||
if (is_null($v)) {
|
||||
return $this;
|
||||
}
|
||||
|
||||
if ($v < $value) {
|
||||
throw new InvalidArgumentException(
|
||||
sprintf('Argument %d must be at least %s.', $this->key, $value)
|
||||
);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines that current argument must be under a maxiumum value
|
||||
*
|
||||
* @return \Intervention\Image\Commands\Argument
|
||||
*/
|
||||
public function max($value)
|
||||
{
|
||||
$v = $this->type('numeric')->value();
|
||||
|
||||
if (is_null($v)) {
|
||||
return $this;
|
||||
}
|
||||
|
||||
if ($v > $value) {
|
||||
throw new InvalidArgumentException(
|
||||
sprintf('Argument %d may not be greater than %s.', $this->key, $value)
|
||||
);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if value is "PHP" integer (120 but also 120.0)
|
||||
*
|
||||
* @param mixed $value
|
||||
* @return boolean
|
||||
*/
|
||||
private function isDigit($value)
|
||||
{
|
||||
return is_numeric($value) ? intval($value) == $value : false;
|
||||
}
|
||||
}
|
@ -1,29 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Intervention\Image\Commands;
|
||||
|
||||
class ChecksumCommand extends AbstractCommand
|
||||
{
|
||||
/**
|
||||
* Calculates checksum of given image
|
||||
*
|
||||
* @param \Intervention\Image\Image $image
|
||||
* @return boolean
|
||||
*/
|
||||
public function execute($image)
|
||||
{
|
||||
$colors = [];
|
||||
|
||||
$size = $image->getSize();
|
||||
|
||||
for ($x=0; $x <= ($size->width-1); $x++) {
|
||||
for ($y=0; $y <= ($size->height-1); $y++) {
|
||||
$colors[] = $image->pickColor($x, $y, 'array');
|
||||
}
|
||||
}
|
||||
|
||||
$this->setOutput(md5(serialize($colors)));
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
@ -1,35 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Intervention\Image\Commands;
|
||||
|
||||
use Closure;
|
||||
|
||||
class CircleCommand extends AbstractCommand
|
||||
{
|
||||
/**
|
||||
* Draw a circle centered on given image
|
||||
*
|
||||
* @param \Intervention\Image\image $image
|
||||
* @return boolean
|
||||
*/
|
||||
public function execute($image)
|
||||
{
|
||||
$diameter = $this->argument(0)->type('numeric')->required()->value();
|
||||
$x = $this->argument(1)->type('numeric')->required()->value();
|
||||
$y = $this->argument(2)->type('numeric')->required()->value();
|
||||
$callback = $this->argument(3)->type('closure')->value();
|
||||
|
||||
$circle_classname = sprintf('\Intervention\Image\%s\Shapes\CircleShape',
|
||||
$image->getDriver()->getDriverName());
|
||||
|
||||
$circle = new $circle_classname($diameter);
|
||||
|
||||
if ($callback instanceof Closure) {
|
||||
$callback($circle);
|
||||
}
|
||||
|
||||
$circle->applyToImage($image, $x, $y);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
@ -1,36 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Intervention\Image\Commands;
|
||||
|
||||
use Closure;
|
||||
|
||||
class EllipseCommand extends AbstractCommand
|
||||
{
|
||||
/**
|
||||
* Draws ellipse on given image
|
||||
*
|
||||
* @param \Intervention\Image\Image $image
|
||||
* @return boolean
|
||||
*/
|
||||
public function execute($image)
|
||||
{
|
||||
$width = $this->argument(0)->type('numeric')->required()->value();
|
||||
$height = $this->argument(1)->type('numeric')->required()->value();
|
||||
$x = $this->argument(2)->type('numeric')->required()->value();
|
||||
$y = $this->argument(3)->type('numeric')->required()->value();
|
||||
$callback = $this->argument(4)->type('closure')->value();
|
||||
|
||||
$ellipse_classname = sprintf('\Intervention\Image\%s\Shapes\EllipseShape',
|
||||
$image->getDriver()->getDriverName());
|
||||
|
||||
$ellipse = new $ellipse_classname($width, $height);
|
||||
|
||||
if ($callback instanceof Closure) {
|
||||
$callback($ellipse);
|
||||
}
|
||||
|
||||
$ellipse->applyToImage($image, $x, $y);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
@ -1,61 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Intervention\Image\Commands;
|
||||
|
||||
use Intervention\Image\Exception\NotReadableException;
|
||||
use Intervention\Image\Exception\NotSupportedException;
|
||||
|
||||
class ExifCommand extends AbstractCommand
|
||||
{
|
||||
/**
|
||||
* Read Exif data from the given image
|
||||
*
|
||||
* Note: Windows PHP Users - in order to use this method you will need to
|
||||
* enable the mbstring and exif extensions within the php.ini file.
|
||||
*
|
||||
* @param \Intervention\Image\Image $image
|
||||
* @return boolean
|
||||
*/
|
||||
public function execute($image)
|
||||
{
|
||||
if (!function_exists('exif_read_data')) {
|
||||
throw new NotSupportedException(
|
||||
"Reading Exif data is not supported by this PHP installation."
|
||||
);
|
||||
}
|
||||
|
||||
$key = $this->argument(0)->value();
|
||||
|
||||
// try to read exif data from image file
|
||||
try {
|
||||
if ($image->dirname && $image->basename) {
|
||||
$stream = $image->dirname . '/' . $image->basename;
|
||||
} elseif (version_compare(PHP_VERSION, '7.2.0', '>=')) {
|
||||
// https://www.php.net/manual/en/function.exif-read-data.php#refsect1-function.exif-read-data-changelog
|
||||
$stream = $image->stream()->detach();
|
||||
} else {
|
||||
// https://bugs.php.net/bug.php?id=65187
|
||||
$stream = $image->encode('data-url')->encoded;
|
||||
}
|
||||
|
||||
$data = @exif_read_data($stream);
|
||||
|
||||
if (!is_null($key) && is_array($data)) {
|
||||
$data = array_key_exists($key, $data) ? $data[$key] : false;
|
||||
}
|
||||
|
||||
} catch (\Exception $e) {
|
||||
throw new NotReadableException(
|
||||
sprintf(
|
||||
"Cannot read the Exif data from the filename (%s) provided ",
|
||||
$image->dirname . '/' . $image->basename
|
||||
),
|
||||
$e->getCode(),
|
||||
$e
|
||||
);
|
||||
}
|
||||
|
||||
$this->setOutput($data);
|
||||
return true;
|
||||
}
|
||||
}
|
@ -1,68 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Intervention\Image\Commands;
|
||||
|
||||
use Intervention\Image\Exception\NotSupportedException;
|
||||
|
||||
class IptcCommand extends AbstractCommand
|
||||
{
|
||||
/**
|
||||
* Read Iptc data from the given image
|
||||
*
|
||||
* @param \Intervention\Image\Image $image
|
||||
* @return boolean
|
||||
*/
|
||||
public function execute($image)
|
||||
{
|
||||
if ( ! function_exists('iptcparse')) {
|
||||
throw new NotSupportedException(
|
||||
"Reading Iptc data is not supported by this PHP installation."
|
||||
);
|
||||
}
|
||||
|
||||
$key = $this->argument(0)->value();
|
||||
|
||||
$info = [];
|
||||
@getimagesize($image->dirname .'/'. $image->basename, $info);
|
||||
|
||||
$data = [];
|
||||
|
||||
if (array_key_exists('APP13', $info)) {
|
||||
$iptc = iptcparse($info['APP13']);
|
||||
|
||||
if (is_array($iptc)) {
|
||||
$data['DocumentTitle'] = isset($iptc["2#005"][0]) ? $iptc["2#005"][0] : null;
|
||||
$data['Urgency'] = isset($iptc["2#010"][0]) ? $iptc["2#010"][0] : null;
|
||||
$data['Category'] = isset($iptc["2#015"][0]) ? $iptc["2#015"][0] : null;
|
||||
$data['Subcategories'] = isset($iptc["2#020"][0]) ? $iptc["2#020"][0] : null;
|
||||
$data['Keywords'] = isset($iptc["2#025"][0]) ? $iptc["2#025"] : null;
|
||||
$data['ReleaseDate'] = isset($iptc["2#030"][0]) ? $iptc["2#030"][0] : null;
|
||||
$data['ReleaseTime'] = isset($iptc["2#035"][0]) ? $iptc["2#035"][0] : null;
|
||||
$data['SpecialInstructions'] = isset($iptc["2#040"][0]) ? $iptc["2#040"][0] : null;
|
||||
$data['CreationDate'] = isset($iptc["2#055"][0]) ? $iptc["2#055"][0] : null;
|
||||
$data['CreationTime'] = isset($iptc["2#060"][0]) ? $iptc["2#060"][0] : null;
|
||||
$data['AuthorByline'] = isset($iptc["2#080"][0]) ? $iptc["2#080"][0] : null;
|
||||
$data['AuthorTitle'] = isset($iptc["2#085"][0]) ? $iptc["2#085"][0] : null;
|
||||
$data['City'] = isset($iptc["2#090"][0]) ? $iptc["2#090"][0] : null;
|
||||
$data['SubLocation'] = isset($iptc["2#092"][0]) ? $iptc["2#092"][0] : null;
|
||||
$data['State'] = isset($iptc["2#095"][0]) ? $iptc["2#095"][0] : null;
|
||||
$data['Country'] = isset($iptc["2#101"][0]) ? $iptc["2#101"][0] : null;
|
||||
$data['OTR'] = isset($iptc["2#103"][0]) ? $iptc["2#103"][0] : null;
|
||||
$data['Headline'] = isset($iptc["2#105"][0]) ? $iptc["2#105"][0] : null;
|
||||
$data['Source'] = isset($iptc["2#110"][0]) ? $iptc["2#110"][0] : null;
|
||||
$data['PhotoSource'] = isset($iptc["2#115"][0]) ? $iptc["2#115"][0] : null;
|
||||
$data['Copyright'] = isset($iptc["2#116"][0]) ? $iptc["2#116"][0] : null;
|
||||
$data['Caption'] = isset($iptc["2#120"][0]) ? $iptc["2#120"][0] : null;
|
||||
$data['CaptionWriter'] = isset($iptc["2#122"][0]) ? $iptc["2#122"][0] : null;
|
||||
}
|
||||
}
|
||||
|
||||
if (! is_null($key) && is_array($data)) {
|
||||
$data = array_key_exists($key, $data) ? $data[$key] : false;
|
||||
}
|
||||
|
||||
$this->setOutput($data);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
@ -1,36 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Intervention\Image\Commands;
|
||||
|
||||
use Closure;
|
||||
|
||||
class LineCommand extends AbstractCommand
|
||||
{
|
||||
/**
|
||||
* Draws line on given image
|
||||
*
|
||||
* @param \Intervention\Image\Image $image
|
||||
* @return boolean
|
||||
*/
|
||||
public function execute($image)
|
||||
{
|
||||
$x1 = $this->argument(0)->type('numeric')->required()->value();
|
||||
$y1 = $this->argument(1)->type('numeric')->required()->value();
|
||||
$x2 = $this->argument(2)->type('numeric')->required()->value();
|
||||
$y2 = $this->argument(3)->type('numeric')->required()->value();
|
||||
$callback = $this->argument(4)->type('closure')->value();
|
||||
|
||||
$line_classname = sprintf('\Intervention\Image\%s\Shapes\LineShape',
|
||||
$image->getDriver()->getDriverName());
|
||||
|
||||
$line = new $line_classname($x2, $y2);
|
||||
|
||||
if ($callback instanceof Closure) {
|
||||
$callback($line);
|
||||
}
|
||||
|
||||
$line->applyToImage($image, $x1, $y1);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
@ -1,48 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Intervention\Image\Commands;
|
||||
|
||||
class OrientateCommand extends AbstractCommand
|
||||
{
|
||||
/**
|
||||
* Correct image orientation according to Exif data
|
||||
*
|
||||
* @param \Intervention\Image\Image $image
|
||||
* @return boolean
|
||||
*/
|
||||
public function execute($image)
|
||||
{
|
||||
switch ($image->exif('Orientation')) {
|
||||
|
||||
case 2:
|
||||
$image->flip();
|
||||
break;
|
||||
|
||||
case 3:
|
||||
$image->rotate(180);
|
||||
break;
|
||||
|
||||
case 4:
|
||||
$image->rotate(180)->flip();
|
||||
break;
|
||||
|
||||
case 5:
|
||||
$image->rotate(270)->flip();
|
||||
break;
|
||||
|
||||
case 6:
|
||||
$image->rotate(270);
|
||||
break;
|
||||
|
||||
case 7:
|
||||
$image->rotate(90)->flip();
|
||||
break;
|
||||
|
||||
case 8:
|
||||
$image->rotate(90);
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
@ -1,49 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Intervention\Image\Commands;
|
||||
|
||||
use Closure;
|
||||
use Intervention\Image\Exception\InvalidArgumentException;
|
||||
|
||||
class PolygonCommand extends AbstractCommand
|
||||
{
|
||||
/**
|
||||
* Draw a polygon on given image
|
||||
*
|
||||
* @param \Intervention\Image\image $image
|
||||
* @return boolean
|
||||
*/
|
||||
public function execute($image)
|
||||
{
|
||||
$points = $this->argument(0)->type('array')->required()->value();
|
||||
$callback = $this->argument(1)->type('closure')->value();
|
||||
|
||||
$vertices_count = count($points);
|
||||
|
||||
// check if number if coordinates is even
|
||||
if ($vertices_count % 2 !== 0) {
|
||||
throw new InvalidArgumentException(
|
||||
"The number of given polygon vertices must be even."
|
||||
);
|
||||
}
|
||||
|
||||
if ($vertices_count < 6) {
|
||||
throw new InvalidArgumentException(
|
||||
"You must have at least 3 points in your array."
|
||||
);
|
||||
}
|
||||
|
||||
$polygon_classname = sprintf('\Intervention\Image\%s\Shapes\PolygonShape',
|
||||
$image->getDriver()->getDriverName());
|
||||
|
||||
$polygon = new $polygon_classname($points);
|
||||
|
||||
if ($callback instanceof Closure) {
|
||||
$callback($polygon);
|
||||
}
|
||||
|
||||
$polygon->applyToImage($image);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
@ -1,45 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Intervention\Image\Commands;
|
||||
|
||||
use GuzzleHttp\Psr7\Response;
|
||||
|
||||
class PsrResponseCommand extends AbstractCommand
|
||||
{
|
||||
/**
|
||||
* Builds PSR7 compatible response. May replace "response" command in
|
||||
* some future.
|
||||
*
|
||||
* Method will generate binary stream and put it inside PSR-7
|
||||
* ResponseInterface. Following code can be optimized using native php
|
||||
* streams and more "clean" streaming, however drivers has to be updated
|
||||
* first.
|
||||
*
|
||||
* @param \Intervention\Image\Image $image
|
||||
* @return boolean
|
||||
*/
|
||||
public function execute($image)
|
||||
{
|
||||
$format = $this->argument(0)->value();
|
||||
$quality = $this->argument(1)->between(0, 100)->value();
|
||||
|
||||
//Encoded property will be populated at this moment
|
||||
$stream = $image->stream($format, $quality);
|
||||
|
||||
$mimetype = finfo_buffer(
|
||||
finfo_open(FILEINFO_MIME_TYPE),
|
||||
$image->getEncoded()
|
||||
);
|
||||
|
||||
$this->setOutput(new Response(
|
||||
200,
|
||||
[
|
||||
'Content-Type' => $mimetype,
|
||||
'Content-Length' => strlen($image->getEncoded())
|
||||
],
|
||||
$stream
|
||||
));
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
@ -1,36 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Intervention\Image\Commands;
|
||||
|
||||
use Closure;
|
||||
|
||||
class RectangleCommand extends AbstractCommand
|
||||
{
|
||||
/**
|
||||
* Draws rectangle on given image
|
||||
*
|
||||
* @param \Intervention\Image\Image $image
|
||||
* @return boolean
|
||||
*/
|
||||
public function execute($image)
|
||||
{
|
||||
$x1 = $this->argument(0)->type('numeric')->required()->value();
|
||||
$y1 = $this->argument(1)->type('numeric')->required()->value();
|
||||
$x2 = $this->argument(2)->type('numeric')->required()->value();
|
||||
$y2 = $this->argument(3)->type('numeric')->required()->value();
|
||||
$callback = $this->argument(4)->type('closure')->value();
|
||||
|
||||
$rectangle_classname = sprintf('\Intervention\Image\%s\Shapes\RectangleShape',
|
||||
$image->getDriver()->getDriverName());
|
||||
|
||||
$rectangle = new $rectangle_classname($x1, $y1, $x2, $y2);
|
||||
|
||||
if ($callback instanceof Closure) {
|
||||
$callback($rectangle);
|
||||
}
|
||||
|
||||
$rectangle->applyToImage($image, $x1, $y1);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
@ -1,26 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Intervention\Image\Commands;
|
||||
|
||||
use Intervention\Image\Response;
|
||||
|
||||
class ResponseCommand extends AbstractCommand
|
||||
{
|
||||
/**
|
||||
* Builds HTTP response from given image
|
||||
*
|
||||
* @param \Intervention\Image\Image $image
|
||||
* @return boolean
|
||||
*/
|
||||
public function execute($image)
|
||||
{
|
||||
$format = $this->argument(0)->value();
|
||||
$quality = $this->argument(1)->between(0, 100)->value();
|
||||
|
||||
$response = new Response($image, $format, $quality);
|
||||
|
||||
$this->setOutput($response->make());
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
@ -1,39 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Intervention\Image\Commands;
|
||||
|
||||
class StreamCommand extends AbstractCommand
|
||||
{
|
||||
/**
|
||||
* Builds PSR7 stream based on image data. Method uses Guzzle PSR7
|
||||
* implementation as easiest choice.
|
||||
*
|
||||
* @param \Intervention\Image\Image $image
|
||||
* @return boolean
|
||||
*/
|
||||
public function execute($image)
|
||||
{
|
||||
$format = $this->argument(0)->value();
|
||||
$quality = $this->argument(1)->between(0, 100)->value();
|
||||
$data = $image->encode($format, $quality)->getEncoded();
|
||||
|
||||
$this->setOutput($this->getStream($data));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create stream from given data
|
||||
*
|
||||
* @param string $data
|
||||
* @return \Psr\Http\Message\StreamInterface
|
||||
*/
|
||||
protected function getStream($data)
|
||||
{
|
||||
if (class_exists(\GuzzleHttp\Psr7\Utils::class)) {
|
||||
return \GuzzleHttp\Psr7\Utils::streamFor($data); // guzzlehttp/psr7 >= 2.0
|
||||
}
|
||||
|
||||
return \GuzzleHttp\Psr7\stream_for($data); // guzzlehttp/psr7 < 2.0
|
||||
}
|
||||
}
|
@ -1,34 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Intervention\Image\Commands;
|
||||
|
||||
use Closure;
|
||||
|
||||
class TextCommand extends AbstractCommand
|
||||
{
|
||||
/**
|
||||
* Write text on given image
|
||||
* @param \Intervention\Image\Image $image
|
||||
* @return boolean
|
||||
*/
|
||||
public function execute($image)
|
||||
{
|
||||
$text = $this->argument(0)->required()->value();
|
||||
$x = $this->argument(1)->type('numeric')->value(0);
|
||||
$y = $this->argument(2)->type('numeric')->value(0);
|
||||
$callback = $this->argument(3)->type('closure')->value();
|
||||
|
||||
$fontclassname = sprintf('\Intervention\Image\%s\Font',
|
||||
$image->getDriver()->getDriverName());
|
||||
|
||||
$font = new $fontclassname($text);
|
||||
|
||||
if ($callback instanceof Closure) {
|
||||
$callback($font);
|
||||
}
|
||||
|
||||
$font->applyToImage($image, $x, $y);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
@ -1,92 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Intervention\Image;
|
||||
|
||||
class Constraint
|
||||
{
|
||||
/**
|
||||
* Bit value of aspect ratio constraint
|
||||
*/
|
||||
const ASPECTRATIO = 1;
|
||||
|
||||
/**
|
||||
* Bit value of upsize constraint
|
||||
*/
|
||||
const UPSIZE = 2;
|
||||
|
||||
/**
|
||||
* Constraint size
|
||||
*
|
||||
* @var \Intervention\Image\Size
|
||||
*/
|
||||
private $size;
|
||||
|
||||
/**
|
||||
* Integer value of fixed parameters
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
private $fixed = 0;
|
||||
|
||||
/**
|
||||
* Create a new constraint based on size
|
||||
*
|
||||
* @param Size $size
|
||||
*/
|
||||
public function __construct(Size $size)
|
||||
{
|
||||
$this->size = $size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns current size of constraint
|
||||
*
|
||||
* @return \Intervention\Image\Size
|
||||
*/
|
||||
public function getSize()
|
||||
{
|
||||
return $this->size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fix the given argument in current constraint
|
||||
*
|
||||
* @param int $type
|
||||
* @return void
|
||||
*/
|
||||
public function fix($type)
|
||||
{
|
||||
$this->fixed = ($this->fixed & ~(1 << $type)) | (1 << $type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if given argument is fixed in current constraint
|
||||
*
|
||||
* @param int $type
|
||||
* @return boolean
|
||||
*/
|
||||
public function isFixed($type)
|
||||
{
|
||||
return (bool) ($this->fixed & (1 << $type));
|
||||
}
|
||||
|
||||
/**
|
||||
* Fixes aspect ratio in current constraint
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function aspectRatio()
|
||||
{
|
||||
$this->fix(self::ASPECTRATIO);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fixes possibility to size up in current constraint
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function upsize()
|
||||
{
|
||||
$this->fix(self::UPSIZE);
|
||||
}
|
||||
}
|
@ -1,8 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Intervention\Image\Exception;
|
||||
|
||||
class ImageException extends \RuntimeException
|
||||
{
|
||||
# nothing to override
|
||||
}
|
@ -1,8 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Intervention\Image\Exception;
|
||||
|
||||
class InvalidArgumentException extends ImageException
|
||||
{
|
||||
# nothing to override
|
||||
}
|
@ -1,8 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Intervention\Image\Exception;
|
||||
|
||||
class MissingDependencyException extends ImageException
|
||||
{
|
||||
# nothing to override
|
||||
}
|
@ -1,8 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Intervention\Image\Exception;
|
||||
|
||||
class NotFoundException extends ImageException
|
||||
{
|
||||
# nothing to override
|
||||
}
|
@ -1,8 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Intervention\Image\Exception;
|
||||
|
||||
class NotReadableException extends ImageException
|
||||
{
|
||||
# nothing to override
|
||||
}
|
@ -1,8 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Intervention\Image\Exception;
|
||||
|
||||
class NotSupportedException extends ImageException
|
||||
{
|
||||
# nothing to override
|
||||
}
|
@ -1,8 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Intervention\Image\Exception;
|
||||
|
||||
class NotWritableException extends ImageException
|
||||
{
|
||||
# nothing to override
|
||||
}
|
@ -1,8 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Intervention\Image\Exception;
|
||||
|
||||
class RuntimeException extends ImageException
|
||||
{
|
||||
# nothing to override
|
||||
}
|
@ -1,19 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Intervention\Image\Facades;
|
||||
|
||||
use Illuminate\Support\Facades\Facade;
|
||||
|
||||
/**
|
||||
* @method static \Intervention\Image\Image make(mixed $data)
|
||||
* @method static self configure(array $config)
|
||||
* @method static \Intervention\Image\Image canvas(int $width, int $height, mixed $background = null)
|
||||
* @method static \Intervention\Image\Image cache(\Closure $callback, int $lifetime = null, boolean $returnObj = false)
|
||||
*/
|
||||
class Image extends Facade
|
||||
{
|
||||
protected static function getFacadeAccessor()
|
||||
{
|
||||
return 'image';
|
||||
}
|
||||
}
|
@ -1,92 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Intervention\Image;
|
||||
|
||||
class File
|
||||
{
|
||||
/**
|
||||
* Mime type
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $mime;
|
||||
|
||||
/**
|
||||
* Name of directory path
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $dirname;
|
||||
|
||||
/**
|
||||
* Basename of current file
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $basename;
|
||||
|
||||
/**
|
||||
* File extension of current file
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $extension;
|
||||
|
||||
/**
|
||||
* File name of current file
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $filename;
|
||||
|
||||
/**
|
||||
* Sets all instance properties from given path
|
||||
*
|
||||
* @param string $path
|
||||
*/
|
||||
public function setFileInfoFromPath($path)
|
||||
{
|
||||
$info = pathinfo($path);
|
||||
$this->dirname = array_key_exists('dirname', $info) ? $info['dirname'] : null;
|
||||
$this->basename = array_key_exists('basename', $info) ? $info['basename'] : null;
|
||||
$this->extension = array_key_exists('extension', $info) ? $info['extension'] : null;
|
||||
$this->filename = array_key_exists('filename', $info) ? $info['filename'] : null;
|
||||
|
||||
if (file_exists($path) && is_file($path)) {
|
||||
$this->mime = finfo_file(finfo_open(FILEINFO_MIME_TYPE), $path);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get file size
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function filesize()
|
||||
{
|
||||
$path = $this->basePath();
|
||||
|
||||
if (file_exists($path) && is_file($path)) {
|
||||
return filesize($path);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get fully qualified path
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function basePath()
|
||||
{
|
||||
if ($this->dirname && $this->basename) {
|
||||
return ($this->dirname .'/'. $this->basename);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
@ -1,44 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Intervention\Image\Filters;
|
||||
|
||||
use Intervention\Image\Image;
|
||||
|
||||
class DemoFilter implements FilterInterface
|
||||
{
|
||||
/**
|
||||
* Default size of filter effects
|
||||
*/
|
||||
const DEFAULT_SIZE = 10;
|
||||
|
||||
/**
|
||||
* Size of filter effects
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
private $size;
|
||||
|
||||
/**
|
||||
* Creates new instance of filter
|
||||
*
|
||||
* @param int $size
|
||||
*/
|
||||
public function __construct($size = null)
|
||||
{
|
||||
$this->size = is_numeric($size) ? intval($size) : self::DEFAULT_SIZE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies filter effects to given image
|
||||
*
|
||||
* @param \Intervention\Image\Image $image
|
||||
* @return \Intervention\Image\Image
|
||||
*/
|
||||
public function applyFilter(Image $image)
|
||||
{
|
||||
$image->pixelate($this->size);
|
||||
$image->greyscale();
|
||||
|
||||
return $image;
|
||||
}
|
||||
}
|
@ -1,16 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Intervention\Image\Filters;
|
||||
|
||||
use Intervention\Image\Image;
|
||||
|
||||
interface FilterInterface
|
||||
{
|
||||
/**
|
||||
* Applies filter to given image
|
||||
*
|
||||
* @param \Intervention\Image\Image $image
|
||||
* @return \Intervention\Image\Image
|
||||
*/
|
||||
public function applyFilter(Image $image);
|
||||
}
|
@ -1,227 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Intervention\Image\Gd;
|
||||
|
||||
use Intervention\Image\AbstractColor;
|
||||
use Intervention\Image\Exception\NotSupportedException;
|
||||
|
||||
class Color extends AbstractColor
|
||||
{
|
||||
/**
|
||||
* RGB Red value of current color instance
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $r;
|
||||
|
||||
/**
|
||||
* RGB Green value of current color instance
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $g;
|
||||
|
||||
/**
|
||||
* RGB Blue value of current color instance
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $b;
|
||||
|
||||
/**
|
||||
* RGB Alpha value of current color instance
|
||||
*
|
||||
* @var float
|
||||
*/
|
||||
public $a;
|
||||
|
||||
/**
|
||||
* Initiates color object from integer
|
||||
*
|
||||
* @param int $value
|
||||
* @return \Intervention\Image\AbstractColor
|
||||
*/
|
||||
public function initFromInteger($value)
|
||||
{
|
||||
$this->a = ($value >> 24) & 0xFF;
|
||||
$this->r = ($value >> 16) & 0xFF;
|
||||
$this->g = ($value >> 8) & 0xFF;
|
||||
$this->b = $value & 0xFF;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initiates color object from given array
|
||||
*
|
||||
* @param array $value
|
||||
* @return \Intervention\Image\AbstractColor
|
||||
*/
|
||||
public function initFromArray($array)
|
||||
{
|
||||
$array = array_values($array);
|
||||
|
||||
if (count($array) == 4) {
|
||||
|
||||
// color array with alpha value
|
||||
list($r, $g, $b, $a) = $array;
|
||||
$this->a = $this->alpha2gd($a);
|
||||
|
||||
} elseif (count($array) == 3) {
|
||||
|
||||
// color array without alpha value
|
||||
list($r, $g, $b) = $array;
|
||||
$this->a = 0;
|
||||
|
||||
}
|
||||
|
||||
$this->r = $r;
|
||||
$this->g = $g;
|
||||
$this->b = $b;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initiates color object from given string
|
||||
*
|
||||
* @param string $value
|
||||
* @return \Intervention\Image\AbstractColor
|
||||
*/
|
||||
public function initFromString($value)
|
||||
{
|
||||
if ($color = $this->rgbaFromString($value)) {
|
||||
$this->r = $color[0];
|
||||
$this->g = $color[1];
|
||||
$this->b = $color[2];
|
||||
$this->a = $this->alpha2gd($color[3]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initiates color object from given R, G and B values
|
||||
*
|
||||
* @param int $r
|
||||
* @param int $g
|
||||
* @param int $b
|
||||
* @return \Intervention\Image\AbstractColor
|
||||
*/
|
||||
public function initFromRgb($r, $g, $b)
|
||||
{
|
||||
$this->r = intval($r);
|
||||
$this->g = intval($g);
|
||||
$this->b = intval($b);
|
||||
$this->a = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initiates color object from given R, G, B and A values
|
||||
*
|
||||
* @param int $r
|
||||
* @param int $g
|
||||
* @param int $b
|
||||
* @param float $a
|
||||
* @return \Intervention\Image\AbstractColor
|
||||
*/
|
||||
public function initFromRgba($r, $g, $b, $a = 1)
|
||||
{
|
||||
$this->r = intval($r);
|
||||
$this->g = intval($g);
|
||||
$this->b = intval($b);
|
||||
$this->a = $this->alpha2gd($a);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initiates color object from given ImagickPixel object
|
||||
*
|
||||
* @param ImagickPixel $value
|
||||
* @return \Intervention\Image\AbstractColor
|
||||
*/
|
||||
public function initFromObject($value)
|
||||
{
|
||||
throw new NotSupportedException(
|
||||
"GD colors cannot init from ImagickPixel objects."
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates integer value of current color instance
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getInt()
|
||||
{
|
||||
return ($this->a << 24) + ($this->r << 16) + ($this->g << 8) + $this->b;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates hexadecimal value of current color instance
|
||||
*
|
||||
* @param string $prefix
|
||||
* @return string
|
||||
*/
|
||||
public function getHex($prefix = '')
|
||||
{
|
||||
return sprintf('%s%02x%02x%02x', $prefix, $this->r, $this->g, $this->b);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates RGB(A) in array format of current color instance
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getArray()
|
||||
{
|
||||
return [$this->r, $this->g, $this->b, round(1 - $this->a / 127, 2)];
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates RGBA in string format of current color instance
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getRgba()
|
||||
{
|
||||
return sprintf('rgba(%d, %d, %d, %.2F)', $this->r, $this->g, $this->b, round(1 - $this->a / 127, 2));
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if current color is different from given color
|
||||
*
|
||||
* @param AbstractColor $color
|
||||
* @param int $tolerance
|
||||
* @return boolean
|
||||
*/
|
||||
public function differs(AbstractColor $color, $tolerance = 0)
|
||||
{
|
||||
$color_tolerance = round($tolerance * 2.55);
|
||||
$alpha_tolerance = round($tolerance * 1.27);
|
||||
|
||||
$delta = [
|
||||
'r' => abs($color->r - $this->r),
|
||||
'g' => abs($color->g - $this->g),
|
||||
'b' => abs($color->b - $this->b),
|
||||
'a' => abs($color->a - $this->a)
|
||||
];
|
||||
|
||||
return (
|
||||
$delta['r'] > $color_tolerance or
|
||||
$delta['g'] > $color_tolerance or
|
||||
$delta['b'] > $color_tolerance or
|
||||
$delta['a'] > $alpha_tolerance
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert rgba alpha (0-1) value to gd value (0-127)
|
||||
*
|
||||
* @param float $input
|
||||
* @return int
|
||||
*/
|
||||
private function alpha2gd($input)
|
||||
{
|
||||
$oldMin = 0;
|
||||
$oldMax = 1;
|
||||
|
||||
$newMin = 127;
|
||||
$newMax = 0;
|
||||
|
||||
return ceil(((($input- $oldMin) * ($newMax - $newMin)) / ($oldMax - $oldMin)) + $newMin);
|
||||
}
|
||||
}
|
@ -1,25 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Intervention\Image\Gd\Commands;
|
||||
|
||||
use Intervention\Image\Commands\AbstractCommand;
|
||||
|
||||
class BackupCommand extends AbstractCommand
|
||||
{
|
||||
/**
|
||||
* Saves a backups of current state of image core
|
||||
*
|
||||
* @param \Intervention\Image\Image $image
|
||||
* @return boolean
|
||||
*/
|
||||
public function execute($image)
|
||||
{
|
||||
$backupName = $this->argument(0)->value();
|
||||
|
||||
// clone current image resource
|
||||
$clone = clone $image;
|
||||
$image->setBackup($clone->getCore(), $backupName);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
@ -1,25 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Intervention\Image\Gd\Commands;
|
||||
|
||||
use Intervention\Image\Commands\AbstractCommand;
|
||||
|
||||
class BlurCommand extends AbstractCommand
|
||||
{
|
||||
/**
|
||||
* Applies blur effect on image
|
||||
*
|
||||
* @param \Intervention\Image\Image $image
|
||||
* @return boolean
|
||||
*/
|
||||
public function execute($image)
|
||||
{
|
||||
$amount = $this->argument(0)->between(0, 100)->value(1);
|
||||
|
||||
for ($i=0; $i < intval($amount); $i++) {
|
||||
imagefilter($image->getCore(), IMG_FILTER_GAUSSIAN_BLUR);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
@ -1,21 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Intervention\Image\Gd\Commands;
|
||||
|
||||
use Intervention\Image\Commands\AbstractCommand;
|
||||
|
||||
class BrightnessCommand extends AbstractCommand
|
||||
{
|
||||
/**
|
||||
* Changes image brightness
|
||||
*
|
||||
* @param \Intervention\Image\Image $image
|
||||
* @return boolean
|
||||
*/
|
||||
public function execute($image)
|
||||
{
|
||||
$level = $this->argument(0)->between(-100, 100)->required()->value();
|
||||
|
||||
return imagefilter($image->getCore(), IMG_FILTER_BRIGHTNESS, ($level * 2.55));
|
||||
}
|
||||
}
|
@ -1,29 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Intervention\Image\Gd\Commands;
|
||||
|
||||
use Intervention\Image\Commands\AbstractCommand;
|
||||
|
||||
class ColorizeCommand extends AbstractCommand
|
||||
{
|
||||
/**
|
||||
* Changes balance of different RGB color channels
|
||||
*
|
||||
* @param \Intervention\Image\Image $image
|
||||
* @return boolean
|
||||
*/
|
||||
public function execute($image)
|
||||
{
|
||||
$red = $this->argument(0)->between(-100, 100)->required()->value();
|
||||
$green = $this->argument(1)->between(-100, 100)->required()->value();
|
||||
$blue = $this->argument(2)->between(-100, 100)->required()->value();
|
||||
|
||||
// normalize colorize levels
|
||||
$red = round($red * 2.55);
|
||||
$green = round($green * 2.55);
|
||||
$blue = round($blue * 2.55);
|
||||
|
||||
// apply filter
|
||||
return imagefilter($image->getCore(), IMG_FILTER_COLORIZE, $red, $green, $blue);
|
||||
}
|
||||
}
|
@ -1,21 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Intervention\Image\Gd\Commands;
|
||||
|
||||
use Intervention\Image\Commands\AbstractCommand;
|
||||
|
||||
class ContrastCommand extends AbstractCommand
|
||||
{
|
||||
/**
|
||||
* Changes contrast of image
|
||||
*
|
||||
* @param \Intervention\Image\Image $image
|
||||
* @return boolean
|
||||
*/
|
||||
public function execute($image)
|
||||
{
|
||||
$level = $this->argument(0)->between(-100, 100)->required()->value();
|
||||
|
||||
return imagefilter($image->getCore(), IMG_FILTER_CONTRAST, ($level * -1));
|
||||
}
|
||||
}
|
@ -1,40 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Intervention\Image\Gd\Commands;
|
||||
|
||||
use Intervention\Image\Point;
|
||||
use Intervention\Image\Size;
|
||||
|
||||
class CropCommand extends ResizeCommand
|
||||
{
|
||||
/**
|
||||
* Crop an image instance
|
||||
*
|
||||
* @param \Intervention\Image\Image $image
|
||||
* @return boolean
|
||||
*/
|
||||
public function execute($image)
|
||||
{
|
||||
$width = $this->argument(0)->type('digit')->required()->value();
|
||||
$height = $this->argument(1)->type('digit')->required()->value();
|
||||
$x = $this->argument(2)->type('digit')->value();
|
||||
$y = $this->argument(3)->type('digit')->value();
|
||||
|
||||
if (is_null($width) || is_null($height)) {
|
||||
throw new \Intervention\Image\Exception\InvalidArgumentException(
|
||||
"Width and height of cutout needs to be defined."
|
||||
);
|
||||
}
|
||||
|
||||
$cropped = new Size($width, $height);
|
||||
$position = new Point($x, $y);
|
||||
|
||||
// align boxes
|
||||
if (is_null($x) && is_null($y)) {
|
||||
$position = $image->getSize()->align('center')->relativePosition($cropped->align('center'));
|
||||
}
|
||||
|
||||
// crop image core
|
||||
return $this->modify($image, 0, 0, $position->x, $position->y, $cropped->width, $cropped->height, $cropped->width, $cropped->height);
|
||||
}
|
||||
}
|
@ -1,27 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Intervention\Image\Gd\Commands;
|
||||
|
||||
use Intervention\Image\Commands\AbstractCommand;
|
||||
|
||||
class DestroyCommand extends AbstractCommand
|
||||
{
|
||||
/**
|
||||
* Destroys current image core and frees up memory
|
||||
*
|
||||
* @param \Intervention\Image\Image $image
|
||||
* @return boolean
|
||||
*/
|
||||
public function execute($image)
|
||||
{
|
||||
// destroy image core
|
||||
imagedestroy($image->getCore());
|
||||
|
||||
// destroy backups
|
||||
foreach ($image->getBackups() as $backup) {
|
||||
imagedestroy($backup);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
@ -1,69 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Intervention\Image\Gd\Commands;
|
||||
|
||||
use Intervention\Image\Commands\AbstractCommand;
|
||||
use Intervention\Image\Gd\Color;
|
||||
use Intervention\Image\Gd\Decoder;
|
||||
|
||||
class FillCommand extends AbstractCommand
|
||||
{
|
||||
/**
|
||||
* Fills image with color or pattern
|
||||
*
|
||||
* @param \Intervention\Image\Image $image
|
||||
* @return boolean
|
||||
*/
|
||||
public function execute($image)
|
||||
{
|
||||
$filling = $this->argument(0)->value();
|
||||
$x = $this->argument(1)->type('digit')->value();
|
||||
$y = $this->argument(2)->type('digit')->value();
|
||||
|
||||
$width = $image->getWidth();
|
||||
$height = $image->getHeight();
|
||||
$resource = $image->getCore();
|
||||
|
||||
try {
|
||||
|
||||
// set image tile filling
|
||||
$source = new Decoder;
|
||||
$tile = $source->init($filling);
|
||||
imagesettile($image->getCore(), $tile->getCore());
|
||||
$filling = IMG_COLOR_TILED;
|
||||
|
||||
} catch (\Intervention\Image\Exception\NotReadableException $e) {
|
||||
|
||||
// set solid color filling
|
||||
$color = new Color($filling);
|
||||
$filling = $color->getInt();
|
||||
}
|
||||
|
||||
imagealphablending($resource, true);
|
||||
|
||||
if (is_int($x) && is_int($y)) {
|
||||
|
||||
// resource should be visible through transparency
|
||||
$base = $image->getDriver()->newImage($width, $height)->getCore();
|
||||
imagecopy($base, $resource, 0, 0, 0, 0, $width, $height);
|
||||
|
||||
// floodfill if exact position is defined
|
||||
imagefill($resource, $x, $y, $filling);
|
||||
|
||||
// copy filled original over base
|
||||
imagecopy($base, $resource, 0, 0, 0, 0, $width, $height);
|
||||
|
||||
// set base as new resource-core
|
||||
$image->setCore($base);
|
||||
imagedestroy($resource);
|
||||
|
||||
} else {
|
||||
// fill whole image otherwise
|
||||
imagefilledrectangle($resource, 0, 0, $width - 1, $height - 1, $filling);
|
||||
}
|
||||
|
||||
isset($tile) ? imagedestroy($tile->getCore()) : null;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
@ -1,32 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Intervention\Image\Gd\Commands;
|
||||
|
||||
use Intervention\Image\Size;
|
||||
|
||||
class FitCommand extends ResizeCommand
|
||||
{
|
||||
/**
|
||||
* Crops and resized an image at the same time
|
||||
*
|
||||
* @param \Intervention\Image\Image $image
|
||||
* @return boolean
|
||||
*/
|
||||
public function execute($image)
|
||||
{
|
||||
$width = $this->argument(0)->type('digit')->required()->value();
|
||||
$height = $this->argument(1)->type('digit')->value($width);
|
||||
$constraints = $this->argument(2)->type('closure')->value();
|
||||
$position = $this->argument(3)->type('string')->value('center');
|
||||
|
||||
// calculate size
|
||||
$cropped = $image->getSize()->fit(new Size($width, $height), $position);
|
||||
$resized = clone $cropped;
|
||||
$resized = $resized->resize($width, $height, $constraints);
|
||||
|
||||
// modify image
|
||||
$this->modify($image, 0, 0, $cropped->pivot->x, $cropped->pivot->y, $resized->getWidth(), $resized->getHeight(), $cropped->getWidth(), $cropped->getHeight());
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
@ -1,37 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Intervention\Image\Gd\Commands;
|
||||
|
||||
class FlipCommand extends ResizeCommand
|
||||
{
|
||||
/**
|
||||
* Mirrors an image
|
||||
*
|
||||
* @param \Intervention\Image\Image $image
|
||||
* @return boolean
|
||||
*/
|
||||
public function execute($image)
|
||||
{
|
||||
$mode = $this->argument(0)->value('h');
|
||||
|
||||
$size = $image->getSize();
|
||||
$dst = clone $size;
|
||||
|
||||
switch (strtolower($mode)) {
|
||||
case 2:
|
||||
case 'v':
|
||||
case 'vert':
|
||||
case 'vertical':
|
||||
$size->pivot->y = $size->height - 1;
|
||||
$size->height = $size->height * (-1);
|
||||
break;
|
||||
|
||||
default:
|
||||
$size->pivot->x = $size->width - 1;
|
||||
$size->width = $size->width * (-1);
|
||||
break;
|
||||
}
|
||||
|
||||
return $this->modify($image, 0, 0, $size->pivot->x, $size->pivot->y, $dst->width, $dst->height, $size->width, $size->height);
|
||||
}
|
||||
}
|
@ -1,21 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Intervention\Image\Gd\Commands;
|
||||
|
||||
use Intervention\Image\Commands\AbstractCommand;
|
||||
|
||||
class GammaCommand extends AbstractCommand
|
||||
{
|
||||
/**
|
||||
* Applies gamma correction to a given image
|
||||
*
|
||||
* @param \Intervention\Image\Image $image
|
||||
* @return boolean
|
||||
*/
|
||||
public function execute($image)
|
||||
{
|
||||
$gamma = $this->argument(0)->type('numeric')->required()->value();
|
||||
|
||||
return imagegammacorrect($image->getCore(), 1, $gamma);
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user