Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Fix flaky dominant color hex on non-opaque alpha after resize
  • Loading branch information
lucasmichot committed Aug 3, 2026
commit 791f9f602cb3427f0a94d9d52382b8025850283a
3 changes: 2 additions & 1 deletion src/Illuminate/Image/Drivers/InterventionDriver.php
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,8 @@ protected function dominantColorFrom(ImageInterface $image): string
$sample = clone $image;

try {
return $sample->resize(1, 1)->colorAt(0, 0)->toHex(true);
// Interpolation during the 1x1 resize can leave alpha slightly non-opaque, so it's dropped here.
return substr($sample->resize(1, 1)->colorAt(0, 0)->toHex(true), 0, 7);
} finally {
unset($sample);
}
Expand Down
23 changes: 23 additions & 0 deletions tests/Image/Drivers/GdDriverTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,14 @@ public function test_dominant_color_returns_hex_for_solid_image()
$this->assertSame('#0080ff', $driver->dominantColor($contents));
}

public function test_dominant_color_ignores_alpha_channel(): void
{
$driver = new GdDriver;
$contents = $this->semiTransparentColorImageContents(0, 128, 255, 128);

$this->assertSame('#0080ff', $driver->dominantColor($contents));
}

public function test_processes_crop()
{
$driver = new GdDriver;
Expand Down Expand Up @@ -493,6 +501,21 @@ protected function solidColorImageContents(int $red, int $green, int $blue, int
return ob_get_clean();
}

protected function semiTransparentColorImageContents(int $red, int $green, int $blue, int $alpha, int $width = 100, int $height = 100): string
{
$image = imagecreatetruecolor($width, $height);
imagesavealpha($image, true);
// GD alpha runs 0 (opaque) to 127 (fully transparent), the inverse of a 0-255 alpha channel.
$gdAlpha = (int) round((255 - $alpha) / 255 * 127);
$color = imagecolorallocatealpha($image, $red, $green, $blue, $gdAlpha);
imagefill($image, 0, 0, $color);

ob_start();
imagepng($image);

return ob_get_clean();
}

protected function pipeline(?Transformation $transformation = null, ?string $format = null, ?int $quality = null): ImagePipeline
{
$pipeline = new ImagePipeline;
Expand Down
21 changes: 21 additions & 0 deletions tests/Image/Drivers/ImagickDriverTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,14 @@ public function test_dominant_color_returns_hex_for_solid_image()
$this->assertSame('#0080ff', $driver->dominantColor($contents));
}

public function test_dominant_color_ignores_alpha_channel(): void
{
$driver = new ImagickDriver;
$contents = $this->semiTransparentColorImageContents(0, 128, 255, 128);

$this->assertSame('#0080ff', $driver->dominantColor($contents));
}

public function test_processes_crop()
{
$driver = new ImagickDriver;
Expand Down Expand Up @@ -504,6 +512,19 @@ protected function solidColorImageContents(int $red, int $green, int $blue, int
return $contents;
}

protected function semiTransparentColorImageContents(int $red, int $green, int $blue, int $alpha, int $width = 100, int $height = 100): string
{
$imagick = new \Imagick;
$imagick->newImage($width, $height, new \ImagickPixel(sprintf('rgba(%d,%d,%d,%.2f)', $red, $green, $blue, $alpha / 255)));
$imagick->setImageFormat('png');

$contents = $imagick->getImageBlob();
$imagick->clear();
$imagick->destroy();

return $contents;
}

protected function pipeline(?Transformation $transformation = null, ?string $format = null, ?int $quality = null): ImagePipeline
{
$pipeline = new ImagePipeline;
Expand Down