diff --git a/src/Drivers/Imagick/Modifiers/RotateModifier.php b/src/Drivers/Imagick/Modifiers/RotateModifier.php index eff3fc23..22f12627 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 a280009c..43188ddf 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()); + } + } }