mirror of
https://github.com/Intervention/image.git
synced 2025-08-13 17:34:04 +02:00
Fix bug in CropModifier of Imagick driver (#1428)
The CropModifier produced strange artifacts if another resize step was performed after the modification. This patch removes the copying of the alpha channel in the CropModifier and implements a different method. See: https://github.com/Intervention/image/issues/1426
This commit is contained in:
@@ -5,7 +5,7 @@ declare(strict_types=1);
|
|||||||
namespace Intervention\Image\Drivers\Imagick\Modifiers;
|
namespace Intervention\Image\Drivers\Imagick\Modifiers;
|
||||||
|
|
||||||
use Imagick;
|
use Imagick;
|
||||||
use Intervention\Image\Drivers\Imagick\Driver;
|
use ImagickPixel;
|
||||||
use Intervention\Image\Interfaces\ImageInterface;
|
use Intervention\Image\Interfaces\ImageInterface;
|
||||||
use Intervention\Image\Interfaces\SpecializedInterface;
|
use Intervention\Image\Interfaces\SpecializedInterface;
|
||||||
use Intervention\Image\Modifiers\CropModifier as GenericCropModifier;
|
use Intervention\Image\Modifiers\CropModifier as GenericCropModifier;
|
||||||
@@ -14,20 +14,30 @@ class CropModifier extends GenericCropModifier implements SpecializedInterface
|
|||||||
{
|
{
|
||||||
public function apply(ImageInterface $image): ImageInterface
|
public function apply(ImageInterface $image): ImageInterface
|
||||||
{
|
{
|
||||||
$crop = $this->crop($image);
|
// decode background color
|
||||||
$background = $this->driver()->colorProcessor($image->colorspace())->colorToNative(
|
$background = $this->driver()->colorProcessor($image->colorspace())->colorToNative(
|
||||||
$this->driver()->handleInput($this->background)
|
$this->driver()->handleInput($this->background)
|
||||||
);
|
);
|
||||||
|
|
||||||
// create empty container imagick to rebuild core
|
// create empty container imagick to rebuild core
|
||||||
$imagick = new Imagick();
|
$imagick = new Imagick();
|
||||||
|
|
||||||
|
// save resolution to add it later
|
||||||
$resolution = $image->resolution()->perInch();
|
$resolution = $image->resolution()->perInch();
|
||||||
|
|
||||||
|
// define position of the image on the new canvas
|
||||||
|
$crop = $this->crop($image);
|
||||||
|
$position = [
|
||||||
|
($crop->pivot()->x() + $this->offset_x) * -1,
|
||||||
|
($crop->pivot()->y() + $this->offset_y) * -1,
|
||||||
|
];
|
||||||
|
|
||||||
foreach ($image as $frame) {
|
foreach ($image as $frame) {
|
||||||
// create new frame canvas with modifiers background
|
// create new frame canvas with modifiers background
|
||||||
$canvas = new Imagick();
|
$canvas = new Imagick();
|
||||||
$canvas->newImage($crop->width(), $crop->height(), $background, 'png');
|
$canvas->newImage($crop->width(), $crop->height(), $background, 'png');
|
||||||
$canvas->setImageResolution($resolution->x(), $resolution->y());
|
$canvas->setImageResolution($resolution->x(), $resolution->y());
|
||||||
|
$canvas->setImageAlphaChannel(Imagick::ALPHACHANNEL_SET); // or ALPHACHANNEL_ACTIVATE?
|
||||||
|
|
||||||
// set animation details
|
// set animation details
|
||||||
if ($image->isAnimated()) {
|
if ($image->isAnimated()) {
|
||||||
@@ -36,31 +46,28 @@ class CropModifier extends GenericCropModifier implements SpecializedInterface
|
|||||||
$canvas->setImageDispose($frame->native()->getImageDispose());
|
$canvas->setImageDispose($frame->native()->getImageDispose());
|
||||||
}
|
}
|
||||||
|
|
||||||
// place original frame content onto the empty colored frame canvas
|
// make the rectangular position of the original image transparent
|
||||||
$canvas->compositeImage(
|
// so that we can later place the original on top. this preserves
|
||||||
$frame->native(),
|
// the transparency of the original and shows the background color
|
||||||
Imagick::COMPOSITE_DEFAULT,
|
// of the modifier in the other areas. if the original image has no
|
||||||
($crop->pivot()->x() + $this->offset_x) * -1,
|
// transparent area the rectangular transparency will be covered by
|
||||||
($crop->pivot()->y() + $this->offset_y) * -1,
|
// the original.
|
||||||
|
$clearer = new Imagick();
|
||||||
|
$clearer->newImage(
|
||||||
|
$frame->native()->getImageWidth(),
|
||||||
|
$frame->native()->getImageHeight(),
|
||||||
|
new ImagickPixel('black'),
|
||||||
);
|
);
|
||||||
|
$canvas->compositeImage($clearer, Imagick::COMPOSITE_DSTOUT, ...$position);
|
||||||
|
|
||||||
// copy alpha channel if available
|
// place original frame content onto prepared frame canvas
|
||||||
if ($frame->native()->getImageAlphaChannel()) {
|
$canvas->compositeImage($frame->native(), Imagick::COMPOSITE_DEFAULT, ...$position);
|
||||||
$canvas->compositeImage(
|
|
||||||
$frame->native(),
|
|
||||||
version_compare(Driver::version(), '7.0.0', '>=') ?
|
|
||||||
Imagick::COMPOSITE_COPYOPACITY :
|
|
||||||
Imagick::COMPOSITE_DSTIN,
|
|
||||||
($crop->pivot()->x() + $this->offset_x) * -1,
|
|
||||||
($crop->pivot()->y() + $this->offset_y) * -1,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// add newly built frame to container imagick
|
// add newly built frame to container imagick
|
||||||
$imagick->addImage($canvas);
|
$imagick->addImage($canvas);
|
||||||
}
|
}
|
||||||
|
|
||||||
// replace imagick
|
// replace imagick in the original image
|
||||||
$image->core()->setNative($imagick);
|
$image->core()->setNative($imagick);
|
||||||
|
|
||||||
return $image;
|
return $image;
|
||||||
|
19
tests/Feature/Imagick/CropResizePngTest.php
Normal file
19
tests/Feature/Imagick/CropResizePngTest.php
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Intervention\Image\Tests\Feature\Imagick;
|
||||||
|
|
||||||
|
use Intervention\Image\Tests\ImagickTestCase;
|
||||||
|
|
||||||
|
class CropResizePngTest extends ImagickTestCase
|
||||||
|
{
|
||||||
|
public function testCropResizePng(): void
|
||||||
|
{
|
||||||
|
$image = $this->readTestImage('tile.png');
|
||||||
|
$image->crop(100, 100);
|
||||||
|
$image->resize(200, 200);
|
||||||
|
$this->assertTransparency($image->pickColor(7, 22));
|
||||||
|
$this->assertTransparency($image->pickColor(22, 7));
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user