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:
@@ -18,6 +18,6 @@ class TransparentColorDecoder extends HexColorDecoder
|
|||||||
throw new DecoderException('Unable to decode input');
|
throw new DecoderException('Unable to decode input');
|
||||||
}
|
}
|
||||||
|
|
||||||
return parent::decode('#00000000');
|
return parent::decode('#ff00ff00');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -7,9 +7,12 @@ use Intervention\Image\Interfaces\FrameInterface;
|
|||||||
use Intervention\Image\Interfaces\ImageInterface;
|
use Intervention\Image\Interfaces\ImageInterface;
|
||||||
use Intervention\Image\Interfaces\ModifierInterface;
|
use Intervention\Image\Interfaces\ModifierInterface;
|
||||||
use Intervention\Image\Interfaces\SizeInterface;
|
use Intervention\Image\Interfaces\SizeInterface;
|
||||||
|
use Intervention\Image\Traits\CanBuildNewImage;
|
||||||
|
|
||||||
class CropModifier implements ModifierInterface
|
class CropModifier implements ModifierInterface
|
||||||
{
|
{
|
||||||
|
use CanBuildNewImage;
|
||||||
|
|
||||||
public function __construct(
|
public function __construct(
|
||||||
protected int $width,
|
protected int $width,
|
||||||
protected int $height,
|
protected int $height,
|
||||||
@@ -36,30 +39,28 @@ class CropModifier implements ModifierInterface
|
|||||||
protected function cropFrame(FrameInterface $frame, SizeInterface $resizeTo): void
|
protected function cropFrame(FrameInterface $frame, SizeInterface $resizeTo): void
|
||||||
{
|
{
|
||||||
// create new image
|
// create new image
|
||||||
$modified = imagecreatetruecolor(
|
$modified = $this->imageFactory()->newCore(
|
||||||
$resizeTo->width(),
|
$resizeTo->width(),
|
||||||
$resizeTo->height()
|
$resizeTo->height()
|
||||||
);
|
);
|
||||||
|
|
||||||
// get current image
|
// get original image
|
||||||
$current = $frame->core();
|
$original = $frame->core();
|
||||||
|
|
||||||
// preserve transparency
|
// preserve transparency
|
||||||
imagealphablending($modified, false);
|
$transIndex = imagecolortransparent($original);
|
||||||
$transIndex = imagecolortransparent($current);
|
|
||||||
|
|
||||||
if ($transIndex != -1) {
|
if ($transIndex != -1) {
|
||||||
$rgba = imagecolorsforindex($modified, $transIndex);
|
$rgba = imagecolorsforindex($modified, $transIndex);
|
||||||
$transColor = imagecolorallocatealpha($modified, $rgba['red'], $rgba['green'], $rgba['blue'], 127);
|
$transColor = imagecolorallocatealpha($modified, $rgba['red'], $rgba['green'], $rgba['blue'], 127);
|
||||||
imagefill($modified, 0, 0, $transColor);
|
imagefill($modified, 0, 0, $transColor);
|
||||||
} else {
|
imagecolortransparent($modified, $transColor);
|
||||||
imagesavealpha($modified, true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// copy content from resource
|
// copy content from resource
|
||||||
imagecopyresampled(
|
imagecopyresampled(
|
||||||
$modified,
|
$modified,
|
||||||
$current,
|
$original,
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
$resizeTo->pivot()->x() + $this->offset_x,
|
$resizeTo->pivot()->x() + $this->offset_x,
|
||||||
@@ -70,22 +71,6 @@ class CropModifier implements ModifierInterface
|
|||||||
$resizeTo->height(),
|
$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
|
// set new content as recource
|
||||||
$frame->setCore($modified);
|
$frame->setCore($modified);
|
||||||
}
|
}
|
||||||
|
@@ -7,9 +7,12 @@ use Intervention\Image\Interfaces\FrameInterface;
|
|||||||
use Intervention\Image\Interfaces\ImageInterface;
|
use Intervention\Image\Interfaces\ImageInterface;
|
||||||
use Intervention\Image\Interfaces\ModifierInterface;
|
use Intervention\Image\Interfaces\ModifierInterface;
|
||||||
use Intervention\Image\Interfaces\SizeInterface;
|
use Intervention\Image\Interfaces\SizeInterface;
|
||||||
|
use Intervention\Image\Traits\CanBuildNewImage;
|
||||||
|
|
||||||
class FitModifier extends AbstractFitModifier implements ModifierInterface
|
class FitModifier extends AbstractFitModifier implements ModifierInterface
|
||||||
{
|
{
|
||||||
|
use CanBuildNewImage;
|
||||||
|
|
||||||
public function apply(ImageInterface $image): ImageInterface
|
public function apply(ImageInterface $image): ImageInterface
|
||||||
{
|
{
|
||||||
$crop = $this->getCropSize($image);
|
$crop = $this->getCropSize($image);
|
||||||
@@ -25,30 +28,28 @@ class FitModifier extends AbstractFitModifier implements ModifierInterface
|
|||||||
protected function modifyFrame(FrameInterface $frame, SizeInterface $crop, SizeInterface $resize): void
|
protected function modifyFrame(FrameInterface $frame, SizeInterface $crop, SizeInterface $resize): void
|
||||||
{
|
{
|
||||||
// create new image
|
// create new image
|
||||||
$modified = imagecreatetruecolor(
|
$modified = $this->imageFactory()->newCore(
|
||||||
$resize->width(),
|
$resize->width(),
|
||||||
$resize->height()
|
$resize->height()
|
||||||
);
|
);
|
||||||
|
|
||||||
// get current image
|
// get original image
|
||||||
$current = $frame->core();
|
$original = $frame->core();
|
||||||
|
|
||||||
// preserve transparency
|
// preserve transparency
|
||||||
imagealphablending($modified, false);
|
$transIndex = imagecolortransparent($original);
|
||||||
$transIndex = imagecolortransparent($current);
|
|
||||||
|
|
||||||
if ($transIndex != -1) {
|
if ($transIndex != -1) {
|
||||||
$rgba = imagecolorsforindex($modified, $transIndex);
|
$rgba = imagecolorsforindex($modified, $transIndex);
|
||||||
$transColor = imagecolorallocatealpha($modified, $rgba['red'], $rgba['green'], $rgba['blue'], 127);
|
$transColor = imagecolorallocatealpha($modified, $rgba['red'], $rgba['green'], $rgba['blue'], 127);
|
||||||
imagefill($modified, 0, 0, $transColor);
|
imagefill($modified, 0, 0, $transColor);
|
||||||
} else {
|
imagecolortransparent($modified, $transColor);
|
||||||
imagesavealpha($modified, true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// copy content from resource
|
// copy content from resource
|
||||||
imagecopyresampled(
|
imagecopyresampled(
|
||||||
$modified,
|
$modified,
|
||||||
$current,
|
$original,
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
$crop->pivot()->x(),
|
$crop->pivot()->x(),
|
||||||
@@ -59,22 +60,6 @@ class FitModifier extends AbstractFitModifier implements ModifierInterface
|
|||||||
$crop->height()
|
$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
|
// set new content as resource
|
||||||
$frame->setCore($modified);
|
$frame->setCore($modified);
|
||||||
}
|
}
|
||||||
|
@@ -4,22 +4,25 @@ namespace Intervention\Image\Drivers\Gd\Modifiers;
|
|||||||
|
|
||||||
use Intervention\Image\Drivers\Abstract\Modifiers\AbstractPadModifier;
|
use Intervention\Image\Drivers\Abstract\Modifiers\AbstractPadModifier;
|
||||||
use Intervention\Image\Drivers\Gd\Traits\CanHandleColors;
|
use Intervention\Image\Drivers\Gd\Traits\CanHandleColors;
|
||||||
|
use Intervention\Image\Interfaces\ColorInterface;
|
||||||
use Intervention\Image\Interfaces\FrameInterface;
|
use Intervention\Image\Interfaces\FrameInterface;
|
||||||
use Intervention\Image\Interfaces\ImageInterface;
|
use Intervention\Image\Interfaces\ImageInterface;
|
||||||
use Intervention\Image\Interfaces\ModifierInterface;
|
use Intervention\Image\Interfaces\ModifierInterface;
|
||||||
use Intervention\Image\Interfaces\SizeInterface;
|
use Intervention\Image\Interfaces\SizeInterface;
|
||||||
|
use Intervention\Image\Traits\CanBuildNewImage;
|
||||||
use Intervention\Image\Traits\CanHandleInput;
|
use Intervention\Image\Traits\CanHandleInput;
|
||||||
|
|
||||||
class PadModifier extends AbstractPadModifier implements ModifierInterface
|
class PadModifier extends AbstractPadModifier implements ModifierInterface
|
||||||
{
|
{
|
||||||
use CanHandleInput;
|
use CanHandleInput;
|
||||||
use CanHandleColors;
|
use CanHandleColors;
|
||||||
|
use CanBuildNewImage;
|
||||||
|
|
||||||
public function apply(ImageInterface $image): ImageInterface
|
public function apply(ImageInterface $image): ImageInterface
|
||||||
{
|
{
|
||||||
$crop = $this->getCropSize($image);
|
$crop = $this->getCropSize($image);
|
||||||
$resize = $this->getResizeSize($image);
|
$resize = $this->getResizeSize($image);
|
||||||
$background = $this->colorToInteger($this->handleInput($this->background));
|
$background = $this->handleInput($this->background);
|
||||||
|
|
||||||
foreach ($image as $frame) {
|
foreach ($image as $frame) {
|
||||||
$this->modify($frame, $crop, $resize, $background);
|
$this->modify($frame, $crop, $resize, $background);
|
||||||
@@ -32,27 +35,34 @@ class PadModifier extends AbstractPadModifier implements ModifierInterface
|
|||||||
FrameInterface $frame,
|
FrameInterface $frame,
|
||||||
SizeInterface $crop,
|
SizeInterface $crop,
|
||||||
SizeInterface $resize,
|
SizeInterface $resize,
|
||||||
int $background
|
ColorInterface $background
|
||||||
): void {
|
): void {
|
||||||
// create new image
|
// create new gd image
|
||||||
$modified = imagecreatetruecolor(
|
$modified = $this->imageFactory()->newCore(
|
||||||
$resize->width(),
|
$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
|
// copy image from original with blending alpha
|
||||||
$current = $frame->core();
|
imagealphablending($modified, true);
|
||||||
|
|
||||||
// preserve transparency
|
|
||||||
imagealphablending($modified, false);
|
|
||||||
imagesavealpha($modified, true);
|
|
||||||
|
|
||||||
// copy content from resource
|
|
||||||
imagecopyresampled(
|
imagecopyresampled(
|
||||||
$modified,
|
$modified,
|
||||||
$current,
|
$frame->core(),
|
||||||
$crop->pivot()->x(),
|
$crop->pivot()->x(),
|
||||||
$crop->pivot()->y(),
|
$crop->pivot()->y(),
|
||||||
0,
|
0,
|
||||||
|
@@ -37,14 +37,15 @@ class ResizeModifier implements ModifierInterface
|
|||||||
$current = $frame->core();
|
$current = $frame->core();
|
||||||
|
|
||||||
// preserve transparency
|
// preserve transparency
|
||||||
imagealphablending($modified, false);
|
|
||||||
$transIndex = imagecolortransparent($current);
|
$transIndex = imagecolortransparent($current);
|
||||||
|
|
||||||
if ($transIndex != -1) {
|
if ($transIndex != -1) {
|
||||||
$rgba = imagecolorsforindex($modified, $transIndex);
|
$rgba = imagecolorsforindex($modified, $transIndex);
|
||||||
$transColor = imagecolorallocatealpha($modified, $rgba['red'], $rgba['green'], $rgba['blue'], 127);
|
$transColor = imagecolorallocatealpha($modified, $rgba['red'], $rgba['green'], $rgba['blue'], 127);
|
||||||
imagefill($modified, 0, 0, $transColor);
|
imagefill($modified, 0, 0, $transColor);
|
||||||
|
imagecolortransparent($modified, $transColor);
|
||||||
} else {
|
} else {
|
||||||
|
imagealphablending($modified, false);
|
||||||
imagesavealpha($modified, true);
|
imagesavealpha($modified, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -62,22 +63,6 @@ class ResizeModifier implements ModifierInterface
|
|||||||
$frame->size()->height()
|
$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
|
// set new content as recource
|
||||||
$frame->setCore($modified);
|
$frame->setCore($modified);
|
||||||
}
|
}
|
||||||
|
@@ -120,6 +120,6 @@ class GdInputHandlerTest extends TestCase
|
|||||||
$input = 'transparent';
|
$input = 'transparent';
|
||||||
$result = $handler->handle($input);
|
$result = $handler->handle($input);
|
||||||
$this->assertInstanceOf(RgbColor::class, $result);
|
$this->assertInstanceOf(RgbColor::class, $result);
|
||||||
$this->assertEquals([0, 0, 0, 0], $result->toArray());
|
$this->assertEquals([255, 0, 255, 0], $result->toArray());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -120,6 +120,6 @@ class InputHandlerTest extends TestCase
|
|||||||
$input = 'transparent';
|
$input = 'transparent';
|
||||||
$result = $handler->handle($input);
|
$result = $handler->handle($input);
|
||||||
$this->assertInstanceOf(RgbColor::class, $result);
|
$this->assertInstanceOf(RgbColor::class, $result);
|
||||||
$this->assertEquals([0, 0, 0, 0], $result->toArray());
|
$this->assertEquals([255, 0, 255, 0], $result->toArray());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user