mirror of
https://github.com/Intervention/image.git
synced 2025-08-31 09:31:53 +02:00
Resizing
This commit is contained in:
@@ -65,11 +65,6 @@ abstract class AbstractImage
|
||||
return new Size($this->width(), $this->height());
|
||||
}
|
||||
|
||||
public function getResizer(): Resizer
|
||||
{
|
||||
return new Resizer($this->getSize());
|
||||
}
|
||||
|
||||
public function isAnimated(): bool
|
||||
{
|
||||
return $this->getFrames()->count() > 1;
|
||||
@@ -132,46 +127,66 @@ abstract class AbstractImage
|
||||
|
||||
public function resize(...$arguments): ImageInterface
|
||||
{
|
||||
$size = $this->getResizer()->setTargetSizeByArray($arguments)->resize();
|
||||
$crop = $this->getSize();
|
||||
$resize = Resizer::make()
|
||||
->setTargetSizeByArray($arguments)
|
||||
->resize($crop);
|
||||
|
||||
return $this->modify(
|
||||
$this->resolveDriverClass('Modifiers\ResizeModifier', $size)
|
||||
$this->resolveDriverClass('Modifiers\CropResizeModifier', $crop, $resize)
|
||||
);
|
||||
}
|
||||
|
||||
public function resizeDown(...$arguments): ImageInterface
|
||||
{
|
||||
$size = $this->getResizer()->setTargetSizeByArray($arguments)->resizeDown();
|
||||
$crop = $this->getSize();
|
||||
$resize = Resizer::make()
|
||||
->setTargetSizeByArray($arguments)
|
||||
->resizeDown($crop);
|
||||
|
||||
return $this->modify(
|
||||
$this->resolveDriverClass('Modifiers\ResizeModifier', $size)
|
||||
$this->resolveDriverClass('Modifiers\CropResizeModifier', $crop, $resize)
|
||||
);
|
||||
}
|
||||
|
||||
public function scale(...$arguments): ImageInterface
|
||||
{
|
||||
$size = $this->getResizer()->setTargetSizeByArray($arguments)->scale();
|
||||
$crop = $this->getSize();
|
||||
$resize = Resizer::make()
|
||||
->setTargetSizeByArray($arguments)
|
||||
->scale($crop);
|
||||
|
||||
return $this->modify(
|
||||
$this->resolveDriverClass('Modifiers\ResizeModifier', $size)
|
||||
$this->resolveDriverClass('Modifiers\CropResizeModifier', $crop, $resize)
|
||||
);
|
||||
}
|
||||
|
||||
public function scaleDown(...$arguments): ImageInterface
|
||||
{
|
||||
$size = $this->getResizer()->setTargetSizeByArray($arguments)->scaleDown();
|
||||
$crop = $this->getSize();
|
||||
$resize = Resizer::make()
|
||||
->setTargetSizeByArray($arguments)
|
||||
->scaleDown($crop);
|
||||
|
||||
return $this->modify(
|
||||
$this->resolveDriverClass('Modifiers\ResizeModifier', $size)
|
||||
$this->resolveDriverClass('Modifiers\CropResizeModifier', $size)
|
||||
);
|
||||
}
|
||||
|
||||
public function fit(int $width, int $height, string $position = 'center'): ImageInterface
|
||||
{
|
||||
$size = new Size($width, $height);
|
||||
// crop
|
||||
$crop = Resizer::make()
|
||||
->toSize($this->getSize())
|
||||
->contain(new Size($width, $height));
|
||||
$crop = Resizer::make()
|
||||
->toSize($crop)
|
||||
->crop($this->getSize(), $position);
|
||||
|
||||
$resize = new Size($width, $height);
|
||||
|
||||
return $this->modify(
|
||||
$this->resolveDriverClass('Modifiers\FitModifier', $size, $position)
|
||||
$this->resolveDriverClass('Modifiers\CropResizeModifier', $crop, $resize, $position)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -180,7 +195,7 @@ abstract class AbstractImage
|
||||
$size = new Size($width, $height);
|
||||
|
||||
return $this->modify(
|
||||
$this->resolveDriverClass('Modifiers\FitDownModifier', $size, $position)
|
||||
$this->resolveDriverClass('Modifiers\CropResizeModifier', $crop, $resize, $position)
|
||||
);
|
||||
}
|
||||
|
||||
|
@@ -2,22 +2,29 @@
|
||||
|
||||
namespace Intervention\Image\Drivers\Gd\Modifiers;
|
||||
|
||||
use Intervention\Image\Drivers\Abstract\Modifiers\AbstractResizeModifier;
|
||||
use Intervention\Image\Interfaces\FrameInterface;
|
||||
use Intervention\Image\Interfaces\ImageInterface;
|
||||
use Intervention\Image\Interfaces\ModifierInterface;
|
||||
use Intervention\Image\Interfaces\SizeInterface;
|
||||
use Intervention\Image\Traits\CanResizeGeometrically;
|
||||
|
||||
class ResizeModifier extends AbstractResizeModifier implements ModifierInterface
|
||||
class CropResizeModifier implements ModifierInterface
|
||||
{
|
||||
protected $crop;
|
||||
protected $resize;
|
||||
protected $position;
|
||||
|
||||
public function __construct(SizeInterface $crop, SizeInterface $resize, string $position = 'top-left')
|
||||
{
|
||||
$this->crop = $crop;
|
||||
$this->resize = $resize;
|
||||
$this->position = $position;
|
||||
}
|
||||
|
||||
public function apply(ImageInterface $image): ImageInterface
|
||||
{
|
||||
$crop = $this->getCropSize($image);
|
||||
$resize = $this->getResizeSize($image);
|
||||
|
||||
foreach ($image as $frame) {
|
||||
$this->modify($frame, $crop, $resize);
|
||||
$this->modify($frame, $this->crop, $this->resize);
|
||||
}
|
||||
|
||||
return $image;
|
@@ -6,16 +6,8 @@ use Intervention\Image\Interfaces\ImageInterface;
|
||||
use Intervention\Image\Interfaces\ModifierInterface;
|
||||
use Intervention\Image\Interfaces\SizeInterface;
|
||||
|
||||
class FitModifier extends ResizeModifier implements ModifierInterface
|
||||
class FitModifier extends CropResizeModifier implements ModifierInterface
|
||||
{
|
||||
protected $position;
|
||||
|
||||
public function __construct(SizeInterface $target, string $position = 'top-left')
|
||||
{
|
||||
$this->target = $target;
|
||||
$this->position = $position;
|
||||
}
|
||||
|
||||
protected function getCropSize(ImageInterface $image): SizeInterface
|
||||
{
|
||||
$imagesize = $image->getSize();
|
||||
|
@@ -67,6 +67,17 @@ class Resizer
|
||||
$this->target = new Size(0, 0);
|
||||
}
|
||||
|
||||
public static function make(callable $callback = null): self
|
||||
{
|
||||
$resizer = new self();
|
||||
|
||||
if (is_callable($callback)) {
|
||||
$callback($resizer);
|
||||
}
|
||||
|
||||
return $resizer;
|
||||
}
|
||||
|
||||
protected function hasTargetWidth(): bool
|
||||
{
|
||||
return $this->target->getWidth() > 0;
|
||||
@@ -245,4 +256,65 @@ class Resizer
|
||||
|
||||
return $resized;
|
||||
}
|
||||
|
||||
/**
|
||||
* Scale given size to cover target size
|
||||
*
|
||||
* @param SizeInterface $size Size to be resized
|
||||
* @return SizeInterface
|
||||
*/
|
||||
public function cover(SizeInterface $size): SizeInterface
|
||||
{
|
||||
$resized = clone $size;
|
||||
|
||||
// auto height
|
||||
$resized->setWidth($this->target->getWidth());
|
||||
$resized->setHeight($this->getProportionalHeight($size));
|
||||
|
||||
if ($resized->fitsInto($this->target)) {
|
||||
// auto width
|
||||
$resized->setWidth($this->getProportionalWidth($size));
|
||||
$resized->setHeight($this->target->getHeight());
|
||||
}
|
||||
|
||||
return $resized;
|
||||
}
|
||||
|
||||
/**
|
||||
* Scale given size to contain target size
|
||||
*
|
||||
* @param SizeInterface $size Size to be resized
|
||||
* @return SizeInterface
|
||||
*/
|
||||
public function contain(SizeInterface $size): SizeInterface
|
||||
{
|
||||
$resized = clone $size;
|
||||
|
||||
// auto height
|
||||
$resized->setWidth($this->target->getWidth());
|
||||
$resized->setHeight($this->getProportionalHeight($size));
|
||||
|
||||
if (!$resized->fitsInto($this->target)) {
|
||||
// auto width
|
||||
$resized->setWidth($this->getProportionalWidth($size));
|
||||
$resized->setHeight($this->target->getHeight());
|
||||
}
|
||||
|
||||
return $resized;
|
||||
}
|
||||
|
||||
/**
|
||||
* Crop target size out of given size at given position (i.e. move the pivot point)
|
||||
*
|
||||
* @param SizeInterface $size
|
||||
* @param string $position
|
||||
* @return SizeInterface
|
||||
*/
|
||||
public function crop(SizeInterface $size, string $position = 'top-left'): SizeInterface
|
||||
{
|
||||
return $this->resize($size)->alignPivotTo(
|
||||
$size->alignPivot($position),
|
||||
$position
|
||||
);
|
||||
}
|
||||
}
|
||||
|
28
tests/Drivers/Gd/Modifiers/FitModifierTest.php
Normal file
28
tests/Drivers/Gd/Modifiers/FitModifierTest.php
Normal file
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
namespace Intervention\Image\Tests\Drivers\Gd\Modifiers;
|
||||
|
||||
use Intervention\Image\Drivers\Gd\Image;
|
||||
use Intervention\Image\Drivers\Gd\Modifiers\FitModifier;
|
||||
use Intervention\Image\Geometry\Size;
|
||||
use Intervention\Image\Tests\TestCase;
|
||||
use Intervention\Image\Tests\Traits\CanCreateGdTestImage;
|
||||
|
||||
class FitModifierTest extends TestCase
|
||||
{
|
||||
use CanCreateGdTestImage;
|
||||
|
||||
public function testColorChange(): void
|
||||
{
|
||||
$image = $this->createTestImage('test.jpg');
|
||||
$image->resize(800, 600);
|
||||
$this->assertEquals(800, $image->width());
|
||||
$this->assertEquals(600, $image->height());
|
||||
|
||||
$image->fit(100, 100);
|
||||
|
||||
// $image->modify(new FitModifier(new Size(100, 100)));
|
||||
// $this->assertEquals(30, $image->width());
|
||||
// $this->assertEquals(20, $image->height());
|
||||
}
|
||||
}
|
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace Intervention\Image\Tests\Geometry;
|
||||
|
||||
use Intervention\Image\Geometry\Point;
|
||||
use Intervention\Image\Geometry\Resizer;
|
||||
use Intervention\Image\Geometry\Size;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
@@ -367,4 +368,84 @@ class ResizerTest extends TestCase
|
||||
$this->assertEquals(13, $result->getWidth());
|
||||
$this->assertEquals(10, $result->getHeight());
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider coverDataProvider
|
||||
*/
|
||||
public function testCover($origin, $target, $result): void
|
||||
{
|
||||
$resizer = new Resizer();
|
||||
$resizer->toSize($target);
|
||||
$resized = $resizer->cover($origin);
|
||||
$this->assertEquals($result->getWidth(), $resized->getWidth());
|
||||
$this->assertEquals($result->getHeight(), $resized->getHeight());
|
||||
}
|
||||
|
||||
public function coverDataProvider(): array
|
||||
{
|
||||
return [
|
||||
[new Size(800, 600), new Size(100, 100), new Size(133, 100)],
|
||||
[new Size(800, 600), new Size(200, 100), new Size(200, 150)],
|
||||
[new Size(800, 600), new Size(100, 200), new Size(267, 200)],
|
||||
[new Size(800, 600), new Size(2000, 10), new Size(2000, 1500)],
|
||||
[new Size(800, 600), new Size(10, 2000), new Size(2667, 2000)],
|
||||
[new Size(800, 600), new Size(800, 600), new Size(800, 600)],
|
||||
[new Size(400, 300), new Size(120, 120), new Size(160, 120)],
|
||||
[new Size(600, 800), new Size(100, 100), new Size(100, 133)],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider containDataProvider
|
||||
*/
|
||||
public function testContain($origin, $target, $result): void
|
||||
{
|
||||
$resizer = new Resizer();
|
||||
$resizer->toSize($target);
|
||||
$resized = $resizer->contain($origin);
|
||||
$this->assertEquals($result->getWidth(), $resized->getWidth());
|
||||
$this->assertEquals($result->getHeight(), $resized->getHeight());
|
||||
}
|
||||
|
||||
public function containDataProvider(): array
|
||||
{
|
||||
return [
|
||||
[new Size(800, 600), new Size(100, 100), new Size(100, 75)],
|
||||
[new Size(800, 600), new Size(200, 100), new Size(133, 100)],
|
||||
[new Size(800, 600), new Size(100, 200), new Size(100, 75)],
|
||||
[new Size(800, 600), new Size(2000, 10), new Size(13, 10)],
|
||||
[new Size(800, 600), new Size(10, 2000), new Size(10, 8)],
|
||||
[new Size(800, 600), new Size(800, 600), new Size(800, 600)],
|
||||
[new Size(400, 300), new Size(120, 120), new Size(120, 90)],
|
||||
[new Size(600, 800), new Size(100, 100), new Size(75, 100)],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider cropDataProvider
|
||||
*/
|
||||
public function testCrop($origin, $target, $position, $result): void
|
||||
{
|
||||
$resizer = new Resizer();
|
||||
$resizer->toSize($target);
|
||||
$resized = $resizer->crop($origin, $position);
|
||||
$this->assertEquals($result->getWidth(), $resized->getWidth());
|
||||
$this->assertEquals($result->getHeight(), $resized->getHeight());
|
||||
$this->assertEquals($result->getPivot()->getX(), $resized->getPivot()->getX());
|
||||
$this->assertEquals($result->getPivot()->getY(), $resized->getPivot()->getY());
|
||||
}
|
||||
|
||||
public function cropDataProvider(): array
|
||||
{
|
||||
return [
|
||||
[new Size(800, 600), new Size(100, 100), 'center', new Size(100, 100, new Point(350, 250))],
|
||||
[new Size(800, 600), new Size(200, 100), 'center', new Size(200, 100, new Point(300, 250))],
|
||||
[new Size(800, 600), new Size(100, 200), 'center', new Size(100, 200, new Point(350, 200))],
|
||||
[new Size(800, 600), new Size(2000, 10), 'center', new Size(2000, 10, new Point(-600, 295))],
|
||||
[new Size(800, 600), new Size(10, 2000), 'center', new Size(10, 2000, new Point(395, -700))],
|
||||
[new Size(800, 600), new Size(800, 600), 'center', new Size(800, 600, new Point(0, 0))],
|
||||
[new Size(400, 300), new Size(120, 120), 'center', new Size(120, 120, new Point(140, 90))],
|
||||
[new Size(600, 800), new Size(100, 100), 'center', new Size(100, 100, new Point(250, 350))],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user