Skip to content

Commit

Permalink
Add CropModifier
Browse files Browse the repository at this point in the history
  • Loading branch information
olivervogel committed Oct 23, 2023
1 parent 01854ed commit 6d744bf
Show file tree
Hide file tree
Showing 5 changed files with 200 additions and 0 deletions.
12 changes: 12 additions & 0 deletions src/Drivers/Abstract/AbstractImage.php
Original file line number Diff line number Diff line change
Expand Up @@ -345,6 +345,18 @@ public function padDown(
);
}

public function crop(
int $width,
int $height,
string $position = 'center',
int $offset_x = 0,
int $offset_y = 0
): ImageInterface {
return $this->modify(
$this->resolveDriverClass('Modifiers\CropModifier', $width, $height, $position, $offset_x, $offset_y)
);
}

public function removeAnimation(int $position = 0): ImageInterface
{
return $this->modify(
Expand Down
94 changes: 94 additions & 0 deletions src/Drivers/Gd/Modifiers/CropModifier.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
<?php

namespace Intervention\Image\Drivers\Gd\Modifiers;

use Intervention\Image\Geometry\Rectangle;
use Intervention\Image\Interfaces\FrameInterface;
use Intervention\Image\Interfaces\ImageInterface;
use Intervention\Image\Interfaces\ModifierInterface;
use Intervention\Image\Interfaces\SizeInterface;

class CropModifier implements ModifierInterface
{
public function __construct(
protected int $width,
protected int $height,
protected string $position = 'center',
protected int $offset_x = 0,
protected int $offset_y = 0
) {
//
}

public function apply(ImageInterface $image): ImageInterface
{
$crop = new Rectangle($this->width, $this->height);
$crop->align($this->position);
$crop->alignPivotTo($image->getSize(), $this->position);

foreach ($image as $frame) {
$this->cropFrame($frame, $crop);
}

return $image;
}

protected function cropFrame(FrameInterface $frame, SizeInterface $resizeTo): void
{
// create new image
$modified = imagecreatetruecolor(
$resizeTo->getWidth(),
$resizeTo->getHeight()
);

// get current image
$current = $frame->getCore();

// preserve transparency
imagealphablending($modified, false);
$transIndex = imagecolortransparent($current);

if ($transIndex != -1) {
$rgba = imagecolorsforindex($modified, $transIndex);
$transColor = imagecolorallocatealpha($modified, $rgba['red'], $rgba['green'], $rgba['blue'], 127);
imagefill($modified, 0, 0, $transColor);
} else {
imagesavealpha($modified, true);
}

// copy content from resource
imagecopyresampled(
$modified,
$current,
0,
0,
$resizeTo->getPivot()->getX(),
$resizeTo->getPivot()->getY(),
$resizeTo->getWidth(),
$resizeTo->getHeight(),
$resizeTo->getWidth(),
$resizeTo->getHeight(),
);

imagedestroy($current);

if ($transIndex != -1) { // @todo refactor because of duplication
imagecolortransparent($modified, $transIndex);
for ($y = 0; $y < $resizeTo->getHeight(); ++$y) {
for ($x = 0; $x < $resizeTo->getWidth(); ++$x) {
if (((imagecolorat($modified, $x, $y) >> 24) & 0x7F) >= 100) {
imagesetpixel(
$modified,
$x,
$y,
$transIndex
);
}
}
}
}

// set new content as recource
$frame->setCore($modified);
}
}
38 changes: 38 additions & 0 deletions src/Drivers/Imagick/Modifiers/CropModifier.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<?php

namespace Intervention\Image\Drivers\Imagick\Modifiers;

use Intervention\Image\Geometry\Rectangle;
use Intervention\Image\Interfaces\ImageInterface;
use Intervention\Image\Interfaces\ModifierInterface;

class CropModifier implements ModifierInterface
{
public function __construct(
protected int $width,
protected int $height,
protected string $position = 'center',
protected int $offset_x = 0,
protected int $offset_y = 0
) {
//
}

public function apply(ImageInterface $image): ImageInterface
{
$crop = new Rectangle($this->width, $this->height);
$crop->align($this->position);
$crop->alignPivotTo($image->getSize(), $this->position);

foreach ($image as $frame) {
$frame->getCore()->extentImage(
$crop->getWidth(),
$crop->getHeight(),
$crop->getPivot()->getX() + $this->offset_x,
$crop->getPivot()->getY() + $this->offset_y
);
}

return $image;
}
}
28 changes: 28 additions & 0 deletions tests/Drivers/Gd/Modifiers/CropModifierTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<?php

namespace Intervention\Image\Tests\Drivers\Gd\Modifiers;

use Intervention\Image\Drivers\Gd\Modifiers\CropModifier;
use Intervention\Image\Tests\TestCase;
use Intervention\Image\Tests\Traits\CanCreateGdTestImage;

/**
* @requires extension gd
* @covers \Intervention\Image\Drivers\Gd\Modifiers\CropModifier
*/
class CropModifierTest extends TestCase
{
use CanCreateGdTestImage;

public function testModify(): void
{
$image = $this->createTestImage('blocks.png');
$image = $image->modify(new CropModifier(200, 200, 'bottom-right'));
$image->toPng()->save('./test.png');
$this->assertEquals(200, $image->getWidth());
$this->assertEquals(200, $image->getHeight());
$this->assertColor(255, 0, 0, 255, $image->pickColor(5, 5));
$this->assertColor(255, 0, 0, 255, $image->pickColor(100, 100));
$this->assertColor(255, 0, 0, 255, $image->pickColor(190, 190));
}
}
28 changes: 28 additions & 0 deletions tests/Drivers/Imagick/Modifiers/CropModifierTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<?php

namespace Intervention\Image\Tests\Drivers\Imagick\Modifiers;

use Intervention\Image\Drivers\Imagick\Modifiers\CropModifier;
use Intervention\Image\Tests\TestCase;
use Intervention\Image\Tests\Traits\CanCreateImagickTestImage;

/**
* @requires extension gd
* @covers \Intervention\Image\Drivers\Imagick\Modifiers\CropModifier
*/
class CropModifierTest extends TestCase
{
use CanCreateImagickTestImage;

public function testModify(): void
{
$image = $this->createTestImage('blocks.png');
$image = $image->modify(new CropModifier(200, 200, 'bottom-right'));
$image->toPng()->save('./test.png');
$this->assertEquals(200, $image->getWidth());
$this->assertEquals(200, $image->getHeight());
$this->assertColor(255, 0, 0, 255, $image->pickColor(5, 5));
$this->assertColor(255, 0, 0, 255, $image->pickColor(100, 100));
$this->assertColor(255, 0, 0, 255, $image->pickColor(190, 190));
}
}

0 comments on commit 6d744bf

Please sign in to comment.