diff --git a/src/Modifiers/ContainModifier.php b/src/Modifiers/ContainModifier.php index b726f35..cbfb933 100644 --- a/src/Modifiers/ContainModifier.php +++ b/src/Modifiers/ContainModifier.php @@ -57,6 +57,11 @@ private function contain(FrameInterface $frame, SizeInterface $resize, ColorInte 'no_rotate' => true, ]); + if ($resized->bands < 3) { + // Grayscale -> RGB + $resized = $resized->colourspace('srgb'); + } + if (!$resized->hasAlpha()) { $resized = $resized->bandjoin_const(255); } diff --git a/src/Modifiers/CropModifier.php b/src/Modifiers/CropModifier.php index 745b59c..8ea8c83 100644 --- a/src/Modifiers/CropModifier.php +++ b/src/Modifiers/CropModifier.php @@ -76,22 +76,22 @@ private function background(SizeInterface $resizeTo, ImageInterface $image): Vip $bgColor->channel(Blue::class)->value(), ]; - $originalImage = $image->core()->native(); - if ($originalImage->bands === 1) { + $imageNative = $image->core()->native(); + if ($imageNative->bands < 3) { // Grayscale -> RGB - $originalImage = $originalImage->colourspace('srgb'); + $imageNative = $imageNative->colourspace('srgb'); } // original image and background must have the same number of bands - if ($originalImage->hasAlpha()) { + if ($imageNative->hasAlpha()) { $bands[] = $bgColor->channel(Alpha::class)->value(); } return VipsImage::black(1, 1) ->add($bgColor->channel(Red::class)->value()) - ->cast($originalImage->format) + ->cast($imageNative->format) ->embed(0, 0, $resizeTo->width(), $resizeTo->height(), ['extend' => Extend::COPY]) - ->copy(['interpretation' => $originalImage->interpretation]) + ->copy(['interpretation' => $imageNative->interpretation]) ->bandjoin($bands); } @@ -136,6 +136,11 @@ private function cropFrame( ); if ($crop->width() > $originalSize->width() || $cropped->height < $crop->height()) { + if ($cropped->bands < 3) { + // Grayscale -> RGB + $cropped = $cropped->colourspace('srgb'); + } + $cropped = $background->insert( $cropped, max($offset_x * -1, 0), diff --git a/src/Modifiers/PadModifier.php b/src/Modifiers/PadModifier.php index 27a1593..44e40ae 100644 --- a/src/Modifiers/PadModifier.php +++ b/src/Modifiers/PadModifier.php @@ -55,11 +55,12 @@ private function pad(FrameInterface $frame, SizeInterface $resize, ColorInterfac 'no_rotate' => true, ]); + if ($resized->bands < 3) { + // Grayscale -> RGB + $resized = $resized->colourspace('srgb'); + } + if (!$resized->hasAlpha()) { - if ($resized->bands === 1) { - // Grayscale -> RGB - $resized = $resized->colourspace('srgb'); - } $resized = $resized->bandjoin_const(255); } diff --git a/tests/Unit/Modifiers/ContainModifierTest.php b/tests/Unit/Modifiers/ContainModifierTest.php index d7736f4..433c505 100644 --- a/tests/Unit/Modifiers/ContainModifierTest.php +++ b/tests/Unit/Modifiers/ContainModifierTest.php @@ -65,4 +65,28 @@ public function testModifyContainAnimated(): void $this->assertColor(255, 255, 255, 0, $frame->toImage(new Driver())->pickColor(0, 0)); } } + + public function testModifyContainGrayscale(): void + { + $image = $this->readTestImage('grayscale.png'); + $this->assertEquals(150, $image->width()); + $this->assertEquals(200, $image->height()); + $image->modify(new ContainModifier(200, 200, 'transparent', 'top')); + $this->assertEquals(200, $image->width()); + $this->assertEquals(200, $image->height()); + $this->assertColor(255, 255, 255, 0, $image->pickColor(0, 0)); + $this->assertColor(0, 0, 0, 255, $image->pickColor(50, 0)); + } + + public function testModifyContainGrayscaleAlpha(): void + { + $image = $this->readTestImage('grayscale-alpha.png'); + $this->assertEquals(256, $image->width()); + $this->assertEquals(256, $image->height()); + $image->modify(new ContainModifier(258, 256, 'transparent', 'top')); + $this->assertEquals(258, $image->width()); + $this->assertEquals(256, $image->height()); + $this->assertColor(255, 255, 255, 0, $image->pickColor(0, 0)); + $this->assertColor(0, 0, 0, 128, $image->pickColor(1, 0)); + } } diff --git a/tests/Unit/Modifiers/CropModifierTest.php b/tests/Unit/Modifiers/CropModifierTest.php index e290997..bc7c917 100644 --- a/tests/Unit/Modifiers/CropModifierTest.php +++ b/tests/Unit/Modifiers/CropModifierTest.php @@ -100,4 +100,16 @@ public function testCropGrayscale(): void // Ensure the image is encodable $image->encode(); } + + public function testCropGrayscaleAlpha(): void + { + $image = $this->readTestImage('grayscale-alpha.png'); + $image->modify(new CropModifier(258, 258, 0, 0, 'ff0000', 'center')); + $this->assertColor(255, 0, 0, 255, $image->pickColor(0, 0)); + $this->assertColor(0, 0, 0, 128, $image->pickColor(1, 1)); + $this->assertColor(255, 255, 255, 128, $image->pickColor(256, 1)); + + // Ensure the image is encodable + $image->encode(); + } } diff --git a/tests/Unit/Modifiers/PadModifierTest.php b/tests/Unit/Modifiers/PadModifierTest.php index 1a4765f..14252f5 100644 --- a/tests/Unit/Modifiers/PadModifierTest.php +++ b/tests/Unit/Modifiers/PadModifierTest.php @@ -50,4 +50,18 @@ public function testModifyGrayscale(): void $this->assertColor(255, 0, 0, 255, $image->pickColor(199, 0)); $this->assertColor(255, 0, 0, 255, $image->pickColor(199, 199)); } + + public function testModifyGrayscaleAlpha(): void + { + $image = $this->readTestImage('grayscale-alpha.png'); + $this->assertEquals(256, $image->width()); + $this->assertEquals(256, $image->height()); + $image->modify(new PadModifier(258, 258, 'f00')); + $this->assertEquals(258, $image->width()); + $this->assertEquals(258, $image->height()); + $this->assertColor(255, 0, 0, 255, $image->pickColor(0, 0)); + $this->assertColor(255, 0, 0, 255, $image->pickColor(0, 257)); + $this->assertColor(255, 0, 0, 255, $image->pickColor(257, 0)); + $this->assertColor(255, 0, 0, 255, $image->pickColor(257, 257)); + } } diff --git a/tests/resources/grayscale-alpha.png b/tests/resources/grayscale-alpha.png new file mode 100644 index 0000000..e341d5b Binary files /dev/null and b/tests/resources/grayscale-alpha.png differ