From 575f5b691ffc22feffd6e22cbe82c97b0eb67d76 Mon Sep 17 00:00:00 2001 From: Nicolas Lemoine Date: Mon, 6 Jul 2026 18:44:50 +0200 Subject: [PATCH] Reset page geometry after Imagick rotation Imagick's rotateImage() grows the virtual canvas for non-right angles and leaves each frame with a negative page offset (a 480x480 frame rotated 45 degrees ends up 680x680-100-100). ImageMagick's animated-AVIF writer (libheif sequences) honours that offset when compositing the sequence, shifting every frame up and left and leaving the bottom/right region transparent. Reset each frame's page to +0+0 after rotating, mirroring TrimModifier and CoverModifier which already normalize page geometry. This keeps the Imagick driver consistent with the GD and vips drivers, which leave no offset, and fixes the transparent-corner artifact in animated AVIF. --- src/Drivers/Imagick/Modifiers/RotateModifier.php | 6 ++++++ .../Imagick/Modifiers/RotateModifierTest.php | 15 +++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/src/Drivers/Imagick/Modifiers/RotateModifier.php b/src/Drivers/Imagick/Modifiers/RotateModifier.php index eff3fc232..22f126270 100644 --- a/src/Drivers/Imagick/Modifiers/RotateModifier.php +++ b/src/Drivers/Imagick/Modifiers/RotateModifier.php @@ -32,6 +32,12 @@ public function apply(ImageInterface $image): ImageInterface 'Failed to apply ' . self::class . ', unable to rotate image', ); } + + // Reset the virtual canvas page that rotateImage() leaves behind. A + // non-right angle produces a negative page offset which otherwise + // corrupts the animated-AVIF (libheif sequences) writer, leaving the + // bottom/right region transparent. Mirrors TrimModifier/CoverModifier. + $frame->native()->setImagePage(0, 0, 0, 0); } catch (ImagickException $e) { throw new ModifierException( 'Failed to apply ' . self::class . ', unable to rotate image', diff --git a/tests/Unit/Drivers/Imagick/Modifiers/RotateModifierTest.php b/tests/Unit/Drivers/Imagick/Modifiers/RotateModifierTest.php index a280009cb..43188ddf6 100644 --- a/tests/Unit/Drivers/Imagick/Modifiers/RotateModifierTest.php +++ b/tests/Unit/Drivers/Imagick/Modifiers/RotateModifierTest.php @@ -23,4 +23,19 @@ public function testRotate(): void $this->assertEquals(240, $image->width()); $this->assertEquals(320, $image->height()); } + + public function testRotateResetsFramePageOffset(): void + { + // A non-right-angle rotation grows the virtual canvas; ImageMagick leaves + // each frame with a negative page offset. That offset mis-composes the + // animated-AVIF (libheif sequences) writer, leaving the bottom/right + // transparent, so rotate must reset every frame's page to +0+0. + $image = $this->readTestImage('animation.gif'); + $image->modify(new RotateModifier(45, 'fff')); + + foreach ($image as $frame) { + $this->assertSame(0, $frame->offsetLeft()); + $this->assertSame(0, $frame->offsetTop()); + } + } }