1
0
mirror of https://github.com/Intervention/image.git synced 2025-08-12 08:54:03 +02:00

Fix transparency issues with gd driver resizing

This commit is contained in:
Oliver Vogel
2023-11-05 14:02:19 +01:00
parent 1fa784365f
commit 6ebdf8a96f
7 changed files with 48 additions and 83 deletions

View File

@@ -18,6 +18,6 @@ class TransparentColorDecoder extends HexColorDecoder
throw new DecoderException('Unable to decode input');
}
return parent::decode('#00000000');
return parent::decode('#ff00ff00');
}
}

View File

@@ -7,9 +7,12 @@ use Intervention\Image\Interfaces\FrameInterface;
use Intervention\Image\Interfaces\ImageInterface;
use Intervention\Image\Interfaces\ModifierInterface;
use Intervention\Image\Interfaces\SizeInterface;
use Intervention\Image\Traits\CanBuildNewImage;
class CropModifier implements ModifierInterface
{
use CanBuildNewImage;
public function __construct(
protected int $width,
protected int $height,
@@ -36,30 +39,28 @@ class CropModifier implements ModifierInterface
protected function cropFrame(FrameInterface $frame, SizeInterface $resizeTo): void
{
// create new image
$modified = imagecreatetruecolor(
$modified = $this->imageFactory()->newCore(
$resizeTo->width(),
$resizeTo->height()
);
// get current image
$current = $frame->core();
// get original image
$original = $frame->core();
// preserve transparency
imagealphablending($modified, false);
$transIndex = imagecolortransparent($current);
$transIndex = imagecolortransparent($original);
if ($transIndex != -1) {
$rgba = imagecolorsforindex($modified, $transIndex);
$transColor = imagecolorallocatealpha($modified, $rgba['red'], $rgba['green'], $rgba['blue'], 127);
imagefill($modified, 0, 0, $transColor);
} else {
imagesavealpha($modified, true);
imagecolortransparent($modified, $transColor);
}
// copy content from resource
imagecopyresampled(
$modified,
$current,
$original,
0,
0,
$resizeTo->pivot()->x() + $this->offset_x,
@@ -70,22 +71,6 @@ class CropModifier implements ModifierInterface
$resizeTo->height(),
);
if ($transIndex != -1) { // @todo refactor because of duplication
imagecolortransparent($modified, $transIndex);
for ($y = 0; $y < $resizeTo->height(); ++$y) {
for ($x = 0; $x < $resizeTo->width(); ++$x) {
if (((imagecolorat($modified, $x, $y) >> 24) & 0x7F) >= 100) {
imagesetpixel(
$modified,
$x,
$y,
$transIndex
);
}
}
}
}
// set new content as recource
$frame->setCore($modified);
}

View File

@@ -7,9 +7,12 @@ use Intervention\Image\Interfaces\FrameInterface;
use Intervention\Image\Interfaces\ImageInterface;
use Intervention\Image\Interfaces\ModifierInterface;
use Intervention\Image\Interfaces\SizeInterface;
use Intervention\Image\Traits\CanBuildNewImage;
class FitModifier extends AbstractFitModifier implements ModifierInterface
{
use CanBuildNewImage;
public function apply(ImageInterface $image): ImageInterface
{
$crop = $this->getCropSize($image);
@@ -25,30 +28,28 @@ class FitModifier extends AbstractFitModifier implements ModifierInterface
protected function modifyFrame(FrameInterface $frame, SizeInterface $crop, SizeInterface $resize): void
{
// create new image
$modified = imagecreatetruecolor(
$modified = $this->imageFactory()->newCore(
$resize->width(),
$resize->height()
);
// get current image
$current = $frame->core();
// get original image
$original = $frame->core();
// preserve transparency
imagealphablending($modified, false);
$transIndex = imagecolortransparent($current);
$transIndex = imagecolortransparent($original);
if ($transIndex != -1) {
$rgba = imagecolorsforindex($modified, $transIndex);
$transColor = imagecolorallocatealpha($modified, $rgba['red'], $rgba['green'], $rgba['blue'], 127);
imagefill($modified, 0, 0, $transColor);
} else {
imagesavealpha($modified, true);
imagecolortransparent($modified, $transColor);
}
// copy content from resource
imagecopyresampled(
$modified,
$current,
$original,
0,
0,
$crop->pivot()->x(),
@@ -59,22 +60,6 @@ class FitModifier extends AbstractFitModifier implements ModifierInterface
$crop->height()
);
if ($transIndex != -1) { // @todo refactor because of duplication
imagecolortransparent($modified, $transIndex);
for ($y = 0; $y < $resize->height(); ++$y) {
for ($x = 0; $x < $resize->width(); ++$x) {
if (((imagecolorat($modified, $x, $y) >> 24) & 0x7F) >= 100) {
imagesetpixel(
$modified,
$x,
$y,
$transIndex
);
}
}
}
}
// set new content as resource
$frame->setCore($modified);
}

View File

@@ -4,22 +4,25 @@ namespace Intervention\Image\Drivers\Gd\Modifiers;
use Intervention\Image\Drivers\Abstract\Modifiers\AbstractPadModifier;
use Intervention\Image\Drivers\Gd\Traits\CanHandleColors;
use Intervention\Image\Interfaces\ColorInterface;
use Intervention\Image\Interfaces\FrameInterface;
use Intervention\Image\Interfaces\ImageInterface;
use Intervention\Image\Interfaces\ModifierInterface;
use Intervention\Image\Interfaces\SizeInterface;
use Intervention\Image\Traits\CanBuildNewImage;
use Intervention\Image\Traits\CanHandleInput;
class PadModifier extends AbstractPadModifier implements ModifierInterface
{
use CanHandleInput;
use CanHandleColors;
use CanBuildNewImage;
public function apply(ImageInterface $image): ImageInterface
{
$crop = $this->getCropSize($image);
$resize = $this->getResizeSize($image);
$background = $this->colorToInteger($this->handleInput($this->background));
$background = $this->handleInput($this->background);
foreach ($image as $frame) {
$this->modify($frame, $crop, $resize, $background);
@@ -32,27 +35,34 @@ class PadModifier extends AbstractPadModifier implements ModifierInterface
FrameInterface $frame,
SizeInterface $crop,
SizeInterface $resize,
int $background
ColorInterface $background
): void {
// create new image
$modified = imagecreatetruecolor(
// create new gd image
$modified = $this->imageFactory()->newCore(
$resize->width(),
$resize->height()
$resize->height(),
$background
);
imagefill($modified, 0, 0, $background);
// make image area transparent to keep transparency
// even if background-color is set
$transparent = imagecolorallocatealpha($modified, 255, 0, 255, 127);
imagealphablending($modified, false); // do not blend / just overwrite
imagecolortransparent($modified, $transparent);
imagefilledrectangle(
$modified,
$crop->pivot()->x(),
$crop->pivot()->y(),
$crop->pivot()->x() + $crop->width() - 1,
$crop->pivot()->y() + $crop->height() - 1,
$transparent
);
// get current image
$current = $frame->core();
// preserve transparency
imagealphablending($modified, false);
imagesavealpha($modified, true);
// copy content from resource
// copy image from original with blending alpha
imagealphablending($modified, true);
imagecopyresampled(
$modified,
$current,
$frame->core(),
$crop->pivot()->x(),
$crop->pivot()->y(),
0,

View File

@@ -37,14 +37,15 @@ class ResizeModifier implements ModifierInterface
$current = $frame->core();
// preserve transparency
imagealphablending($modified, false);
$transIndex = imagecolortransparent($current);
if ($transIndex != -1) {
$rgba = imagecolorsforindex($modified, $transIndex);
$transColor = imagecolorallocatealpha($modified, $rgba['red'], $rgba['green'], $rgba['blue'], 127);
imagefill($modified, 0, 0, $transColor);
imagecolortransparent($modified, $transColor);
} else {
imagealphablending($modified, false);
imagesavealpha($modified, true);
}
@@ -62,22 +63,6 @@ class ResizeModifier implements ModifierInterface
$frame->size()->height()
);
if ($transIndex != -1) { // @todo refactor because of duplication
imagecolortransparent($modified, $transIndex);
for ($y = 0; $y < $resizeTo->height(); ++$y) {
for ($x = 0; $x < $resizeTo->width(); ++$x) {
if (((imagecolorat($modified, $x, $y) >> 24) & 0x7F) >= 100) {
imagesetpixel(
$modified,
$x,
$y,
$transIndex
);
}
}
}
}
// set new content as recource
$frame->setCore($modified);
}

View File

@@ -120,6 +120,6 @@ class GdInputHandlerTest extends TestCase
$input = 'transparent';
$result = $handler->handle($input);
$this->assertInstanceOf(RgbColor::class, $result);
$this->assertEquals([0, 0, 0, 0], $result->toArray());
$this->assertEquals([255, 0, 255, 0], $result->toArray());
}
}

View File

@@ -120,6 +120,6 @@ class InputHandlerTest extends TestCase
$input = 'transparent';
$result = $handler->handle($input);
$this->assertInstanceOf(RgbColor::class, $result);
$this->assertEquals([0, 0, 0, 0], $result->toArray());
$this->assertEquals([255, 0, 255, 0], $result->toArray());
}
}