Skip to content

Commit

Permalink
Fix bug in imagick driver's CropModifier
Browse files Browse the repository at this point in the history
See: #1426
  • Loading branch information
olivervogel committed Jan 31, 2025
1 parent 70bbb17 commit 107e623
Showing 1 changed file with 22 additions and 21 deletions.
43 changes: 22 additions & 21 deletions src/Drivers/Imagick/Modifiers/CropModifier.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
namespace Intervention\Image\Drivers\Imagick\Modifiers;

use Imagick;
use Intervention\Image\Drivers\Imagick\Driver;
use Intervention\Image\Interfaces\ImageInterface;
use Intervention\Image\Interfaces\SpecializedInterface;
use Intervention\Image\Modifiers\CropModifier as GenericCropModifier;
Expand All @@ -14,20 +13,30 @@ class CropModifier extends GenericCropModifier implements SpecializedInterface
{
public function apply(ImageInterface $image): ImageInterface
{
$crop = $this->crop($image);
// decode background color
$background = $this->driver()->colorProcessor($image->colorspace())->colorToNative(
$this->driver()->handleInput($this->background)
);

// create empty container imagick to rebuild core
$imagick = new Imagick();

// save resolution to add it later
$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) {
// create new frame canvas with modifiers background
$canvas = new Imagick();
$canvas->newImage($crop->width(), $crop->height(), $background, 'png');
$canvas->setImageResolution($resolution->x(), $resolution->y());
$canvas->setImageAlphaChannel(Imagick::ALPHACHANNEL_SET); // or ALPHACHANNEL_ACTIVATE?
// set animation details
if ($image->isAnimated()) {
Expand All @@ -36,31 +45,23 @@ public function apply(ImageInterface $image): ImageInterface
$canvas->setImageDispose($frame->native()->getImageDispose());
}

// place original frame content onto the empty colored frame canvas
$canvas->compositeImage(
$frame->native(),
Imagick::COMPOSITE_DEFAULT,
($crop->pivot()->x() + $this->offset_x) * -1,
($crop->pivot()->y() + $this->offset_y) * -1,
);
// Make the entire rectangle at the position of the original image
// transparent so that we can later place the original on top.
// This preserves the transparency of the original and shows
// the background color of the modifier in the other areas
$clear = new Imagick();
$clear->newImage($frame->native()->getImageWidth(), $frame->native()->getImageHeight(), 'black');
$canvas->compositeImage($clear, Imagick::COMPOSITE_DSTOUT, ...$position);

// copy alpha channel if available
if ($frame->native()->getImageAlphaChannel()) {
$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,
);
}
// place original frame content onto the empty colored frame canvas
// with the transparent rectangle
$canvas->compositeImage($frame->native(), Imagick::COMPOSITE_DEFAULT, ...$position);

// add newly built frame to container imagick
$imagick->addImage($canvas);
}

// replace imagick
// replace imagick in the original image
$image->core()->setNative($imagick);

return $image;
Expand Down

0 comments on commit 107e623

Please sign in to comment.