Compare commits
2 commits
Author | SHA1 | Date | |
---|---|---|---|
ac0e9e1acb | |||
37ab60d81b |
30
.atoum.php
|
@ -1,30 +0,0 @@
|
|||
<?php
|
||||
use mageekguy\atoum\reports;
|
||||
|
||||
$runner
|
||||
->addTestsFromDirectory(__DIR__ . '/tests/units');
|
||||
|
||||
$runner->getScore()->getCoverage()->excludeDirectory(__DIR__ . '/tests/units/mock');
|
||||
|
||||
$travis = getenv('TRAVIS');
|
||||
if ($travis) {
|
||||
$script->addDefaultReport();
|
||||
$coverallsToken = getenv('COVERALLS_REPO_TOKEN');
|
||||
if ($coverallsToken) {
|
||||
$coverallsReport = new reports\asynchronous\coveralls('classes', $coverallsToken);
|
||||
$defaultFinder = $coverallsReport->getBranchFinder();
|
||||
$coverallsReport
|
||||
->setBranchFinder(function () use ($defaultFinder) {
|
||||
if (($branch = getenv('TRAVIS_BRANCH')) === false) {
|
||||
$branch = $defaultFinder();
|
||||
}
|
||||
return $branch;
|
||||
}
|
||||
)
|
||||
->setServiceName('travis-ci')
|
||||
->setServiceJobId(getenv('TRAVIS_JOB_ID'))
|
||||
->addDefaultWriter()
|
||||
;
|
||||
$runner->addReport($coverallsReport);
|
||||
}
|
||||
}
|
19
.devcontainer/Dockerfile
Normal file
|
@ -0,0 +1,19 @@
|
|||
FROM ubuntu:22.04
|
||||
|
||||
# prepare to install php 8.2
|
||||
RUN apt update && apt install -y software-properties-common
|
||||
RUN add-apt-repository ppa:ondrej/php
|
||||
RUN apt update
|
||||
|
||||
# install php 8.2 and other fundamental packages
|
||||
RUN export DEBIAN_FRONTEND=noninteractive; apt install -y --no-install-recommends php8.2 php-curl git openssl unzip
|
||||
|
||||
# install composer and its CA certificates
|
||||
COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer
|
||||
COPY --from=composer:latest /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ca-certificates.crt
|
||||
|
||||
# install the PHP extensions that basically all PHP projects should need
|
||||
RUN export DEBIAN_FRONTEND=noninteractive; apt install -y php8.2-opcache php-xdebug php-mbstring php-zip php-gd php-xml
|
||||
|
||||
# install extensions that are more project-specific
|
||||
RUN export DEBIAN_FRONTEND=noninteractive; apt install -y php-gmagick
|
37
.devcontainer/devcontainer.json
Normal file
|
@ -0,0 +1,37 @@
|
|||
{
|
||||
// build from dockerfile
|
||||
"build": {
|
||||
"dockerfile": "Dockerfile",
|
||||
"context": ".."
|
||||
},
|
||||
// specify run arguments
|
||||
"runArgs": [
|
||||
"--dns=8.8.8.8" // for some reason DNS doesn't work right unless we explicitly name a DNS server
|
||||
],
|
||||
// mount entire sites_v2 directory, so we can access global config and shared DB
|
||||
"workspaceMount": "source=${localWorkspaceFolder},target=/workspace/${localWorkspaceFolderBasename},type=bind,consistency=cached",
|
||||
"workspaceFolder": "/workspace/${localWorkspaceFolderBasename}",
|
||||
// specify extensions that we want
|
||||
"customizations": {
|
||||
"vscode": {
|
||||
"extensions": [
|
||||
"DEVSENSE.intelli-php-vscode",
|
||||
"DEVSENSE.phptools-vscode",
|
||||
"DEVSENSE.profiler-php-vscode",
|
||||
"DEVSENSE.composer-php-vscode",
|
||||
"SanderRonde.phpstan-vscode",
|
||||
"sibiraj-s.vscode-scss-formatter",
|
||||
"mrmlnc.vscode-scss",
|
||||
"Gruntfuggly.todo-tree",
|
||||
"redhat.vscode-yaml",
|
||||
"oliversturm.fix-json",
|
||||
"ecmel.vscode-html-css",
|
||||
"yzhang.markdown-all-in-one",
|
||||
"DavidAnson.vscode-markdownlint",
|
||||
"helixquar.randomeverything",
|
||||
"neilbrayfield.php-docblocker",
|
||||
"ms-vscode.test-adapter-converter"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
14
.github/workflows/phpstan.yaml
vendored
Normal file
|
@ -0,0 +1,14 @@
|
|||
name: PHPStan
|
||||
on: push
|
||||
jobs:
|
||||
phpstan:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: php-actions/composer@v6
|
||||
with:
|
||||
dev: yes
|
||||
- uses: php-actions/phpstan@v3
|
||||
with:
|
||||
path: src
|
||||
level: max
|
13
.github/workflows/phpunit.yaml
vendored
Normal file
|
@ -0,0 +1,13 @@
|
|||
name: PHPUnit
|
||||
on: push
|
||||
jobs:
|
||||
phpunit:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: php-actions/composer@v6
|
||||
with:
|
||||
dev: yes
|
||||
- uses: php-actions/phpunit@v3
|
||||
with:
|
||||
version: 10
|
3
.gitignore
vendored
|
@ -3,4 +3,5 @@ composer.phar
|
|||
composer.lock
|
||||
debug.log
|
||||
/examples/out/*
|
||||
!.gitkeep
|
||||
!.gitkeep
|
||||
.phpunit.result.cache
|
|
@ -1,9 +0,0 @@
|
|||
language: php
|
||||
php:
|
||||
- 7.1
|
||||
- 7.2
|
||||
- 7.3
|
||||
- 7.4
|
||||
install:
|
||||
- composer install
|
||||
script: composer test
|
23
README.md
|
@ -1,9 +1,6 @@
|
|||
# image-transform
|
||||
|
||||
[![Build Status](https://travis-ci.org/jobyone/image-transform.svg?branch=main)](https://travis-ci.org/jobyone/image-transform)
|
||||
[![Coverage Status](https://coveralls.io/repos/github/jobyone/image-transform/badge.svg?branch=main)](https://coveralls.io/github/jobyone/image-transform?branch=main)
|
||||
|
||||
A tightly-focused library for performing a very limited set of simple image transformations. This library's purpose is to eschew the standard kitchen sink approach to PHP image libraries in favor of high performance, wide driver support, and a dead simple API.
|
||||
A tightly-focused library for performing a very limited set of simple image transformations. This library's purpose is to eschew the standard kitchen sink approach to PHP image libraries in favor of high performance, wider driver support, and a dead simple API.
|
||||
|
||||
## Current state
|
||||
|
||||
|
@ -11,12 +8,11 @@ This library is under active development, and until a 1.0 release is made you sh
|
|||
|
||||
### Current progress
|
||||
|
||||
| Driver | Rotate | Mirror | Resize | Crop | Overlay | Grayscale | Colorize |
|
||||
| :--------- | :----: | :----: | :----: | :--: | :-----: | :-------: | :------: |
|
||||
| GD | X | X | X | X | | | |
|
||||
| Imagick | | | | | | | |
|
||||
| Gmagick | | | | | | | |
|
||||
| ImagickCLI | X | X | X | X | | | |
|
||||
| Driver | Rotate | Mirror | Resize | Crop |
|
||||
| :-------------- | :----: | :----: | :----: | :---: |
|
||||
| GDDriver | X | X | X | X |
|
||||
| MagickDriver | | | | |
|
||||
| MagickCliDriver | X | X | X | X |
|
||||
|
||||
## Roadmap
|
||||
|
||||
|
@ -25,9 +21,8 @@ This library is under active development, and until a 1.0 release is made you sh
|
|||
A 1.0 release will not be made until the following drivers are available and solidly tested:
|
||||
|
||||
* GD
|
||||
* Imagick
|
||||
* Gmagick
|
||||
* GmagickCLI
|
||||
* Magick (unified driver that will use either ImageMagick or Gmagick automatically depending on what is available)
|
||||
* MagickCliDriver (unified driver that can be configured to use either ImageMagick or Gmagick CLI tools)
|
||||
|
||||
### Transforms
|
||||
|
||||
|
@ -57,7 +52,7 @@ More complex, and also lesser used effects/stages that may or may not make it in
|
|||
|
||||
#### Order of operations
|
||||
|
||||
In the name of simplicity and ease of use, the effective order of operations will always be as reflected above:
|
||||
In the name of simplicity, ease of use, and performance, the effective order of operations will always and only be:
|
||||
|
||||
1. Orientation
|
||||
2. Resizing and cropping
|
||||
|
|
|
@ -15,23 +15,22 @@
|
|||
}
|
||||
},
|
||||
"suggest": {
|
||||
"ext-imagick": "to use the Imagick implementation",
|
||||
"ext-imagick": "to use the ImageMagick implementation",
|
||||
"ext-gmagick": "to use the Gmagick implementation"
|
||||
},
|
||||
"require": {
|
||||
"php": ">=7.1",
|
||||
"php": ">=8.1",
|
||||
"ext-gd": "*"
|
||||
},
|
||||
"require-dev": {
|
||||
"atoum/atoum": "^3.4",
|
||||
"atoum/stubs": "^2.6"
|
||||
"ext-gmagick": "*",
|
||||
"ext-gd": "*",
|
||||
"phpunit/phpunit": "^10.3",
|
||||
"phpstan/phpstan": "^1.10"
|
||||
},
|
||||
"autoload-dev": {
|
||||
"psr-4": {
|
||||
"ByJoby\\ImageTransform\\tests\\": "tests/"
|
||||
}
|
||||
},
|
||||
"scripts": {
|
||||
"test": "./vendor/bin/atoum -d tests"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
<?php
|
||||
|
||||
use ByJoby\ImageTransform\Drivers\ImagickCLIDriver;
|
||||
use ByJoby\ImageTransform\Drivers\MagickCliDriver;
|
||||
use ByJoby\ImageTransform\Sizers\Cover;
|
||||
|
||||
include __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
// first step is instantiate a Driver, in this case ImagickCLI
|
||||
$driver = new ImagickCLIDriver();
|
||||
$driver = new MagickCliDriver();
|
||||
|
||||
// instantiate an Image object using a source file and Sizer
|
||||
// in this example we're covering a 200x500 box
|
||||
|
|
4
phpstan.neon
Normal file
|
@ -0,0 +1,4 @@
|
|||
parameters:
|
||||
level: max
|
||||
paths:
|
||||
- src
|
31
phpunit.xml
Normal file
|
@ -0,0 +1,31 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<phpunit
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:noNamespaceSchemaLocation="vendor/phpunit/phpunit/phpunit.xsd"
|
||||
colors="true"
|
||||
executionOrder="random"
|
||||
failOnWarning="true"
|
||||
failOnRisky="true"
|
||||
failOnEmptyTestSuite="true"
|
||||
beStrictAboutOutputDuringTests="true"
|
||||
verbose="true"
|
||||
bootstrap="vendor/autoload.php">
|
||||
<php>
|
||||
<ini name="display_errors" value="On" />
|
||||
<ini name="error_reporting" value="-1" />
|
||||
<ini name="xdebug.mode" value="coverage" />
|
||||
</php>
|
||||
<testsuites>
|
||||
<testsuite name="Tests">
|
||||
<directory>tests/</directory>
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
<coverage>
|
||||
<include>
|
||||
<directory suffix=".php">src</directory>
|
||||
</include>
|
||||
<report>
|
||||
<html outputDirectory="coverage" lowUpperBound="50" highLowerBound="90" />
|
||||
</report>
|
||||
</coverage>
|
||||
</phpunit>
|
26
src/DefaultDriver.php
Normal file
|
@ -0,0 +1,26 @@
|
|||
<?php
|
||||
/* image-transform | https://github.com/jobyone/image-transform | MIT License */
|
||||
namespace ByJoby\ImageTransform;
|
||||
|
||||
use ByJoby\ImageTransform\Drivers\GDDriver;
|
||||
|
||||
/**
|
||||
* Stores a default driver to be used when a driver is not set for an Image.
|
||||
* Defaults to a GD driver.
|
||||
*/
|
||||
class DefaultDriver
|
||||
{
|
||||
/** @var DriverInterface|null */
|
||||
protected static $driver;
|
||||
|
||||
public static function get(): DriverInterface
|
||||
{
|
||||
return static::$driver
|
||||
?? static::$driver = new GDDriver();
|
||||
}
|
||||
|
||||
public static function set(DriverInterface $driver): void
|
||||
{
|
||||
static::$driver = $driver;
|
||||
}
|
||||
}
|
|
@ -6,6 +6,24 @@ use ByJoby\ImageTransform\Sizers\AbstractSizer;
|
|||
|
||||
interface DriverInterface
|
||||
{
|
||||
public function image(string $src, AbstractSizer $sizer): Image;
|
||||
/**
|
||||
* Save an image with its current settings. If a filename is specified the
|
||||
* image will be saved to it and null returned, otherwise the image will be
|
||||
* returned as a string.
|
||||
*
|
||||
* @param Image $image
|
||||
* @param string|null $filename
|
||||
* @return string|null
|
||||
*/
|
||||
public function save(Image $image, ?string $filename = null): ?string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the temp directory in which files should be created if necessary for
|
||||
* processing images. A directory in the system temp folder will be used by
|
||||
* default.
|
||||
*
|
||||
* @param string $dir
|
||||
* @return static
|
||||
*/
|
||||
public function setTempDir(string $dir): static;
|
||||
}
|
|
@ -1,13 +0,0 @@
|
|||
<?php
|
||||
/* image-transform | https://github.com/jobyone/image-transform | MIT License */
|
||||
namespace ByJoby\ImageTransform\Drivers;
|
||||
|
||||
abstract class AbstractCLIDriver extends AbstractDriver
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
if (!function_exists('exec')) {
|
||||
throw new \Exception("CLI drivers can't be used with the current configuration because exec is disabled");
|
||||
}
|
||||
}
|
||||
}
|
7
src/Drivers/AbstractCliDriver.php
Normal file
|
@ -0,0 +1,7 @@
|
|||
<?php
|
||||
/* image-transform | https://github.com/jobyone/image-transform | MIT License */
|
||||
namespace ByJoby\ImageTransform\Drivers;
|
||||
|
||||
abstract class AbstractCliDriver extends AbstractDriver
|
||||
{
|
||||
}
|
|
@ -5,41 +5,38 @@ namespace ByJoby\ImageTransform\Drivers;
|
|||
use ByJoby\ImageTransform\DriverInterface;
|
||||
use ByJoby\ImageTransform\Image;
|
||||
use ByJoby\ImageTransform\Sizers\AbstractSizer;
|
||||
use Exception;
|
||||
|
||||
abstract class AbstractDriver implements DriverInterface
|
||||
{
|
||||
/** @var string|null */
|
||||
protected $tempDir = null;
|
||||
protected $chmod = 0775;
|
||||
/** @var int */
|
||||
protected $chmod_dir = 0775;
|
||||
/** @var int */
|
||||
protected $chmod_file = 0665;
|
||||
|
||||
abstract protected function doSave(Image $image, string $filename);
|
||||
|
||||
public function __clone()
|
||||
{
|
||||
$this->tempDir = null;
|
||||
}
|
||||
|
||||
public function image(string $src, AbstractSizer $sizer): Image
|
||||
{
|
||||
return new Image($src, $this, $sizer);
|
||||
}
|
||||
abstract protected function doSave(Image $image, string $filename): void;
|
||||
|
||||
public function tempDir(): string
|
||||
{
|
||||
if (!$this->tempDir) {
|
||||
$this->setTempDir(sys_get_temp_dir() . '/byjoby_image-transform/' . uniqid("", true));
|
||||
}
|
||||
// @phpstan-ignore-next-line this is actually checked
|
||||
return $this->tempDir;
|
||||
}
|
||||
|
||||
protected function setTempDir(string $dir)
|
||||
public function setTempDir(string $dir): static
|
||||
{
|
||||
if (!$this->mkdir($dir)) {
|
||||
throw new \Exception("Temp directory " . htmlentities($dir) . " doesn't exist or isn't writeable, and couldn't be created.");
|
||||
}
|
||||
$this->tempDir = $dir;
|
||||
return $this;
|
||||
}
|
||||
|
||||
protected function mkdir(string $dir)
|
||||
protected function mkdir(string $dir): bool
|
||||
{
|
||||
// return true if dir exists and is writeable
|
||||
if (is_dir($dir) && is_writeable($dir)) {
|
||||
|
@ -52,7 +49,7 @@ abstract class AbstractDriver implements DriverInterface
|
|||
if (is_dir($parent)) {
|
||||
// check parent permissions
|
||||
if (!is_writeable($parent)) {
|
||||
chmod($parent, $this->chmod);
|
||||
chmod($parent, $this->chmod_dir);
|
||||
}
|
||||
if (!is_writeable($parent)) {
|
||||
return false;
|
||||
|
@ -61,7 +58,7 @@ abstract class AbstractDriver implements DriverInterface
|
|||
if (!mkdir($dir)) {
|
||||
return false;
|
||||
}
|
||||
chmod($dir, $this->chmod);
|
||||
chmod($dir, $this->chmod_dir);
|
||||
return is_writeable($dir);
|
||||
} else {
|
||||
// parent doesn't exist, so recursive call failed
|
||||
|
@ -82,12 +79,18 @@ abstract class AbstractDriver implements DriverInterface
|
|||
}
|
||||
touch($filename);
|
||||
}
|
||||
$this->doSave($image, realpath($filename));
|
||||
$filename = realpath($filename);
|
||||
if (!$filename) throw new Exception("Invalid filename or path");
|
||||
$this->doSave($image, $filename);
|
||||
chmod($filename, $this->chmod_file);
|
||||
return null;
|
||||
} else {
|
||||
$filename = $this->tempDir() . '/save.jpg';
|
||||
$filename = $this->tempDir() . '/' . uniqid() . '.jpg';
|
||||
$this->doSave($image, $filename);
|
||||
return file_get_contents($filename);
|
||||
/** @var string we can count on this being a string because we just wrote it */
|
||||
$output = file_get_contents($filename);
|
||||
unlink($filename);
|
||||
return $output;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -6,14 +6,20 @@ use ByJoby\ImageTransform\Image;
|
|||
|
||||
abstract class AbstractExtensionDriver extends AbstractDriver
|
||||
{
|
||||
// @phpstan-ignore-next-line we specify types in subclasses
|
||||
abstract protected function getImageObject(Image $image);
|
||||
// @phpstan-ignore-next-line we specify types in subclasses
|
||||
abstract protected function doResize($object, Image $image);
|
||||
// @phpstan-ignore-next-line we specify types in subclasses
|
||||
abstract protected function doCrop($object, Image $image);
|
||||
// @phpstan-ignore-next-line we specify types in subclasses
|
||||
abstract protected function doFlip($object, Image $image);
|
||||
// @phpstan-ignore-next-line we specify types in subclasses
|
||||
abstract protected function doRotation($object, Image $image);
|
||||
abstract protected function saveImageObject($object, string $filename);
|
||||
// @phpstan-ignore-next-line we specify types in subclasses
|
||||
abstract protected function saveImageObject($object, string $filename): void;
|
||||
|
||||
public function doSave(Image $image, string $filename)
|
||||
public function doSave(Image $image, string $filename): void
|
||||
{
|
||||
$object = $this->getImageObject($image);
|
||||
$object = $this->doRotation($object, $image);
|
||||
|
|
|
@ -3,10 +3,12 @@
|
|||
namespace ByJoby\ImageTransform\Drivers;
|
||||
|
||||
use ByJoby\ImageTransform\Image;
|
||||
use GdImage;
|
||||
|
||||
/**
|
||||
* This driver uses PHP's built-in GD libary. This is by far the slowest
|
||||
* driver, but support is basically universal.
|
||||
* This driver uses PHP's built-in GD libary. This is by far the slowest driver,
|
||||
* and its memory use is absolutely atrocious for large images, but support is
|
||||
* basically universal.
|
||||
*/
|
||||
class GDDriver extends AbstractExtensionDriver
|
||||
{
|
||||
|
@ -17,42 +19,62 @@ class GDDriver extends AbstractExtensionDriver
|
|||
}
|
||||
}
|
||||
|
||||
protected function getImageObject(Image $image)
|
||||
protected function getImageObject(Image $image): GdImage
|
||||
{
|
||||
$source = $image->source();
|
||||
$extension = strtolower(preg_replace('/^.+\./', '', $source));
|
||||
/** @var string */
|
||||
$extension = preg_replace('/^.+\./', '', $source);
|
||||
$extension = strtolower($extension);
|
||||
switch ($extension) {
|
||||
case 'bmp':
|
||||
// @phpstan-ignore-next-line this will throw an exception, which is good
|
||||
return imagecreatefrombmp($source);
|
||||
case 'gif':
|
||||
// @phpstan-ignore-next-line this will throw an exception, which is good
|
||||
return imagecreatefromgif($source);
|
||||
case 'jpg':
|
||||
// @phpstan-ignore-next-line this will throw an exception, which is good
|
||||
return imagecreatefromjpeg($source);
|
||||
case 'jpeg':
|
||||
// @phpstan-ignore-next-line this will throw an exception, which is good
|
||||
return imagecreatefromjpeg($source);
|
||||
case 'png':
|
||||
// @phpstan-ignore-next-line this will throw an exception, which is good
|
||||
return imagecreatefrompng($source);
|
||||
case 'wbmp':
|
||||
// @phpstan-ignore-next-line this will throw an exception, which is good
|
||||
return imagecreatefromwbmp($source);
|
||||
case 'webp':
|
||||
// @phpstan-ignore-next-line this will throw an exception, which is good
|
||||
return imagecreatefromwebp($source);
|
||||
case 'xbm':
|
||||
// @phpstan-ignore-next-line this will throw an exception, which is good
|
||||
return imagecreatefromxbm($source);
|
||||
default:
|
||||
throw new \Exception("Unsupported input type: " . htmlentities($source));
|
||||
}
|
||||
}
|
||||
|
||||
protected function doResize($object, Image $image)
|
||||
/**
|
||||
* @param GdImage $object
|
||||
* @param Image $image
|
||||
* @return GdImage
|
||||
*/
|
||||
protected function doResize($object, Image $image): GdImage
|
||||
{
|
||||
$sizer = $image->sizer();
|
||||
if ($sizer->resizeToHeight() && $sizer->resizeToWidth()) {
|
||||
// sizer is calling for a resize
|
||||
/** @var GdImage */
|
||||
$new = imagecreatetruecolor($sizer->resizeToWidth(), $sizer->resizeToHeight());
|
||||
imagecopyresampled(
|
||||
$new, $object,
|
||||
0, 0,//dst x/y
|
||||
0, 0,
|
||||
$new,
|
||||
$object,
|
||||
0,
|
||||
0,
|
||||
//dst x/y
|
||||
0,
|
||||
0,
|
||||
$sizer->resizeToWidth(), $sizer->resizeToHeight(),
|
||||
$sizer->originalWidth(), $sizer->originalHeight()
|
||||
);
|
||||
|
@ -63,17 +85,26 @@ class GDDriver extends AbstractExtensionDriver
|
|||
}
|
||||
}
|
||||
|
||||
protected function doCrop($object, Image $image)
|
||||
/**
|
||||
* @param GdImage $object
|
||||
* @param Image $image
|
||||
* @return GdImage
|
||||
*/
|
||||
protected function doCrop($object, Image $image): GdImage
|
||||
{
|
||||
$sizer = $image->sizer();
|
||||
if ($sizer->cropToHeight() && $sizer->cropToWidth()) {
|
||||
// sizer is calling for a crop
|
||||
/** @var GdImage */
|
||||
$new = imagecreatetruecolor($sizer->cropToWidth(), $sizer->cropToHeight());
|
||||
imagecopyresampled(
|
||||
$new, $object,
|
||||
($sizer->cropToWidth()-$sizer->resizeToWidth())/2,($sizer->cropToHeight()-$sizer->resizeToHeight())/2,
|
||||
0,0,
|
||||
$sizer->resizetoWidth(),$sizer->resizeToHeight(),$sizer->resizeToWidth(),$sizer->resizeToHeight()
|
||||
$new,
|
||||
$object,
|
||||
($sizer->cropToWidth() - $sizer->resizeToWidth()) / 2, ($sizer->cropToHeight() - $sizer->resizeToHeight()) / 2,
|
||||
0,
|
||||
0,
|
||||
// @phpstan-ignore-next-line these are definitely set
|
||||
$sizer->resizetoWidth(), $sizer->resizeToHeight(), $sizer->resizeToWidth(), $sizer->resizeToHeight()
|
||||
);
|
||||
return $new;
|
||||
} else {
|
||||
|
@ -82,47 +113,65 @@ class GDDriver extends AbstractExtensionDriver
|
|||
}
|
||||
}
|
||||
|
||||
protected function doFlip($object, Image $image)
|
||||
/**
|
||||
* @param GdImage $object
|
||||
* @param Image $image
|
||||
* @return GdImage
|
||||
*/
|
||||
protected function doFlip($object, Image $image): GdImage
|
||||
{
|
||||
if ($image->getFlipH()) {
|
||||
imageflip($object,IMG_FLIP_HORIZONTAL);
|
||||
imageflip($object, IMG_FLIP_HORIZONTAL);
|
||||
}
|
||||
if ($image->getFlipV()) {
|
||||
imageflip($object,IMG_FLIP_VERTICAL);
|
||||
imageflip($object, IMG_FLIP_VERTICAL);
|
||||
}
|
||||
return $object;
|
||||
}
|
||||
|
||||
protected function doRotation($object, Image $image)
|
||||
/**
|
||||
* @param GdImage $object
|
||||
* @param Image $image
|
||||
* @return GdImage
|
||||
*/
|
||||
protected function doRotation($object, Image $image): GdImage
|
||||
{
|
||||
if ($rotationAmount = 360 - $image->rotation() * 90) {
|
||||
// @phpstan-ignore-next-line
|
||||
return imagerotate($object, $rotationAmount, 0);
|
||||
}
|
||||
return $object;
|
||||
}
|
||||
|
||||
protected function saveImageObject($object, string $filename)
|
||||
/**
|
||||
* @param GdImage $object
|
||||
* @param string $filename
|
||||
* @return void
|
||||
*/
|
||||
protected function saveImageObject($object, string $filename): void
|
||||
{
|
||||
$extension = strtolower(preg_replace('/^.+\./', '', $filename));
|
||||
/** @var string */
|
||||
$extension = preg_replace('/^.+\./', '', $filename);
|
||||
$extension = strtolower($extension);
|
||||
switch ($extension) {
|
||||
case 'bmp':
|
||||
return imagebmp($object, $filename);
|
||||
imagebmp($object, $filename);
|
||||
case 'gif':
|
||||
return imagegif($object, $filename);
|
||||
imagegif($object, $filename);
|
||||
case 'jpg':
|
||||
return imagejpeg($object, $filename);
|
||||
imagejpeg($object, $filename);
|
||||
case 'jpeg':
|
||||
return imagejpeg($object, $filename);
|
||||
imagejpeg($object, $filename);
|
||||
case 'png':
|
||||
return imagepng($object, $filename);
|
||||
imagepng($object, $filename);
|
||||
case 'wbmp':
|
||||
return imagewbmp($object, $filename);
|
||||
imagewbmp($object, $filename);
|
||||
case 'webp':
|
||||
return imagewebp($object, $filename);
|
||||
imagewebp($object, $filename);
|
||||
case 'xbm':
|
||||
return imagexbm($object, $filename);
|
||||
imagexbm($object, $filename);
|
||||
default:
|
||||
throw new \Exception("Unsupported output type: " . htmlentities($filename));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -5,20 +5,16 @@ namespace ByJoby\ImageTransform\Drivers;
|
|||
use ByJoby\ImageTransform\Image;
|
||||
|
||||
/**
|
||||
* This driver uses exec() and command-line ImageMagick utilities to
|
||||
* transform images. It is likely approaching the limits of how fast this
|
||||
* library can possibly be. The downside is that it will only run if
|
||||
* you have exec() enabled, and your server allows it to execute the
|
||||
* ImageMagick binaries.
|
||||
* This driver uses exec() and command-line ImageMagick (or Gmagick) utilities
|
||||
* to transform images. It is likely approaching the limits of how fast this
|
||||
* library can possibly be. The downside is that it will only run if you have
|
||||
* exec() enabled, and your server allows it to execute the ImageMagick/Gmagick
|
||||
* binaries and use them to read and write image files.
|
||||
*/
|
||||
class ImagickCLIDriver extends AbstractCLIDriver
|
||||
class MagickCliDriver extends AbstractCliDriver
|
||||
{
|
||||
protected $mogrify_executable;
|
||||
|
||||
public function __construct($mogrify_executable = 'magick mogrify')
|
||||
public function __construct(protected string $mogrify_executable = 'magick mogrify')
|
||||
{
|
||||
parent::__construct();
|
||||
$this->mogrify_executable = $mogrify_executable;
|
||||
}
|
||||
|
||||
protected function mogrifyExecutable(): string
|
||||
|
@ -26,7 +22,7 @@ class ImagickCLIDriver extends AbstractCLIDriver
|
|||
return $this->mogrify_executable;
|
||||
}
|
||||
|
||||
protected function doSave(Image $image, string $filename)
|
||||
protected function doSave(Image $image, string $filename): void
|
||||
{
|
||||
// basics of command
|
||||
$command = [
|
144
src/Drivers/MagickDriver.php
Normal file
|
@ -0,0 +1,144 @@
|
|||
<?php
|
||||
/* image-transform | https://github.com/jobyone/image-transform | MIT License */
|
||||
namespace ByJoby\ImageTransform\Drivers;
|
||||
|
||||
use ByJoby\ImageTransform\Image;
|
||||
use Gmagick;
|
||||
use GmagickPixel;
|
||||
use Imagick;
|
||||
use ImagickPixel;
|
||||
|
||||
/**
|
||||
* This driver uses either ImageMagick or Gmagick, depending on its constructor
|
||||
* argument.
|
||||
*/
|
||||
class MagickDriver extends AbstractExtensionDriver
|
||||
{
|
||||
/**
|
||||
* By default this driver will use Imagick, but if you pass a true value it
|
||||
* will instead use Gmagick.
|
||||
*
|
||||
* @param boolean $use_gmagick
|
||||
*/
|
||||
public function __construct(protected bool $use_gmagick = false)
|
||||
{
|
||||
}
|
||||
|
||||
protected function getImageObject(Image $image): Gmagick|Imagick
|
||||
{
|
||||
if ($this->use_gmagick) return new Gmagick($image->source());
|
||||
else return new Imagick($image->source());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Gmagick|Imagick $object
|
||||
* @param Image $image
|
||||
* @return Gmagick|Imagick
|
||||
*/
|
||||
protected function doResize($object, Image $image): Gmagick|Imagick
|
||||
{
|
||||
$sizer = $image->sizer();
|
||||
if ($sizer->resizeToHeight() && $sizer->resizeToWidth()) {
|
||||
if ($object instanceof Gmagick) {
|
||||
$object->resizeimage(
|
||||
$sizer->resizeToWidth(),
|
||||
$sizer->resizeToHeight(),
|
||||
Gmagick::FILTER_LANCZOS,
|
||||
0
|
||||
);
|
||||
} else {
|
||||
$object->resizeImage(
|
||||
$sizer->resizeToWidth(),
|
||||
$sizer->resizeToHeight(),
|
||||
Imagick::FILTER_LANCZOS,
|
||||
0
|
||||
);
|
||||
}
|
||||
}
|
||||
return $object;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Gmagick|Imagick $object
|
||||
* @param Image $image
|
||||
* @return Gmagick|Imagick
|
||||
*/
|
||||
protected function doCrop($object, Image $image): Gmagick|Imagick
|
||||
{
|
||||
$sizer = $image->sizer();
|
||||
$height = $sizer->cropToHeight();
|
||||
$width = $sizer->cropToWidth();
|
||||
if ($height && $width) {
|
||||
$x = intval(($sizer->resizetoWidth() - $width) / 2);
|
||||
$y = intval(($sizer->resizetoHeight() - $height) / 2);
|
||||
if ($object instanceof Gmagick) {
|
||||
$object->cropimage(
|
||||
$width,
|
||||
$height,
|
||||
$x,
|
||||
$y
|
||||
);
|
||||
} else {
|
||||
$object->cropImage(
|
||||
$width,
|
||||
$height,
|
||||
$x,
|
||||
$y
|
||||
);
|
||||
}
|
||||
}
|
||||
return $object;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Gmagick|Imagick $object
|
||||
* @param Image $image
|
||||
* @return Gmagick|Imagick
|
||||
*/
|
||||
protected function doFlip($object, Image $image): Gmagick|Imagick
|
||||
{
|
||||
if ($image->getFlipH()) {
|
||||
if ($object instanceof Gmagick) $object->flipimage();
|
||||
else $object->flipImage();
|
||||
}
|
||||
if ($image->getFlipV()) {
|
||||
if ($object instanceof Gmagick) $object->flopimage();
|
||||
else $object->flopImage();
|
||||
}
|
||||
return $object;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Gmagick|Imagick $object
|
||||
* @param Image $image
|
||||
* @return Gmagick|Imagick
|
||||
*/
|
||||
protected function doRotation($object, Image $image): Gmagick|Imagick
|
||||
{
|
||||
if ($image->rotation()) {
|
||||
if ($object instanceof Gmagick) $object->rotateimage(new GmagickPixel("#000"), $image->rotation() * 90);
|
||||
else $object->rotateImage(new ImagickPixel("#000"), $image->rotation() * 90);
|
||||
}
|
||||
return $object;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Gmagick|Imagick $object
|
||||
* @param string $filename
|
||||
* @return void
|
||||
*/
|
||||
protected function saveImageObject($object, string $filename): void
|
||||
{
|
||||
/** @var string */
|
||||
$format = preg_replace('/^.+\./', '', $filename);
|
||||
$format = strtoupper($format);
|
||||
if ($format == 'JPG') $format = 'JPEG';
|
||||
if ($object instanceof Gmagick) {
|
||||
$object->setimageformat($format);
|
||||
$object->writeimage($filename, true);
|
||||
} else {
|
||||
$object->setImageFormat($format);
|
||||
$object->writeImage($filename);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -3,21 +3,31 @@
|
|||
namespace ByJoby\ImageTransform;
|
||||
|
||||
use ByJoby\ImageTransform\Sizers\AbstractSizer;
|
||||
use ByJoby\ImageTransform\Sizers\Original;
|
||||
|
||||
class Image
|
||||
{
|
||||
protected $source, $driver;
|
||||
protected $originalWidth, $originalHeight;
|
||||
/** @var string */
|
||||
protected $source;
|
||||
/** @var DriverInterface|null */
|
||||
protected $driver;
|
||||
/** @var int */
|
||||
protected $originalWidth;
|
||||
/** @var int */
|
||||
protected $originalHeight;
|
||||
/** @var int */
|
||||
protected $rotation = 0;
|
||||
/** @var boolean */
|
||||
protected $flipH = false;
|
||||
/** @var boolean */
|
||||
protected $flipV = false;
|
||||
/** @var AbstractSizer */
|
||||
protected $sizer = null;
|
||||
|
||||
public function __construct(string $source, DriverInterface $driver, AbstractSizer $sizer)
|
||||
public function __construct(string $source, AbstractSizer|null $sizer = null)
|
||||
{
|
||||
$this->setSource($source);
|
||||
$this->setSizer($sizer);
|
||||
$this->driver = clone $driver;
|
||||
$this->setSizer($sizer ?? new Original());
|
||||
}
|
||||
|
||||
public function source(): string
|
||||
|
@ -25,13 +35,14 @@ class Image
|
|||
return $this->source;
|
||||
}
|
||||
|
||||
public function setSource(string $source)
|
||||
public function setSource(string $source): static
|
||||
{
|
||||
// set source
|
||||
$this->source = realpath($source);
|
||||
if (!$this->source) {
|
||||
throw new \Exception("Source image not found: " . htmlentities($source));
|
||||
$source = realpath($source);
|
||||
if (!$source) {
|
||||
throw new \Exception("Source image not found");
|
||||
}
|
||||
$this->source = $source;
|
||||
// validate file
|
||||
if (!is_file($this->source)) {
|
||||
throw new \Exception("Image file doesn't exist: " . htmlentities($this->source));
|
||||
|
@ -40,7 +51,13 @@ class Image
|
|||
throw new \Exception("Invalid image file: " . htmlentities($this->source));
|
||||
}
|
||||
// get height/width
|
||||
list($this->originalWidth, $this->originalHeight) = getimagesize($this->source);
|
||||
$size = getimagesize($this->source);
|
||||
if (!$size) {
|
||||
throw new \Exception("Couldn't get image size: " . htmlentities($this->source));
|
||||
}
|
||||
list($this->originalWidth, $this->originalHeight) = $size;
|
||||
// return self
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function sizer(): AbstractSizer
|
||||
|
@ -48,15 +65,17 @@ class Image
|
|||
return $this->sizer;
|
||||
}
|
||||
|
||||
public function setSizer(AbstractSizer $sizer)
|
||||
public function setSizer(AbstractSizer $sizer): static
|
||||
{
|
||||
$this->sizer = clone $sizer;
|
||||
$this->sizer->image($this);
|
||||
$this->sizer->setImage($this);
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function rotate(int $steps = 1)
|
||||
public function rotate(int $steps = 1): static
|
||||
{
|
||||
$this->rotation = ($this->rotation + $steps) % 4;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function rotation(): int
|
||||
|
@ -64,22 +83,24 @@ class Image
|
|||
return $this->rotation;
|
||||
}
|
||||
|
||||
public function flipH()
|
||||
public function flipH(): static
|
||||
{
|
||||
$this->flipH = !$this->flipH;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function flipV()
|
||||
public function flipV(): static
|
||||
{
|
||||
$this->flipV = !$this->flipV;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getFlipH()
|
||||
public function getFlipH(): bool
|
||||
{
|
||||
return $this->flipH;
|
||||
}
|
||||
|
||||
public function getFlipV()
|
||||
public function getFlipV(): bool
|
||||
{
|
||||
return $this->flipV;
|
||||
}
|
||||
|
@ -114,8 +135,14 @@ class Image
|
|||
return $this->originalHeight;
|
||||
}
|
||||
|
||||
public function save(string $file)
|
||||
public function driver(): DriverInterface
|
||||
{
|
||||
$this->driver->save($this, $file);
|
||||
return $this->driver ?? DefaultDriver::get();
|
||||
}
|
||||
}
|
||||
|
||||
public function save(string $file): static
|
||||
{
|
||||
$this->driver()->save($this, $file);
|
||||
return $this;
|
||||
}
|
||||
}
|
|
@ -6,6 +6,7 @@ use ByJoby\ImageTransform\Image;
|
|||
|
||||
abstract class AbstractSizer
|
||||
{
|
||||
/** @var Image */
|
||||
protected $image;
|
||||
|
||||
abstract public function width(): int;
|
||||
|
@ -46,8 +47,9 @@ abstract class AbstractSizer
|
|||
return $this->originalWidth()/$this->originalHeight();
|
||||
}
|
||||
|
||||
public function image(Image $image)
|
||||
public function setImage(Image $image): static
|
||||
{
|
||||
$this->image = $image;
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ namespace ByJoby\ImageTransform\Sizers;
|
|||
|
||||
class Cover extends AbstractSizer
|
||||
{
|
||||
/** @var int */
|
||||
protected $width, $height;
|
||||
|
||||
public function __construct(int $width, int $height)
|
||||
|
@ -17,14 +18,17 @@ class Cover extends AbstractSizer
|
|||
return $this->width / $this->height;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array{height:int,width:int}
|
||||
*/
|
||||
protected function calculateSize(): array
|
||||
{
|
||||
if ($this->targetRatio() < $this->originalRatio()) {
|
||||
$height = $this->height;
|
||||
$width = round($height * $this->originalRatio());
|
||||
$width = intval(round($height * $this->originalRatio()));
|
||||
} else {
|
||||
$width = $this->width;
|
||||
$height = round($width / $this->originalRatio());
|
||||
$height = intval(round($width / $this->originalRatio()));
|
||||
}
|
||||
return [
|
||||
'height' => $height,
|
||||
|
@ -61,4 +65,4 @@ class Cover extends AbstractSizer
|
|||
{
|
||||
return $this->height;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -4,6 +4,7 @@ namespace ByJoby\ImageTransform\Sizers;
|
|||
|
||||
class Fit extends AbstractSizer
|
||||
{
|
||||
/** @var int */
|
||||
protected $width, $height;
|
||||
|
||||
public function __construct(int $width, int $height)
|
||||
|
@ -27,14 +28,17 @@ class Fit extends AbstractSizer
|
|||
return $this->width / $this->height;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array{height:int,width:int}
|
||||
*/
|
||||
protected function calculateSize(): array
|
||||
{
|
||||
if ($this->targetRatio() > $this->originalRatio()) {
|
||||
$height = $this->height;
|
||||
$width = round($height * $this->originalRatio());
|
||||
$width = intval(round($height * $this->originalRatio()));
|
||||
} else {
|
||||
$width = $this->width;
|
||||
$height = round($width / $this->originalRatio());
|
||||
$height = intval(round($width / $this->originalRatio()));
|
||||
}
|
||||
return [
|
||||
'height' => $height,
|
||||
|
|
|
@ -2,6 +2,9 @@
|
|||
/* image-transform | https://github.com/jobyone/image-transform | MIT License */
|
||||
namespace ByJoby\ImageTransform\Sizers;
|
||||
|
||||
/**
|
||||
* This sizer does no manipulations and keeps the image the size it originally was.
|
||||
*/
|
||||
class Original extends AbstractSizer
|
||||
{
|
||||
public function resizeToWidth(): ?int
|
||||
|
|
109
tests/Sizers/CoverTest.php
Normal file
|
@ -0,0 +1,109 @@
|
|||
<?php
|
||||
/* image-transform | https://github.com/jobyone/image-transform | MIT License */
|
||||
namespace ByJoby\ImageTransform\Sizers;
|
||||
|
||||
use ByJoby\ImageTransform\Image;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class CoverTest extends TestCase
|
||||
{
|
||||
public function testSquareImageSizedSquare(): void
|
||||
{
|
||||
// mock 200x200 image
|
||||
$image = $this->createMock(Image::class);
|
||||
$image->method("originalWidth")->willReturn(200);
|
||||
$image->method("originalHeight")->willReturn(200);
|
||||
// spin up a 50x50 sizer
|
||||
$sizer = new Cover(50, 50);
|
||||
$sizer->setImage($image);
|
||||
// resized to cover
|
||||
$this->assertEquals(50, $sizer->resizeToWidth());
|
||||
$this->assertEquals(50, $sizer->resizeToHeight());
|
||||
// cropped to size
|
||||
$this->assertEquals(50, $sizer->cropToWidth());
|
||||
$this->assertEquals(50, $sizer->cropToHeight());
|
||||
}
|
||||
|
||||
public function testSquareImageSizedLandscape(): void
|
||||
{
|
||||
// mock 200x200 image
|
||||
$image = $this->createMock(Image::class);
|
||||
$image->method("originalWidth")->willReturn(200);
|
||||
$image->method("originalHeight")->willReturn(200);
|
||||
// spin up a 100x50 sizer
|
||||
$sizer = new Cover(100, 50);
|
||||
$sizer->setImage($image);
|
||||
// resized to cover
|
||||
$this->assertEquals(100, $sizer->resizeToWidth());
|
||||
$this->assertEquals(100, $sizer->resizeToHeight());
|
||||
// cropped to size
|
||||
$this->assertEquals(100, $sizer->cropToWidth());
|
||||
$this->assertEquals(50, $sizer->cropToHeight());
|
||||
}
|
||||
public function testSquareImageSizedPortrait(): void
|
||||
{
|
||||
// mock 200x200 image
|
||||
$image = $this->createMock(Image::class);
|
||||
$image->method("originalWidth")->willReturn(200);
|
||||
$image->method("originalHeight")->willReturn(200);
|
||||
// spin up a 50x100 sizer
|
||||
$sizer = new Cover(50, 100);
|
||||
$sizer->setImage($image);
|
||||
// resized to cover
|
||||
$this->assertEquals(100, $sizer->resizeToWidth());
|
||||
$this->assertEquals(100, $sizer->resizeToHeight());
|
||||
// cropped to size
|
||||
$this->assertEquals(50, $sizer->cropToWidth());
|
||||
$this->assertEquals(100, $sizer->cropToHeight());
|
||||
}
|
||||
|
||||
public function testLandscapeImageSizedSquare(): void
|
||||
{
|
||||
// mock 200x100 image
|
||||
$image = $this->createMock(Image::class);
|
||||
$image->method("originalWidth")->willReturn(200);
|
||||
$image->method("originalHeight")->willReturn(100);
|
||||
// spin up a 50x50 sizer
|
||||
$sizer = new Cover(50, 50);
|
||||
$sizer->setImage($image);
|
||||
// resized to cover
|
||||
$this->assertEquals(100, $sizer->resizeToWidth());
|
||||
$this->assertEquals(50, $sizer->resizeToHeight());
|
||||
// cropped to size
|
||||
$this->assertEquals(50, $sizer->cropToWidth());
|
||||
$this->assertEquals(50, $sizer->cropToHeight());
|
||||
}
|
||||
|
||||
public function testLandscapeImageSizedLandscape(): void
|
||||
{
|
||||
// mock 200x100 image
|
||||
$image = $this->createMock(Image::class);
|
||||
$image->method("originalWidth")->willReturn(200);
|
||||
$image->method("originalHeight")->willReturn(100);
|
||||
// spin up a 100x50 sizer
|
||||
$sizer = new Cover(100, 50);
|
||||
$sizer->setImage($image);
|
||||
// resized to cover
|
||||
$this->assertEquals(100, $sizer->resizeToWidth());
|
||||
$this->assertEquals(50, $sizer->resizeToHeight());
|
||||
// cropped to size
|
||||
$this->assertEquals(100, $sizer->cropToWidth());
|
||||
$this->assertEquals(50, $sizer->cropToHeight());
|
||||
}
|
||||
public function testLandscapeImageSizedPortrait(): void
|
||||
{
|
||||
// mock 200x100 image
|
||||
$image = $this->createMock(Image::class);
|
||||
$image->method("originalWidth")->willReturn(200);
|
||||
$image->method("originalHeight")->willReturn(100);
|
||||
// spin up a 50x100 sizer
|
||||
$sizer = new Cover(50, 100);
|
||||
$sizer->setImage($image);
|
||||
// resized to cover
|
||||
$this->assertEquals(200, $sizer->resizeToWidth());
|
||||
$this->assertEquals(100, $sizer->resizeToHeight());
|
||||
// cropped to size
|
||||
$this->assertEquals(50, $sizer->cropToWidth());
|
||||
$this->assertEquals(100, $sizer->cropToHeight());
|
||||
}
|
||||
}
|
BIN
tests/input-100x200.png
Normal file
After Width: | Height: | Size: 774 B |
BIN
tests/input-200x100.png
Normal file
After Width: | Height: | Size: 679 B |
BIN
tests/input-200x200.png
Normal file
After Width: | Height: | Size: 834 B |
196
tests/test.svg
Normal file
|
@ -0,0 +1,196 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
width="200"
|
||||
height="200"
|
||||
viewBox="0 0 200 200"
|
||||
version="1.1"
|
||||
id="svg1"
|
||||
inkscape:version="1.3 (0e150ed6c4, 2023-07-21)"
|
||||
sodipodi:docname="test.svg"
|
||||
inkscape:export-filename="input-200x200.png.png"
|
||||
inkscape:export-xdpi="96"
|
||||
inkscape:export-ydpi="96"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<sodipodi:namedview
|
||||
id="namedview1"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#000000"
|
||||
borderopacity="0.25"
|
||||
inkscape:showpageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="false"
|
||||
inkscape:deskcolor="#d1d1d1"
|
||||
inkscape:document-units="px"
|
||||
showguides="true"
|
||||
inkscape:zoom="2.3267609"
|
||||
inkscape:cx="94.552044"
|
||||
inkscape:cy="68.980014"
|
||||
inkscape:window-width="1736"
|
||||
inkscape:window-height="1023"
|
||||
inkscape:window-x="156"
|
||||
inkscape:window-y="153"
|
||||
inkscape:window-maximized="0"
|
||||
inkscape:current-layer="layer1" />
|
||||
<defs
|
||||
id="defs1" />
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1">
|
||||
<g
|
||||
id="g3">
|
||||
<rect
|
||||
style="fill:#0000ff;stroke-width:0.188982"
|
||||
id="rect1"
|
||||
width="28.571428"
|
||||
height="25"
|
||||
x="0"
|
||||
y="-150"
|
||||
transform="scale(1,-1)" />
|
||||
<rect
|
||||
style="fill:#000000;stroke-width:0.188982"
|
||||
id="rect1-6"
|
||||
width="28.571428"
|
||||
height="25"
|
||||
x="28.571428"
|
||||
y="-150"
|
||||
transform="scale(1,-1)" />
|
||||
<rect
|
||||
style="fill:#ff00ff;stroke-width:0.188982"
|
||||
id="rect1-61"
|
||||
width="28.571428"
|
||||
height="25"
|
||||
x="57.142857"
|
||||
y="-150"
|
||||
transform="scale(1,-1)" />
|
||||
<rect
|
||||
style="fill:#000000;stroke-width:0.188982"
|
||||
id="rect1-6-8"
|
||||
width="28.571428"
|
||||
height="25"
|
||||
x="85.714287"
|
||||
y="-150"
|
||||
transform="scale(1,-1)" />
|
||||
<rect
|
||||
style="fill:#00ffff;stroke-width:0.188982"
|
||||
id="rect1-61-0"
|
||||
width="28.571428"
|
||||
height="25"
|
||||
x="114.28571"
|
||||
y="-150"
|
||||
transform="scale(1,-1)" />
|
||||
<rect
|
||||
style="fill:#000000;stroke-width:0.188982"
|
||||
id="rect1-6-8-2"
|
||||
width="28.571428"
|
||||
height="25"
|
||||
x="142.85715"
|
||||
y="-150"
|
||||
transform="scale(1,-1)" />
|
||||
<rect
|
||||
style="fill:#000080;stroke-width:0.447214"
|
||||
id="rect2"
|
||||
width="40"
|
||||
height="50"
|
||||
x="0"
|
||||
y="150" />
|
||||
<rect
|
||||
style="fill:#f2f2f2;stroke-width:0.632456"
|
||||
id="rect3"
|
||||
width="40"
|
||||
height="50"
|
||||
x="40"
|
||||
y="150" />
|
||||
<rect
|
||||
style="fill:#cccccc;stroke-width:0.188982"
|
||||
id="rect1-61-0-9"
|
||||
width="28.571428"
|
||||
height="25"
|
||||
x="171.42857"
|
||||
y="-150"
|
||||
transform="scale(1,-1)" />
|
||||
<rect
|
||||
style="fill:#cccccc;stroke-width:0.422577"
|
||||
id="rect1-1"
|
||||
width="28.571428"
|
||||
height="125"
|
||||
x="0"
|
||||
y="-125"
|
||||
transform="scale(1,-1)" />
|
||||
<rect
|
||||
style="fill:#808000;stroke-width:0.422577"
|
||||
id="rect1-6-2"
|
||||
width="28.571428"
|
||||
height="125"
|
||||
x="28.571428"
|
||||
y="-125"
|
||||
transform="scale(1,-1)" />
|
||||
<rect
|
||||
style="fill:#008080;stroke-width:0.422577"
|
||||
id="rect1-61-9"
|
||||
width="28.571428"
|
||||
height="125"
|
||||
x="57.142857"
|
||||
y="-125"
|
||||
transform="scale(1,-1)" />
|
||||
<rect
|
||||
style="fill:#008000;stroke-width:0.422577"
|
||||
id="rect1-6-8-3"
|
||||
width="28.571428"
|
||||
height="125"
|
||||
x="85.714287"
|
||||
y="-125"
|
||||
transform="scale(1,-1)" />
|
||||
<rect
|
||||
style="fill:#800080;stroke-width:0.422577"
|
||||
id="rect1-61-0-1"
|
||||
width="28.571428"
|
||||
height="125"
|
||||
x="114.28571"
|
||||
y="-125"
|
||||
transform="scale(1,-1)" />
|
||||
<rect
|
||||
style="fill:#800000;stroke-width:0.422577"
|
||||
id="rect1-6-8-2-9"
|
||||
width="28.571428"
|
||||
height="125"
|
||||
x="142.85715"
|
||||
y="-125"
|
||||
transform="scale(1,-1)" />
|
||||
<rect
|
||||
style="fill:#000080;stroke-width:0.422577"
|
||||
id="rect1-61-0-9-4"
|
||||
width="28.571428"
|
||||
height="125"
|
||||
x="171.42857"
|
||||
y="-125"
|
||||
transform="scale(1,-1)" />
|
||||
<rect
|
||||
style="fill:#800080;stroke-width:0.632456"
|
||||
id="rect3-5"
|
||||
width="40"
|
||||
height="50"
|
||||
x="80"
|
||||
y="150" />
|
||||
<rect
|
||||
style="fill:#4d4d4d;stroke-width:0.632456"
|
||||
id="rect3-5-2"
|
||||
width="40"
|
||||
height="50"
|
||||
x="120"
|
||||
y="150" />
|
||||
<rect
|
||||
style="fill:#1a1a1a;stroke-width:0.632456"
|
||||
id="rect3-5-2-7"
|
||||
width="40"
|
||||
height="50"
|
||||
x="160"
|
||||
y="150" />
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 5.1 KiB |
Before Width: | Height: | Size: 4.8 KiB |
Before Width: | Height: | Size: 4 KiB |
Before Width: | Height: | Size: 5.6 KiB |
|
@ -1,173 +0,0 @@
|
|||
<?php
|
||||
/* image-transform | https://github.com/jobyone/image-transform | MIT License */
|
||||
namespace ByJoby\ImageTransform\tests\units\Sizers;
|
||||
|
||||
use atoum;
|
||||
use ByJoby\ImageTransform\Sizers\Cover as SizerUnderTest;
|
||||
use ByJoby\ImageTransform\tests\units\mock\MockDriver;
|
||||
|
||||
class Cover extends atoum
|
||||
{
|
||||
public function testPortraitWhenImageIsTaller()
|
||||
{
|
||||
$this
|
||||
->given($image = $this->image(__DIR__.'/../100x200.jpg',100,150))
|
||||
->integer($image->width())->isEqualTo(100)
|
||||
->integer($image->height())->isEqualTo(150)
|
||||
->variable($image->sizer()->resizeToWidth())->isEqualTo(100)
|
||||
->variable($image->sizer()->resizeToHeight())->isEqualTo(200)
|
||||
->variable($image->sizer()->cropToWidth())->isEqualTo(100)
|
||||
->variable($image->sizer()->cropToHeight())->isEqualTo(150)
|
||||
->given($image->rotate())
|
||||
->integer($image->width())->isEqualTo(100)
|
||||
->integer($image->height())->isEqualTo(150)
|
||||
->variable($image->sizer()->resizeToWidth())->isEqualTo(300)
|
||||
->variable($image->sizer()->resizeToHeight())->isEqualTo(150)
|
||||
->variable($image->sizer()->cropToWidth())->isEqualTo(100)
|
||||
->variable($image->sizer()->cropToHeight())->isEqualTo(150)
|
||||
;
|
||||
}
|
||||
|
||||
public function testPortraitWhenImageIsShorter()
|
||||
{
|
||||
$this
|
||||
->given($image = $this->image(__DIR__.'/../100x200.jpg',50,300))
|
||||
->integer($image->width())->isEqualTo(50)
|
||||
->integer($image->height())->isEqualTo(300)
|
||||
->variable($image->sizer()->resizeToWidth())->isEqualTo(150)
|
||||
->variable($image->sizer()->resizeToHeight())->isEqualTo(300)
|
||||
->variable($image->sizer()->cropToWidth())->isEqualTo(50)
|
||||
->variable($image->sizer()->cropToHeight())->isEqualTo(300)
|
||||
->given($image->rotate())
|
||||
->integer($image->width())->isEqualTo(50)
|
||||
->integer($image->height())->isEqualTo(300)
|
||||
->variable($image->sizer()->resizeToWidth())->isEqualTo(600)
|
||||
->variable($image->sizer()->resizeToHeight())->isEqualTo(300)
|
||||
->variable($image->sizer()->cropToWidth())->isEqualTo(50)
|
||||
->variable($image->sizer()->cropToHeight())->isEqualTo(300)
|
||||
;
|
||||
}
|
||||
|
||||
public function testPortraitWithSquareImage()
|
||||
{
|
||||
$this
|
||||
->given($image = $this->image(__DIR__.'/../200x200.jpg',75,300))
|
||||
->integer($image->width())->isEqualTo(75)
|
||||
->integer($image->height())->isEqualTo(300)
|
||||
->variable($image->sizer()->resizeToWidth())->isEqualTo(300)
|
||||
->variable($image->sizer()->resizeToHeight())->isEqualTo(300)
|
||||
->variable($image->sizer()->cropToWidth())->isEqualTo(75)
|
||||
->variable($image->sizer()->cropToHeight())->isEqualTo(300)
|
||||
;
|
||||
}
|
||||
|
||||
public function testPortraitWithLandscapeImage()
|
||||
{
|
||||
$this
|
||||
->given($image = $this->image(__DIR__.'/../200x100.jpg',100,200))
|
||||
->integer($image->width())->isEqualTo(100)
|
||||
->integer($image->height())->isEqualTo(200)
|
||||
->variable($image->sizer()->resizeToWidth())->isEqualTo(400)
|
||||
->variable($image->sizer()->resizeToHeight())->isEqualTo(200)
|
||||
->variable($image->sizer()->cropToWidth())->isEqualTo(100)
|
||||
->variable($image->sizer()->cropToHeight())->isEqualTo(200)
|
||||
;
|
||||
}
|
||||
|
||||
public function testLandscapeWhenImageIsTaller()
|
||||
{
|
||||
$this
|
||||
->given($image = $this->image(__DIR__.'/../200x100.jpg',150,100))
|
||||
->integer($image->width())->isEqualTo(150)
|
||||
->integer($image->height())->isEqualTo(100)
|
||||
->variable($image->sizer()->resizeToWidth())->isEqualTo(200)
|
||||
->variable($image->sizer()->resizeToHeight())->isEqualTo(100)
|
||||
->variable($image->sizer()->cropToWidth())->isEqualTo(150)
|
||||
->variable($image->sizer()->cropToHeight())->isEqualTo(100)
|
||||
;
|
||||
}
|
||||
|
||||
public function testLandscapeWhenImageIsShorter()
|
||||
{
|
||||
$this
|
||||
->given($image = $this->image(__DIR__.'/../200x100.jpg',300,75))
|
||||
->integer($image->width())->isEqualTo(300)
|
||||
->integer($image->height())->isEqualTo(75)
|
||||
->variable($image->sizer()->resizeToWidth())->isEqualTo(300)
|
||||
->variable($image->sizer()->resizeToHeight())->isEqualTo(150)
|
||||
->variable($image->sizer()->cropToWidth())->isEqualTo(300)
|
||||
->variable($image->sizer()->cropToHeight())->isEqualTo(75)
|
||||
;
|
||||
}
|
||||
|
||||
public function testLandscapeWithSquareImage()
|
||||
{
|
||||
$this
|
||||
->given($image = $this->image(__DIR__.'/../200x200.jpg',300,75))
|
||||
->integer($image->width())->isEqualTo(300)
|
||||
->integer($image->height())->isEqualTo(75)
|
||||
->variable($image->sizer()->resizeToWidth())->isEqualTo(300)
|
||||
->variable($image->sizer()->resizeToHeight())->isEqualTo(300)
|
||||
->variable($image->sizer()->cropToWidth())->isEqualTo(300)
|
||||
->variable($image->sizer()->cropToHeight())->isEqualTo(75)
|
||||
;
|
||||
}
|
||||
|
||||
public function testLandscapeWithPortraitImage()
|
||||
{
|
||||
$this
|
||||
->given($image = $this->image(__DIR__.'/../100x200.jpg',200,100))
|
||||
->integer($image->width())->isEqualTo(200)
|
||||
->integer($image->height())->isEqualTo(100)
|
||||
->variable($image->sizer()->resizeToWidth())->isEqualTo(200)
|
||||
->variable($image->sizer()->resizeToHeight())->isEqualTo(400)
|
||||
->variable($image->sizer()->cropToWidth())->isEqualTo(200)
|
||||
->variable($image->sizer()->cropToHeight())->isEqualTo(100)
|
||||
;
|
||||
}
|
||||
|
||||
public function testWithSmallSquareImage()
|
||||
{
|
||||
$this
|
||||
->given($image = $this->image(__DIR__.'/../200x200.jpg',300,300))
|
||||
->integer($image->width())->isEqualTo(300)
|
||||
->integer($image->height())->isEqualTo(300)
|
||||
->variable($image->sizer()->resizeToWidth())->isEqualTo(300)
|
||||
->variable($image->sizer()->resizeToHeight())->isEqualTo(300)
|
||||
->variable($image->sizer()->cropToWidth())->isEqualTo(300)
|
||||
->variable($image->sizer()->cropToHeight())->isEqualTo(300)
|
||||
;
|
||||
}
|
||||
|
||||
public function testWithSmallLandscapeImage()
|
||||
{
|
||||
$this
|
||||
->given($image = $this->image(__DIR__.'/../200x100.jpg',300,300))
|
||||
->integer($image->width())->isEqualTo(300)
|
||||
->integer($image->height())->isEqualTo(300)
|
||||
->variable($image->sizer()->resizeToWidth())->isEqualTo(600)
|
||||
->variable($image->sizer()->resizeToHeight())->isEqualTo(300)
|
||||
->variable($image->sizer()->cropToWidth())->isEqualTo(300)
|
||||
->variable($image->sizer()->cropToHeight())->isEqualTo(300)
|
||||
;
|
||||
}
|
||||
|
||||
public function testWithSmallPortraitImage()
|
||||
{
|
||||
$this
|
||||
->given($image = $this->image(__DIR__.'/../100x200.jpg',300,300))
|
||||
->integer($image->width())->isEqualTo(300)
|
||||
->integer($image->height())->isEqualTo(300)
|
||||
->variable($image->sizer()->resizeToWidth())->isEqualTo(300)
|
||||
->variable($image->sizer()->resizeToHeight())->isEqualTo(600)
|
||||
->variable($image->sizer()->cropToWidth())->isEqualTo(300)
|
||||
->variable($image->sizer()->cropToHeight())->isEqualTo(300)
|
||||
;
|
||||
}
|
||||
|
||||
protected function image(string $path, int $width, int $height)
|
||||
{
|
||||
$driver = new MockDriver();
|
||||
return $driver->image($path, new SizerUnderTest($width, $height));
|
||||
}
|
||||
}
|
|
@ -1,173 +0,0 @@
|
|||
<?php
|
||||
/* image-transform | https://github.com/jobyone/image-transform | MIT License */
|
||||
namespace ByJoby\ImageTransform\tests\units\Sizers;
|
||||
|
||||
use atoum;
|
||||
use ByJoby\ImageTransform\Sizers\Fit as SizerUnderTest;
|
||||
use ByJoby\ImageTransform\tests\units\mock\MockDriver;
|
||||
|
||||
class Fit extends atoum
|
||||
{
|
||||
public function testPortraitWhenImageIsTaller()
|
||||
{
|
||||
$this
|
||||
->given($image = $this->image(__DIR__.'/../100x200.jpg',100,150))
|
||||
->integer($image->width())->isEqualTo(75)
|
||||
->integer($image->height())->isEqualTo(150)
|
||||
->variable($image->sizer()->resizeToWidth())->isEqualTo(75)
|
||||
->variable($image->sizer()->resizeToHeight())->isEqualTo(150)
|
||||
->variable($image->sizer()->cropToWidth())->isNull()
|
||||
->variable($image->sizer()->cropToHeight())->isNull()
|
||||
->given($image->rotate())
|
||||
->integer($image->width())->isEqualTo(100)
|
||||
->integer($image->height())->isEqualTo(50)
|
||||
->variable($image->sizer()->resizeToWidth())->isEqualTo(100)
|
||||
->variable($image->sizer()->resizeToHeight())->isEqualTo(50)
|
||||
->variable($image->sizer()->cropToWidth())->isNull()
|
||||
->variable($image->sizer()->cropToHeight())->isNull()
|
||||
;
|
||||
}
|
||||
|
||||
public function testPortraitWhenImageIsShorter()
|
||||
{
|
||||
$this
|
||||
->given($image = $this->image(__DIR__.'/../100x200.jpg',50,300))
|
||||
->integer($image->width())->isEqualTo(50)
|
||||
->integer($image->height())->isEqualTo(100)
|
||||
->variable($image->sizer()->resizeToWidth())->isEqualTo(50)
|
||||
->variable($image->sizer()->resizeToHeight())->isEqualTo(100)
|
||||
->variable($image->sizer()->cropToWidth())->isNull()
|
||||
->variable($image->sizer()->cropToHeight())->isNull()
|
||||
->given($image->rotate())
|
||||
->integer($image->width())->isEqualTo(50)
|
||||
->integer($image->height())->isEqualTo(25)
|
||||
->variable($image->sizer()->resizeToWidth())->isEqualTo(50)
|
||||
->variable($image->sizer()->resizeToHeight())->isEqualTo(25)
|
||||
->variable($image->sizer()->cropToWidth())->isNull()
|
||||
->variable($image->sizer()->cropToHeight())->isNull()
|
||||
;
|
||||
}
|
||||
|
||||
public function testPortraitWithSquareImage()
|
||||
{
|
||||
$this
|
||||
->given($image = $this->image(__DIR__.'/../200x200.jpg',75,300))
|
||||
->integer($image->width())->isEqualTo(75)
|
||||
->integer($image->height())->isEqualTo(75)
|
||||
->variable($image->sizer()->resizeToWidth())->isEqualTo(75)
|
||||
->variable($image->sizer()->resizeToHeight())->isEqualTo(75)
|
||||
->variable($image->sizer()->cropToWidth())->isNull()
|
||||
->variable($image->sizer()->cropToHeight())->isNull()
|
||||
;
|
||||
}
|
||||
|
||||
public function testPortraitWithLandscapeImage()
|
||||
{
|
||||
$this
|
||||
->given($image = $this->image(__DIR__.'/../200x100.jpg',100,200))
|
||||
->integer($image->width())->isEqualTo(100)
|
||||
->integer($image->height())->isEqualTo(50)
|
||||
->variable($image->sizer()->resizeToWidth())->isEqualTo(100)
|
||||
->variable($image->sizer()->resizeToHeight())->isEqualTo(50)
|
||||
->variable($image->sizer()->cropToWidth())->isNull()
|
||||
->variable($image->sizer()->cropToHeight())->isNull()
|
||||
;
|
||||
}
|
||||
|
||||
public function testLandscapeWhenImageIsTaller()
|
||||
{
|
||||
$this
|
||||
->given($image = $this->image(__DIR__.'/../200x100.jpg',150,100))
|
||||
->integer($image->width())->isEqualTo(150)
|
||||
->integer($image->height())->isEqualTo(75)
|
||||
->variable($image->sizer()->resizeToWidth())->isEqualTo(150)
|
||||
->variable($image->sizer()->resizeToHeight())->isEqualTo(75)
|
||||
->variable($image->sizer()->cropToWidth())->isNull()
|
||||
->variable($image->sizer()->cropToHeight())->isNull()
|
||||
;
|
||||
}
|
||||
|
||||
public function testLandscapeWhenImageIsShorter()
|
||||
{
|
||||
$this
|
||||
->given($image = $this->image(__DIR__.'/../200x100.jpg',300,75))
|
||||
->integer($image->width())->isEqualTo(150)
|
||||
->integer($image->height())->isEqualTo(75)
|
||||
->variable($image->sizer()->resizeToWidth())->isEqualTo(150)
|
||||
->variable($image->sizer()->resizeToHeight())->isEqualTo(75)
|
||||
->variable($image->sizer()->cropToWidth())->isNull()
|
||||
->variable($image->sizer()->cropToHeight())->isNull()
|
||||
;
|
||||
}
|
||||
|
||||
public function testLandscapeWithSquareImage()
|
||||
{
|
||||
$this
|
||||
->given($image = $this->image(__DIR__.'/../200x200.jpg',300,75))
|
||||
->integer($image->width())->isEqualTo(75)
|
||||
->integer($image->height())->isEqualTo(75)
|
||||
->variable($image->sizer()->resizeToWidth())->isEqualTo(75)
|
||||
->variable($image->sizer()->resizeToHeight())->isEqualTo(75)
|
||||
->variable($image->sizer()->cropToWidth())->isNull()
|
||||
->variable($image->sizer()->cropToHeight())->isNull()
|
||||
;
|
||||
}
|
||||
|
||||
public function testLandscapeWithPortraitImage()
|
||||
{
|
||||
$this
|
||||
->given($image = $this->image(__DIR__.'/../100x200.jpg',200,100))
|
||||
->integer($image->width())->isEqualTo(50)
|
||||
->integer($image->height())->isEqualTo(100)
|
||||
->variable($image->sizer()->resizeToWidth())->isEqualTo(50)
|
||||
->variable($image->sizer()->resizeToHeight())->isEqualTo(100)
|
||||
->variable($image->sizer()->cropToWidth())->isNull()
|
||||
->variable($image->sizer()->cropToHeight())->isNull()
|
||||
;
|
||||
}
|
||||
|
||||
public function testWithSmallSquareImage()
|
||||
{
|
||||
$this
|
||||
->given($image = $this->image(__DIR__.'/../200x200.jpg',300,300))
|
||||
->integer($image->width())->isEqualTo(300)
|
||||
->integer($image->height())->isEqualTo(300)
|
||||
->variable($image->sizer()->resizeToWidth())->isEqualTo(300)
|
||||
->variable($image->sizer()->resizeToHeight())->isEqualTo(300)
|
||||
->variable($image->sizer()->cropToWidth())->isNull()
|
||||
->variable($image->sizer()->cropToHeight())->isNull()
|
||||
;
|
||||
}
|
||||
|
||||
public function testWithSmallLandscapeImage()
|
||||
{
|
||||
$this
|
||||
->given($image = $this->image(__DIR__.'/../200x100.jpg',300,300))
|
||||
->integer($image->width())->isEqualTo(300)
|
||||
->integer($image->height())->isEqualTo(150)
|
||||
->variable($image->sizer()->resizeToWidth())->isEqualTo(300)
|
||||
->variable($image->sizer()->resizeToHeight())->isEqualTo(150)
|
||||
->variable($image->sizer()->cropToWidth())->isNull()
|
||||
->variable($image->sizer()->cropToHeight())->isNull()
|
||||
;
|
||||
}
|
||||
|
||||
public function testWithSmallPortraitImage()
|
||||
{
|
||||
$this
|
||||
->given($image = $this->image(__DIR__.'/../100x200.jpg',300,300))
|
||||
->integer($image->width())->isEqualTo(150)
|
||||
->integer($image->height())->isEqualTo(300)
|
||||
->variable($image->sizer()->resizeToWidth())->isEqualTo(150)
|
||||
->variable($image->sizer()->resizeToHeight())->isEqualTo(300)
|
||||
->variable($image->sizer()->cropToWidth())->isNull()
|
||||
->variable($image->sizer()->cropToHeight())->isNull()
|
||||
;
|
||||
}
|
||||
|
||||
protected function image(string $path, int $width, int $height)
|
||||
{
|
||||
$driver = new MockDriver();
|
||||
return $driver->image($path, new SizerUnderTest($width, $height));
|
||||
}
|
||||
}
|
|
@ -1,36 +0,0 @@
|
|||
<?php
|
||||
/* image-transform | https://github.com/jobyone/image-transform | MIT License */
|
||||
namespace ByJoby\ImageTransform\tests\units\Sizers;
|
||||
|
||||
use atoum;
|
||||
use ByJoby\ImageTransform\Sizers\Original as SizerUnderTest;
|
||||
use ByJoby\ImageTransform\tests\units\mock\MockDriver;
|
||||
|
||||
class Original extends atoum
|
||||
{
|
||||
public function testRotation()
|
||||
{
|
||||
$this
|
||||
->given($image = $this->image(__DIR__.'/../100x200.jpg'))
|
||||
->integer($image->width())->isEqualTo(100)
|
||||
->integer($image->height())->isEqualTo(200)
|
||||
->variable($image->sizer()->resizeToWidth())->isNull()
|
||||
->variable($image->sizer()->resizeToHeight())->isNull()
|
||||
->variable($image->sizer()->cropToWidth())->isNull()
|
||||
->variable($image->sizer()->cropToHeight())->isNull()
|
||||
->given($image->rotate())
|
||||
->integer($image->width())->isEqualTo(200)
|
||||
->integer($image->height())->isEqualTo(100)
|
||||
->variable($image->sizer()->resizeToWidth())->isNull()
|
||||
->variable($image->sizer()->resizeToHeight())->isNull()
|
||||
->variable($image->sizer()->cropToWidth())->isNull()
|
||||
->variable($image->sizer()->cropToHeight())->isNull()
|
||||
;
|
||||
}
|
||||
|
||||
protected function image(string $path)
|
||||
{
|
||||
$driver = new MockDriver();
|
||||
return $driver->image($path, new SizerUnderTest());
|
||||
}
|
||||
}
|
|
@ -1,14 +0,0 @@
|
|||
<?php
|
||||
/* image-transform | https://github.com/jobyone/image-transform | MIT License */
|
||||
namespace ByJoby\ImageTransform\tests\units\mock;
|
||||
|
||||
use ByJoby\ImageTransform\Drivers\AbstractDriver;
|
||||
use ByJoby\ImageTransform\Image;
|
||||
|
||||
class MockDriver extends AbstractDriver
|
||||
{
|
||||
protected function doSave(Image $image, string $filename)
|
||||
{
|
||||
//does nothing
|
||||
}
|
||||
}
|