mirror of
https://github.com/Intervention/image.git
synced 2025-09-02 02:12:37 +02:00
Add ResizeCanvasModifiers
This commit is contained in:
85
src/Drivers/Gd/Modifiers/ResizeCanvasModifier.php
Normal file
85
src/Drivers/Gd/Modifiers/ResizeCanvasModifier.php
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Intervention\Image\Drivers\Gd\Modifiers;
|
||||||
|
|
||||||
|
use Intervention\Image\Colors\Rgb\Channels\Blue;
|
||||||
|
use Intervention\Image\Colors\Rgb\Channels\Green;
|
||||||
|
use Intervention\Image\Colors\Rgb\Channels\Red;
|
||||||
|
use Intervention\Image\Drivers\DriverSpecializedModifier;
|
||||||
|
use Intervention\Image\Interfaces\ColorInterface;
|
||||||
|
use Intervention\Image\Interfaces\FrameInterface;
|
||||||
|
use Intervention\Image\Interfaces\ImageInterface;
|
||||||
|
use Intervention\Image\Interfaces\SizeInterface;
|
||||||
|
use Intervention\Image\Modifiers\FillModifier;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @method SizeInterface cropSize(ImageInterface $image)
|
||||||
|
* @property mixed $background
|
||||||
|
*/
|
||||||
|
class ResizeCanvasModifier extends DriverSpecializedModifier
|
||||||
|
{
|
||||||
|
public function apply(ImageInterface $image): ImageInterface
|
||||||
|
{
|
||||||
|
$resize = $this->cropSize($image);
|
||||||
|
$background = $this->driver()->handleInput($this->background);
|
||||||
|
|
||||||
|
foreach ($image as $frame) {
|
||||||
|
$this->modify($frame, $resize, $background);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $image;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function modify(
|
||||||
|
FrameInterface $frame,
|
||||||
|
SizeInterface $resize,
|
||||||
|
ColorInterface $background,
|
||||||
|
): void {
|
||||||
|
// create new gd image
|
||||||
|
$modified = $this->driver()->createImage(
|
||||||
|
$resize->width(),
|
||||||
|
$resize->height()
|
||||||
|
)->modify(
|
||||||
|
new FillModifier($background)
|
||||||
|
)->core()->native();
|
||||||
|
|
||||||
|
// make image area transparent to keep transparency
|
||||||
|
// even if background-color is set
|
||||||
|
$transparent = imagecolorallocatealpha(
|
||||||
|
$modified,
|
||||||
|
$background->channel(Red::class)->value(),
|
||||||
|
$background->channel(Green::class)->value(),
|
||||||
|
$background->channel(Blue::class)->value(),
|
||||||
|
127,
|
||||||
|
);
|
||||||
|
|
||||||
|
imagealphablending($modified, false); // do not blend / just overwrite
|
||||||
|
imagecolortransparent($modified, $transparent);
|
||||||
|
imagefilledrectangle(
|
||||||
|
$modified,
|
||||||
|
$resize->pivot()->x() * -1,
|
||||||
|
$resize->pivot()->y() * -1,
|
||||||
|
$resize->pivot()->x() * -1 + $frame->size()->width() - 1,
|
||||||
|
$resize->pivot()->y() * -1 + $frame->size()->height() - 1,
|
||||||
|
$transparent
|
||||||
|
);
|
||||||
|
|
||||||
|
// copy image from original with blending alpha
|
||||||
|
imagealphablending($modified, true);
|
||||||
|
imagecopyresampled(
|
||||||
|
$modified,
|
||||||
|
$frame->native(),
|
||||||
|
$resize->pivot()->x() * -1,
|
||||||
|
$resize->pivot()->y() * -1,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
$frame->size()->width(),
|
||||||
|
$frame->size()->height(),
|
||||||
|
$frame->size()->width(),
|
||||||
|
$frame->size()->height()
|
||||||
|
);
|
||||||
|
|
||||||
|
// set new content as recource
|
||||||
|
$frame->setNative($modified);
|
||||||
|
}
|
||||||
|
}
|
87
src/Drivers/Imagick/Modifiers/ResizeCanvasModifier.php
Normal file
87
src/Drivers/Imagick/Modifiers/ResizeCanvasModifier.php
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Intervention\Image\Drivers\Imagick\Modifiers;
|
||||||
|
|
||||||
|
use ImagickDraw;
|
||||||
|
use Intervention\Image\Drivers\DriverSpecializedModifier;
|
||||||
|
use Intervention\Image\Interfaces\ImageInterface;
|
||||||
|
use Intervention\Image\Interfaces\SizeInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @method SizeInterface cropSize(ImageInterface $image)
|
||||||
|
* @property mixed $background
|
||||||
|
*/
|
||||||
|
class ResizeCanvasModifier extends DriverSpecializedModifier
|
||||||
|
{
|
||||||
|
public function apply(ImageInterface $image): ImageInterface
|
||||||
|
{
|
||||||
|
$size = $image->size();
|
||||||
|
$resize = $this->cropSize($image);
|
||||||
|
|
||||||
|
$background = $this->driver()->colorProcessor($image->colorspace())->colorToNative(
|
||||||
|
$this->driver()->handleInput($this->background)
|
||||||
|
);
|
||||||
|
|
||||||
|
foreach ($image as $frame) {
|
||||||
|
$frame->native()->extentImage(
|
||||||
|
$resize->width(),
|
||||||
|
$resize->height(),
|
||||||
|
$resize->pivot()->x(),
|
||||||
|
$resize->pivot()->y()
|
||||||
|
);
|
||||||
|
|
||||||
|
if ($resize->width() > $size->width()) {
|
||||||
|
// fill new emerged background
|
||||||
|
$draw = new ImagickDraw();
|
||||||
|
$draw->setFillColor($background);
|
||||||
|
|
||||||
|
$delta = abs($resize->pivot()->x());
|
||||||
|
|
||||||
|
if ($delta > 0) {
|
||||||
|
$draw->rectangle(
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
$delta - 1,
|
||||||
|
$resize->height()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
$draw->rectangle(
|
||||||
|
$size->width() + $delta,
|
||||||
|
0,
|
||||||
|
$resize->width(),
|
||||||
|
$resize->height()
|
||||||
|
);
|
||||||
|
$frame->native()->drawImage($draw);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($resize->height() > $size->height()) {
|
||||||
|
// fill new emerged background
|
||||||
|
$draw = new ImagickDraw();
|
||||||
|
$draw->setFillColor($background);
|
||||||
|
|
||||||
|
$delta = abs($resize->pivot()->y());
|
||||||
|
|
||||||
|
if ($delta > 0) {
|
||||||
|
$draw->rectangle(
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
$resize->width(),
|
||||||
|
$delta - 1
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
$draw->rectangle(
|
||||||
|
0,
|
||||||
|
$size->height() + $delta,
|
||||||
|
$resize->width(),
|
||||||
|
$resize->height()
|
||||||
|
);
|
||||||
|
|
||||||
|
$frame->native()->drawImage($draw);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $image;
|
||||||
|
}
|
||||||
|
}
|
@@ -64,6 +64,7 @@ use Intervention\Image\Modifiers\PlaceModifier;
|
|||||||
use Intervention\Image\Modifiers\ProfileModifier;
|
use Intervention\Image\Modifiers\ProfileModifier;
|
||||||
use Intervention\Image\Modifiers\ProfileRemovalModifier;
|
use Intervention\Image\Modifiers\ProfileRemovalModifier;
|
||||||
use Intervention\Image\Modifiers\RemoveAnimationModifier;
|
use Intervention\Image\Modifiers\RemoveAnimationModifier;
|
||||||
|
use Intervention\Image\Modifiers\ResizeCanvasModifier;
|
||||||
use Intervention\Image\Modifiers\ResizeDownModifier;
|
use Intervention\Image\Modifiers\ResizeDownModifier;
|
||||||
use Intervention\Image\Modifiers\ResizeModifier;
|
use Intervention\Image\Modifiers\ResizeModifier;
|
||||||
use Intervention\Image\Modifiers\ResolutionModifier;
|
use Intervention\Image\Modifiers\ResolutionModifier;
|
||||||
@@ -521,6 +522,20 @@ final class Image implements ImageInterface, Countable
|
|||||||
return $this->modify(new CoverDownModifier($width, $height, $position));
|
return $this->modify(new CoverDownModifier($width, $height, $position));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*
|
||||||
|
* @see ImageInterface::resizeCanvas()
|
||||||
|
*/
|
||||||
|
public function resizeCanvas(
|
||||||
|
int $width,
|
||||||
|
int $height,
|
||||||
|
mixed $background = 'ffffff',
|
||||||
|
string $position = 'center'
|
||||||
|
): ImageInterface {
|
||||||
|
return $this->modify(new ResizeCanvasModifier($width, $height, $background, $position));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritdoc}
|
* {@inheritdoc}
|
||||||
*
|
*
|
||||||
|
@@ -347,6 +347,25 @@ interface ImageInterface extends IteratorAggregate, Countable
|
|||||||
*/
|
*/
|
||||||
public function coverDown(int $width, int $height, string $position = 'center'): ImageInterface;
|
public function coverDown(int $width, int $height, string $position = 'center'): ImageInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resize the boundaries of the current image to given width and height.
|
||||||
|
* An anchor position can be defined to determine from what point of the
|
||||||
|
* image the resizing is going to happen. A background color can be passed
|
||||||
|
* to define the color of the new emerging areas.
|
||||||
|
*
|
||||||
|
* @param int $width
|
||||||
|
* @param int $height
|
||||||
|
* @param string $position
|
||||||
|
* @param mixed $background
|
||||||
|
* @return ImageInterface
|
||||||
|
*/
|
||||||
|
public function resizeCanvas(
|
||||||
|
int $width,
|
||||||
|
int $height,
|
||||||
|
mixed $background = 'ffffff',
|
||||||
|
string $position = 'center'
|
||||||
|
): ImageInterface;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Padded resizing means that the original image is scaled until it fits the
|
* Padded resizing means that the original image is scaled until it fits the
|
||||||
* defined target size with unchanged aspect ratio. The original image is
|
* defined target size with unchanged aspect ratio. The original image is
|
||||||
|
24
src/Modifiers/ResizeCanvasModifier.php
Normal file
24
src/Modifiers/ResizeCanvasModifier.php
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Intervention\Image\Modifiers;
|
||||||
|
|
||||||
|
use Intervention\Image\Geometry\Rectangle;
|
||||||
|
use Intervention\Image\Interfaces\ImageInterface;
|
||||||
|
use Intervention\Image\Interfaces\SizeInterface;
|
||||||
|
|
||||||
|
class ResizeCanvasModifier extends AbstractModifier
|
||||||
|
{
|
||||||
|
public function __construct(
|
||||||
|
public int $width,
|
||||||
|
public int $height,
|
||||||
|
public mixed $background = 'ffffff',
|
||||||
|
public string $position = 'center'
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public function cropSize(ImageInterface $image): SizeInterface
|
||||||
|
{
|
||||||
|
return (new Rectangle($this->width, $this->height))
|
||||||
|
->alignPivotTo($image->size(), $this->position);
|
||||||
|
}
|
||||||
|
}
|
31
tests/Drivers/Gd/Modifiers/ResizeCanvasModifierTest.php
Normal file
31
tests/Drivers/Gd/Modifiers/ResizeCanvasModifierTest.php
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Intervention\Image\Tests\Drivers\Gd\Modifiers;
|
||||||
|
|
||||||
|
use Intervention\Image\Modifiers\ResizeCanvasModifier;
|
||||||
|
use Intervention\Image\Tests\TestCase;
|
||||||
|
use Intervention\Image\Tests\Traits\CanCreateGdTestImage;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @requires extension gd
|
||||||
|
* @covers \Intervention\Image\Modifiers\ResizeCanvasModifier
|
||||||
|
*/
|
||||||
|
class ResizeCanvasModifierTest extends TestCase
|
||||||
|
{
|
||||||
|
use CanCreateGdTestImage;
|
||||||
|
|
||||||
|
public function testModify(): void
|
||||||
|
{
|
||||||
|
$image = $this->createTestImage('tile.png');
|
||||||
|
$this->assertEquals(16, $image->width());
|
||||||
|
$this->assertEquals(16, $image->height());
|
||||||
|
$image->modify(new ResizeCanvasModifier(18, 18, 'ff0', 'center'));
|
||||||
|
$this->assertEquals(18, $image->width());
|
||||||
|
$this->assertEquals(18, $image->height());
|
||||||
|
$this->assertColor(255, 255, 0, 255, $image->pickColor(0, 0));
|
||||||
|
$this->assertColor(180, 224, 0, 255, $image->pickColor(1, 1));
|
||||||
|
$this->assertColor(180, 224, 0, 255, $image->pickColor(2, 2));
|
||||||
|
$this->assertColor(255, 255, 0, 255, $image->pickColor(17, 17));
|
||||||
|
$this->assertTransparency($image->pickColor(12, 1));
|
||||||
|
}
|
||||||
|
}
|
31
tests/Drivers/Imagick/Modifiers/ResizeCanvasModifier.php
Normal file
31
tests/Drivers/Imagick/Modifiers/ResizeCanvasModifier.php
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Intervention\Image\Tests\Drivers\Imagick\Modifiers;
|
||||||
|
|
||||||
|
use Intervention\Image\Modifiers\ResizeCanvasModifier;
|
||||||
|
use Intervention\Image\Tests\TestCase;
|
||||||
|
use Intervention\Image\Tests\Traits\CanCreateImagickTestImage;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @requires extension gd
|
||||||
|
* @covers \Intervention\Image\Modifiers\ResizeCanvasModifier
|
||||||
|
*/
|
||||||
|
class ResizeCanvasModifierTest extends TestCase
|
||||||
|
{
|
||||||
|
use CanCreateImagickTestImage;
|
||||||
|
|
||||||
|
public function testModify(): void
|
||||||
|
{
|
||||||
|
$image = $this->createTestImage('tile.png');
|
||||||
|
$this->assertEquals(16, $image->width());
|
||||||
|
$this->assertEquals(16, $image->height());
|
||||||
|
$image->modify(new ResizeCanvasModifier(18, 18, 'ff0', 'center'));
|
||||||
|
$this->assertEquals(18, $image->width());
|
||||||
|
$this->assertEquals(18, $image->height());
|
||||||
|
$this->assertColor(255, 255, 0, 255, $image->pickColor(0, 0));
|
||||||
|
$this->assertColor(180, 224, 0, 255, $image->pickColor(1, 1));
|
||||||
|
$this->assertColor(180, 224, 0, 255, $image->pickColor(2, 2));
|
||||||
|
$this->assertColor(255, 255, 0, 255, $image->pickColor(17, 17));
|
||||||
|
$this->assertTransparency($image->pickColor(12, 1));
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user