big overhaul of structure, stubs of tests
This commit is contained in:
parent
e95b1d7413
commit
fa8607b276
20 changed files with 623 additions and 143 deletions
54
README.md
54
README.md
|
@ -4,7 +4,7 @@ A tightly-focused library for performing a very limited set of simple image tran
|
||||||
|
|
||||||
## Roadmap
|
## Roadmap
|
||||||
|
|
||||||
This library is under active development, and until a 1.0 release is made you should expect it to potentially change its API and functionality. Possibly **drastically**. That said, I *do* have use of this thing for work, so I'm probably going to be working pretty dang hard on it, and hope to have a stable release by about November of 2020.
|
This library is under active development, and until a 1.0 release is made you should expect it to potentially be broken, and unexpectedly and dramatically change its API and functionality. That said, I *do* have use of this thing for work, so I'm probably going to be working pretty dang hard on it, and hope to have a stable release by about November of 2020.
|
||||||
|
|
||||||
### Drivers
|
### Drivers
|
||||||
|
|
||||||
|
@ -19,22 +19,40 @@ A 1.0 release will not be made until the following drivers are available and sol
|
||||||
|
|
||||||
A 1.0 release will be made available once the following transforms are available and solidly tested across all drivers. These are basically what I see as the bare minimum for such a library to be useful.
|
A 1.0 release will be made available once the following transforms are available and solidly tested across all drivers. These are basically what I see as the bare minimum for such a library to be useful.
|
||||||
|
|
||||||
* rotate (in 90 degree increments)
|
* orientation
|
||||||
* mirror-h
|
* rotate (in 90 degree increments)
|
||||||
* mirror-v
|
* mirror-h
|
||||||
* max-width
|
* mirror-v
|
||||||
* max-height
|
* size
|
||||||
* fit (basically an alias for max-width and max-height)
|
* fit (basically an alias for max-width and max-height)
|
||||||
* cover (scale to cover a box, then crop excess)
|
* cover (scale to cover a box, then crop excess)
|
||||||
* crop (crop toward the center to a given size)
|
* crop (crop toward the center to a given size)
|
||||||
* cover-crop (convenience transform, combining cover and crop, useful for thumbnails)
|
* cover-crop (convenience transform, combining cover and crop, useful for thumbnails)
|
||||||
|
|
||||||
The following transforms are also on my mind as possibilities, but may or may not make it into 1.0:
|
More complex, and also lesser used effects/stages that may or may not make it into 1.0
|
||||||
|
|
||||||
* grayscale
|
* color effects
|
||||||
* colorize (needs to function consistently though)
|
* grayscale
|
||||||
* overlay (i.e. for watermarking)
|
* colorize
|
||||||
* blur
|
* content effects
|
||||||
* hue
|
* overlay
|
||||||
* saturation
|
* blur
|
||||||
* brightness
|
* hue
|
||||||
|
* saturation
|
||||||
|
* brightness
|
||||||
|
|
||||||
|
#### Order of operations
|
||||||
|
|
||||||
|
In the name of simplicity and ease of use, the effective order of operations will always be as reflected above:
|
||||||
|
|
||||||
|
1. Orientation
|
||||||
|
2. Resizing and cropping
|
||||||
|
3. Color effects
|
||||||
|
4. Content-changing effects
|
||||||
|
|
||||||
|
This is only the effective order of operations, because to improve performance the *actual* order of operations, if applicable, will be:
|
||||||
|
|
||||||
|
1. Resizing and cropping
|
||||||
|
2. Orientation
|
||||||
|
3. Color effects
|
||||||
|
4. Content-changing effects
|
||||||
|
|
|
@ -21,5 +21,14 @@
|
||||||
"require": {
|
"require": {
|
||||||
"php": ">=7.1",
|
"php": ">=7.1",
|
||||||
"ext-gd": "*"
|
"ext-gd": "*"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"atoum/atoum": "^3.4",
|
||||||
|
"atoum/stubs": "^2.6"
|
||||||
|
},
|
||||||
|
"autoload-dev": {
|
||||||
|
"psr-4": {
|
||||||
|
"ByJoby\\ImageTransform\\tests\\": "tests/"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
139
composer.lock
generated
139
composer.lock
generated
|
@ -4,17 +4,148 @@
|
||||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||||
"This file is @generated automatically"
|
"This file is @generated automatically"
|
||||||
],
|
],
|
||||||
"content-hash": "6eb3038135c5de665d7b86ae7ecb3427",
|
"content-hash": "5972ee7f683ce7e0b61ef2140ae044e9",
|
||||||
"packages": [],
|
"packages": [],
|
||||||
"packages-dev": [],
|
"packages-dev": [
|
||||||
|
{
|
||||||
|
"name": "atoum/atoum",
|
||||||
|
"version": "3.4.2",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/atoum/atoum.git",
|
||||||
|
"reference": "e90606b89e62c5c18c5d02596078edf55f35b3c3"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/atoum/atoum/zipball/e90606b89e62c5c18c5d02596078edf55f35b3c3",
|
||||||
|
"reference": "e90606b89e62c5c18c5d02596078edf55f35b3c3",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"ext-hash": "*",
|
||||||
|
"ext-json": "*",
|
||||||
|
"ext-tokenizer": "*",
|
||||||
|
"ext-xml": "*",
|
||||||
|
"php": "^5.6.0 || ^7.0.0 <7.5.0"
|
||||||
|
},
|
||||||
|
"replace": {
|
||||||
|
"mageekguy/atoum": "*"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"friendsofphp/php-cs-fixer": "^2"
|
||||||
|
},
|
||||||
|
"suggest": {
|
||||||
|
"atoum/stubs": "Provides IDE support (like autocompletion) for atoum",
|
||||||
|
"ext-mbstring": "Provides support for UTF-8 strings",
|
||||||
|
"ext-xdebug": "Provides code coverage report (>= 2.3)"
|
||||||
|
},
|
||||||
|
"bin": [
|
||||||
|
"bin/atoum"
|
||||||
|
],
|
||||||
|
"type": "library",
|
||||||
|
"extra": {
|
||||||
|
"branch-alias": {
|
||||||
|
"dev-master": "3.x-dev"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"classmap": [
|
||||||
|
"classes/"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"BSD-3-Clause"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Frédéric Hardy",
|
||||||
|
"email": "frederic.hardy@atoum.org",
|
||||||
|
"homepage": "http://blog.mageekbox.net"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "François Dussert",
|
||||||
|
"email": "francois.dussert@atoum.org"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Gérald Croes",
|
||||||
|
"email": "gerald.croes@atoum.org"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Julien Bianchi",
|
||||||
|
"email": "julien.bianchi@atoum.org"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Ludovic Fleury",
|
||||||
|
"email": "ludovic.fleury@atoum.org"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Simple modern and intuitive unit testing framework for PHP 5.3+",
|
||||||
|
"homepage": "http://www.atoum.org",
|
||||||
|
"keywords": [
|
||||||
|
"TDD",
|
||||||
|
"atoum",
|
||||||
|
"test",
|
||||||
|
"unit testing"
|
||||||
|
],
|
||||||
|
"time": "2020-03-04T10:29:09+00:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "atoum/stubs",
|
||||||
|
"version": "2.6.0",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/atoum/stubs.git",
|
||||||
|
"reference": "df8b73b0358de7283ecba91d8f4a9683f583993d"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/atoum/stubs/zipball/df8b73b0358de7283ecba91d8f4a9683f583993d",
|
||||||
|
"reference": "df8b73b0358de7283ecba91d8f4a9683f583993d",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"suggest": {
|
||||||
|
"atoum/atoum": "Include atoum in your projet dependencies"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"extra": {
|
||||||
|
"branch-alias": {
|
||||||
|
"dev-master": "2.x-dev"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"BSD-3-Clause"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Julien Bianchi",
|
||||||
|
"email": "julien.bianchi@atoum.org"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Ludovic Fleury",
|
||||||
|
"email": "ludovic.fleury@atoum.org"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Stubs for atoum, the simple modern and intuitive unit testing framework for PHP 5.3+",
|
||||||
|
"homepage": "http://www.atoum.org",
|
||||||
|
"keywords": [
|
||||||
|
"TDD",
|
||||||
|
"atoum",
|
||||||
|
"test",
|
||||||
|
"unit testing"
|
||||||
|
],
|
||||||
|
"time": "2018-01-29T22:41:37+00:00"
|
||||||
|
}
|
||||||
|
],
|
||||||
"aliases": [],
|
"aliases": [],
|
||||||
"minimum-stability": "stable",
|
"minimum-stability": "stable",
|
||||||
"stability-flags": [],
|
"stability-flags": [],
|
||||||
"prefer-stable": false,
|
"prefer-stable": false,
|
||||||
"prefer-lowest": false,
|
"prefer-lowest": false,
|
||||||
"platform": {
|
"platform": {
|
||||||
|
"php": ">=7.1",
|
||||||
"ext-gd": "*"
|
"ext-gd": "*"
|
||||||
},
|
},
|
||||||
"platform-dev": [],
|
"platform-dev": []
|
||||||
"plugin-api-version": "1.1.0"
|
|
||||||
}
|
}
|
||||||
|
|
2
debug.log
Normal file
2
debug.log
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
[1001/084735.845:ERROR:registration_protocol_win.cc(103)] CreateFile: The system cannot find the file specified. (0x2)
|
||||||
|
[1001/084736.163:ERROR:registration_protocol_win.cc(103)] CreateFile: The system cannot find the file specified. (0x2)
|
BIN
examples/example-portrait.jpg
Normal file
BIN
examples/example-portrait.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 920 KiB |
30
examples/usage.php
Normal file
30
examples/usage.php
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use ByJoby\ImageTransform\Drivers\ImagickCLIDriver;
|
||||||
|
use ByJoby\ImageTransform\Sizers\Cover;
|
||||||
|
use ByJoby\ImageTransform\Sizers\Crop;
|
||||||
|
use ByJoby\ImageTransform\Sizers\Fit;
|
||||||
|
use ByJoby\ImageTransform\Sizers\Original;
|
||||||
|
|
||||||
|
include __DIR__ . '/../vendor/autoload.php';
|
||||||
|
|
||||||
|
$driver = new ImagickCLIDriver();
|
||||||
|
// $sizer = new Fit(1000, 500);
|
||||||
|
// $sizer = new Original();
|
||||||
|
$sizer = new Crop(500,400);
|
||||||
|
|
||||||
|
$image = $driver->image(
|
||||||
|
'example-portrait.jpg',
|
||||||
|
$sizer
|
||||||
|
);
|
||||||
|
// $image->rotate();
|
||||||
|
|
||||||
|
var_dump(
|
||||||
|
'crop: width: '.$image->sizer()->cropToWidth(),
|
||||||
|
'crop: height: '.$image->sizer()->cropToHeight(),
|
||||||
|
'resize: width: '.$image->sizer()->resizeToWidth(),
|
||||||
|
'resize: height: '.$image->sizer()->resizeToHeight(),
|
||||||
|
'final: width: '.$image->width(),
|
||||||
|
'final: height: '.$image->height(),
|
||||||
|
$image
|
||||||
|
);
|
|
@ -2,9 +2,9 @@
|
||||||
/* image-transform | https://github.com/jobyone/image-transform | MIT License */
|
/* image-transform | https://github.com/jobyone/image-transform | MIT License */
|
||||||
namespace ByJoby\ImageTransform;
|
namespace ByJoby\ImageTransform;
|
||||||
|
|
||||||
|
use ByJoby\ImageTransform\Sizers\AbstractSizer;
|
||||||
|
|
||||||
interface DriverInterface
|
interface DriverInterface
|
||||||
{
|
{
|
||||||
public function source(string $source);
|
public function image(string $src, AbstractSizer $sizer): Image;
|
||||||
public function originalWidth(): int;
|
|
||||||
public function originalHeight(): int;
|
|
||||||
}
|
}
|
||||||
|
|
21
src/Drivers/AbstractCLIDriver.php
Normal file
21
src/Drivers/AbstractCLIDriver.php
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
<?php
|
||||||
|
/* image-transform | https://github.com/jobyone/image-transform | MIT License */
|
||||||
|
namespace ByJoby\ImageTransform\Drivers;
|
||||||
|
|
||||||
|
abstract class AbstractCLIDriver extends AbstractDriver
|
||||||
|
{
|
||||||
|
protected $executablePath = '';
|
||||||
|
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
if (!function_exists('exec')) {
|
||||||
|
throw new \Exception("CLI drivers can't be used with the current configuration because exec is disabled");
|
||||||
|
}
|
||||||
|
parent::__construct();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function executablePath($name)
|
||||||
|
{
|
||||||
|
return $this->executablePath.$name;
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,23 +3,64 @@
|
||||||
namespace ByJoby\ImageTransform\Drivers;
|
namespace ByJoby\ImageTransform\Drivers;
|
||||||
|
|
||||||
use ByJoby\ImageTransform\DriverInterface;
|
use ByJoby\ImageTransform\DriverInterface;
|
||||||
|
use ByJoby\ImageTransform\Image;
|
||||||
|
use ByJoby\ImageTransform\Sizers\AbstractSizer;
|
||||||
|
|
||||||
abstract class AbstractDriver implements DriverInterface
|
abstract class AbstractDriver implements DriverInterface
|
||||||
{
|
{
|
||||||
protected $source;
|
protected $tmpDir = null;
|
||||||
|
protected $chmod = 0775;
|
||||||
|
|
||||||
public function source(string $source)
|
public function __construct()
|
||||||
{
|
{
|
||||||
// set source
|
$this->__clone();
|
||||||
$this->source = $source;
|
}
|
||||||
// validate file
|
|
||||||
if (!is_file($this->source)) {
|
public function __clone()
|
||||||
throw new \Exception("Image file doesn't exist: " . htmlentities($this->source));
|
{
|
||||||
|
$this->setTempDir(sys_get_temp_dir() . '/byjoby_image-transform/' . uniqid("",true));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function image(string $src, AbstractSizer $sizer): Image
|
||||||
|
{
|
||||||
|
return new Image($src, $this, $sizer);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setTempDir(string $dir)
|
||||||
|
{
|
||||||
|
if (!$this->mkdir($dir)) {
|
||||||
|
throw new \Exception("Temp directory " . htmlentities($dir) . " doesn't exist or isn't writeable, and couldn't be created.");
|
||||||
}
|
}
|
||||||
if (!exif_imagetype($this->source)) {
|
$this->tmpDir = $dir;
|
||||||
throw new \Exception("Invalid image file: " . htmlentities($this->source));
|
}
|
||||||
|
|
||||||
|
protected function mkdir(string $dir)
|
||||||
|
{
|
||||||
|
// return true if dir exists and is writeable
|
||||||
|
if (is_dir($dir) && is_writeable($dir)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
// recursively ensure parent directory exists
|
||||||
|
$parent = dirname($dir);
|
||||||
|
$this->mkdir($parent);
|
||||||
|
// try to create this directory if it doesn't exist
|
||||||
|
if (is_dir($parent)) {
|
||||||
|
// check parent permissions
|
||||||
|
if (!is_writeable($parent)) {
|
||||||
|
chmod($parent, $this->chmod);
|
||||||
|
}
|
||||||
|
if (!is_writeable($parent)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// create this directory
|
||||||
|
if (!mkdir($dir)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
chmod($dir, $this->chmod);
|
||||||
|
return is_writeable($dir);
|
||||||
|
} else {
|
||||||
|
// parent doesn't exist, so recursive call failed
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
// get height/width
|
|
||||||
list($this->originalWidth, $this->originalHeight) = getimagesize($this->source);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,5 +9,5 @@ namespace ByJoby\ImageTransform\Drivers;
|
||||||
* require that you have CLI Imagick installed, and that your server allows
|
* require that you have CLI Imagick installed, and that your server allows
|
||||||
* PHP's exec() function to use it.
|
* PHP's exec() function to use it.
|
||||||
*/
|
*/
|
||||||
class ImagickCLIDriver extends AbstractDriver
|
class ImagickCLIDriver extends AbstractCLIDriver
|
||||||
{}
|
{}
|
||||||
|
|
|
@ -2,30 +2,104 @@
|
||||||
/* image-transform | https://github.com/jobyone/image-transform | MIT License */
|
/* image-transform | https://github.com/jobyone/image-transform | MIT License */
|
||||||
namespace ByJoby\ImageTransform;
|
namespace ByJoby\ImageTransform;
|
||||||
|
|
||||||
|
use ByJoby\ImageTransform\Sizers\AbstractSizer;
|
||||||
|
|
||||||
class Image
|
class Image
|
||||||
{
|
{
|
||||||
protected $src, $driver;
|
protected $source, $driver;
|
||||||
protected $transforms = [];
|
protected $originalWidth, $originalHeight;
|
||||||
|
protected $rotation = 0;
|
||||||
|
protected $flipH = false;
|
||||||
|
protected $flipV = false;
|
||||||
|
protected $sizer = null;
|
||||||
|
|
||||||
public function __construct(string $src, DriverInterface $driver)
|
public function __construct(string $source, DriverInterface $driver, AbstractSizer $sizer)
|
||||||
{
|
{
|
||||||
$this->src = $src;
|
$this->source($source);
|
||||||
|
$this->sizer($sizer);
|
||||||
$this->driver = clone $driver;
|
$this->driver = clone $driver;
|
||||||
$this->driver->source($src);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function transform(TransformInterface $transform)
|
public function source(string $source)
|
||||||
{
|
{
|
||||||
$this->transforms[] = $transform;
|
// set source
|
||||||
|
$this->source = realpath($source);
|
||||||
|
if (!$this->source) {
|
||||||
|
throw new \Exception("Source image not found: " . htmlentities($source));
|
||||||
|
}
|
||||||
|
// validate file
|
||||||
|
if (!is_file($this->source)) {
|
||||||
|
throw new \Exception("Image file doesn't exist: " . htmlentities($this->source));
|
||||||
|
}
|
||||||
|
if (!exif_imagetype($this->source)) {
|
||||||
|
throw new \Exception("Invalid image file: " . htmlentities($this->source));
|
||||||
|
}
|
||||||
|
// get height/width
|
||||||
|
list($this->originalWidth, $this->originalHeight) = getimagesize($this->source);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function sizer(AbstractSizer $sizer = null): AbstractSizer
|
||||||
|
{
|
||||||
|
if ($sizer) {
|
||||||
|
$this->sizer = clone $sizer;
|
||||||
|
$this->sizer->image($this);
|
||||||
|
}
|
||||||
|
return $this->sizer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function rotate(int $steps = 1)
|
||||||
|
{
|
||||||
|
$this->rotation = ($this->rotation + $steps) % 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function rotation(): int
|
||||||
|
{
|
||||||
|
return $this->rotation;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function flipH()
|
||||||
|
{
|
||||||
|
$this->flipH = !$this->flipH;
|
||||||
|
if ($this->flipH && $this->flipV) {
|
||||||
|
$this->flipH = $this->flipV = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function flipV()
|
||||||
|
{
|
||||||
|
$this->flipV = !$this->flipV;
|
||||||
|
if ($this->flipH && $this->flipV) {
|
||||||
|
$this->flipH = $this->flipV = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function width(): int
|
||||||
|
{
|
||||||
|
return $this->sizer->width();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function height(): int
|
||||||
|
{
|
||||||
|
return $this->sizer->height();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function ratio(): float
|
||||||
|
{
|
||||||
|
return $this->width() / $this->height();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function originalRatio(): float
|
||||||
|
{
|
||||||
|
return $this->originalWidth() / $this->originalHeight();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function originalWidth(): int
|
public function originalWidth(): int
|
||||||
{
|
{
|
||||||
return $this->driver->originalWidth();
|
return $this->originalWidth;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function originalHeight(): int
|
public function originalHeight(): int
|
||||||
{
|
{
|
||||||
return $this->driver->originalHeight();
|
return $this->originalHeight;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
53
src/Sizers/AbstractSizer.php
Normal file
53
src/Sizers/AbstractSizer.php
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
<?php
|
||||||
|
/* image-transform | https://github.com/jobyone/image-transform | MIT License */
|
||||||
|
namespace ByJoby\ImageTransform\Sizers;
|
||||||
|
|
||||||
|
use ByJoby\ImageTransform\Image;
|
||||||
|
|
||||||
|
abstract class AbstractSizer
|
||||||
|
{
|
||||||
|
protected $image;
|
||||||
|
|
||||||
|
abstract public function width(): int;
|
||||||
|
abstract public function height(): int;
|
||||||
|
abstract public function cropToWidth(): ?int;
|
||||||
|
abstract public function cropToHeight(): ?int;
|
||||||
|
|
||||||
|
public function resizeToWidth(): ?int
|
||||||
|
{
|
||||||
|
return $this->width();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function resizeToHeight(): ?int
|
||||||
|
{
|
||||||
|
return $this->height();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function originalWidth(): int
|
||||||
|
{
|
||||||
|
if ($this->image->rotation() % 2) {
|
||||||
|
return $this->image->originalHeight();
|
||||||
|
}else {
|
||||||
|
return $this->image->originalWidth();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function originalHeight(): int
|
||||||
|
{
|
||||||
|
if ($this->image->rotation() % 2) {
|
||||||
|
return $this->image->originalWidth();
|
||||||
|
}else {
|
||||||
|
return $this->image->originalHeight();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function originalRatio(): float
|
||||||
|
{
|
||||||
|
return $this->originalWidth()/$this->originalHeight();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function image(Image $image)
|
||||||
|
{
|
||||||
|
$this->image = $image;
|
||||||
|
}
|
||||||
|
}
|
54
src/Sizers/Cover.php
Normal file
54
src/Sizers/Cover.php
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
<?php
|
||||||
|
/* image-transform | https://github.com/jobyone/image-transform | MIT License */
|
||||||
|
namespace ByJoby\ImageTransform\Sizers;
|
||||||
|
|
||||||
|
class Cover extends AbstractSizer
|
||||||
|
{
|
||||||
|
protected $width, $height;
|
||||||
|
|
||||||
|
public function __construct(int $width, int $height)
|
||||||
|
{
|
||||||
|
$this->width = $width;
|
||||||
|
$this->height = $height;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function targetRatio(): float
|
||||||
|
{
|
||||||
|
return $this->width / $this->height;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function calculateSize(): array
|
||||||
|
{
|
||||||
|
if ($this->targetRatio() < $this->originalRatio()) {
|
||||||
|
$height = $this->height;
|
||||||
|
$width = round($height * $this->originalRatio());
|
||||||
|
} else {
|
||||||
|
$width = $this->width;
|
||||||
|
$height = round($width / $this->originalRatio());
|
||||||
|
}
|
||||||
|
return [
|
||||||
|
'height' => $height,
|
||||||
|
'width' => $width,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function width(): int
|
||||||
|
{
|
||||||
|
return $this->calculateSize()['width'];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function height(): int
|
||||||
|
{
|
||||||
|
return $this->calculateSize()['height'];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function cropToWidth(): ?int
|
||||||
|
{
|
||||||
|
return $this->width;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function cropToHeight(): ?int
|
||||||
|
{
|
||||||
|
return $this->height;
|
||||||
|
}
|
||||||
|
}
|
44
src/Sizers/Crop.php
Normal file
44
src/Sizers/Crop.php
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
<?php
|
||||||
|
/* image-transform | https://github.com/jobyone/image-transform | MIT License */
|
||||||
|
namespace ByJoby\ImageTransform\Sizers;
|
||||||
|
|
||||||
|
class Crop extends AbstractSizer
|
||||||
|
{
|
||||||
|
protected $width, $height;
|
||||||
|
|
||||||
|
public function __construct(int $width, int $height)
|
||||||
|
{
|
||||||
|
$this->width = $width;
|
||||||
|
$this->height = $height;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function width(): int
|
||||||
|
{
|
||||||
|
return $this->width;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function height(): int
|
||||||
|
{
|
||||||
|
return $this->height;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function resizeToHeight(): ?int
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function resizeToWidth(): ?int
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function cropToWidth(): ?int
|
||||||
|
{
|
||||||
|
return $this->width;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function cropToHeight(): ?int
|
||||||
|
{
|
||||||
|
return $this->height;
|
||||||
|
}
|
||||||
|
}
|
54
src/Sizers/Fit.php
Normal file
54
src/Sizers/Fit.php
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
<?php
|
||||||
|
/* image-transform | https://github.com/jobyone/image-transform | MIT License */
|
||||||
|
namespace ByJoby\ImageTransform\Sizers;
|
||||||
|
|
||||||
|
class Fit extends AbstractSizer
|
||||||
|
{
|
||||||
|
protected $width, $height;
|
||||||
|
|
||||||
|
public function __construct(int $width, int $height)
|
||||||
|
{
|
||||||
|
$this->width = $width;
|
||||||
|
$this->height = $height;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function cropToWidth(): ?int
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function cropToHeight(): ?int
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function targetRatio(): float
|
||||||
|
{
|
||||||
|
return $this->width / $this->height;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function calculateSize(): array
|
||||||
|
{
|
||||||
|
if ($this->targetRatio() > $this->originalRatio()) {
|
||||||
|
$height = $this->height;
|
||||||
|
$width = round($height * $this->originalRatio());
|
||||||
|
} else {
|
||||||
|
$width = $this->width;
|
||||||
|
$height = round($width / $this->originalRatio());
|
||||||
|
}
|
||||||
|
return [
|
||||||
|
'height' => $height,
|
||||||
|
'width' => $width,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function width(): int
|
||||||
|
{
|
||||||
|
return $this->calculateSize()['width'];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function height(): int
|
||||||
|
{
|
||||||
|
return $this->calculateSize()['height'];
|
||||||
|
}
|
||||||
|
}
|
36
src/Sizers/Original.php
Normal file
36
src/Sizers/Original.php
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
<?php
|
||||||
|
/* image-transform | https://github.com/jobyone/image-transform | MIT License */
|
||||||
|
namespace ByJoby\ImageTransform\Sizers;
|
||||||
|
|
||||||
|
class Original extends AbstractSizer
|
||||||
|
{
|
||||||
|
public function resizeToWidth(): ?int
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function resizeToHeight(): ?int
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function cropToWidth(): ?int
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function cropToHeight(): ?int
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function width(): int
|
||||||
|
{
|
||||||
|
return $this->originalWidth();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function height(): int
|
||||||
|
{
|
||||||
|
return $this->originalHeight();
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,52 +0,0 @@
|
||||||
<?php
|
|
||||||
/* image-transform | https://github.com/jobyone/image-transform | MIT License */
|
|
||||||
namespace ByJoby\ImageTransform;
|
|
||||||
|
|
||||||
interface TransformInterface
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Whether this transformer changes the contents of the image. Used when
|
|
||||||
* optimizing transformation order.
|
|
||||||
*/
|
|
||||||
const CHANGES_CONTENT = false;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Whether this transformer changes the size of the image. Used when
|
|
||||||
* optimizing transformation order.
|
|
||||||
*/
|
|
||||||
const CHANGES_SIZE = false;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Whether this transformer changes the colors of the image. Used when
|
|
||||||
* optimizing transformation order.
|
|
||||||
*/
|
|
||||||
const CHANGES_COLOR = false;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Whether or not applying this transform multiple times will always
|
|
||||||
* produce the same result. Used with optimizing transformation order.
|
|
||||||
*/
|
|
||||||
const TRANSFORM_STABLE = true;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Optionally return an array of other transforms that perform the
|
|
||||||
* operations necessary to perform this single transform.
|
|
||||||
*
|
|
||||||
* If this method returns anything, the Image object will add the
|
|
||||||
* Transformers returned here, and this object will be discarded.
|
|
||||||
*
|
|
||||||
* This allows new Transformers to be constructed by composing
|
|
||||||
* existing ones.
|
|
||||||
*
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public function chain(): array;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return whether or not this transformation will impact the given
|
|
||||||
* Image. Should return true if it's possible, as it will be
|
|
||||||
* skipped if it returns false.
|
|
||||||
* @return bool
|
|
||||||
*/
|
|
||||||
public function willTransform(Image $image): bool;
|
|
||||||
}
|
|
|
@ -1,19 +0,0 @@
|
||||||
<?php
|
|
||||||
/* image-transform | https://github.com/jobyone/image-transform | MIT License */
|
|
||||||
namespace ByJoby\ImageTransform\Drivers;
|
|
||||||
|
|
||||||
use ByJoby\ImageTransform\Image;
|
|
||||||
use ByJoby\ImageTransform\TransformInterface;
|
|
||||||
|
|
||||||
abstract class AbstractTransform implements TransformInterface
|
|
||||||
{
|
|
||||||
public function chain(): array
|
|
||||||
{
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
public function willTransform(Image $image): bool
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,26 +0,0 @@
|
||||||
<?php
|
|
||||||
/* image-transform | https://github.com/jobyone/image-transform | MIT License */
|
|
||||||
namespace ByJoby\ImageTransform\Drivers;
|
|
||||||
|
|
||||||
use ByJoby\ImageTransform\Image;
|
|
||||||
|
|
||||||
class MaxWidth extends AbstractTransform
|
|
||||||
{
|
|
||||||
const CHANGES_SIZE = true;
|
|
||||||
|
|
||||||
protected $size;
|
|
||||||
|
|
||||||
public function __construct(int $size)
|
|
||||||
{
|
|
||||||
$this->size = $size;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function willTransform(Image $image): bool
|
|
||||||
{
|
|
||||||
if ($image->originalWidth() <= $this->size) {
|
|
||||||
return false;
|
|
||||||
} else {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
10
tests/units/Sizers/Cover.php
Normal file
10
tests/units/Sizers/Cover.php
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
<?php
|
||||||
|
/* image-transform | https://github.com/jobyone/image-transform | MIT License */
|
||||||
|
namespace ByJoby\ImageTransform\tests\units\Sizers;
|
||||||
|
|
||||||
|
use atoum;
|
||||||
|
|
||||||
|
class Cover extends atoum
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in a new issue