1
0
mirror of https://github.com/Intervention/image.git synced 2025-08-13 09:24:05 +02:00

Merge pull request #1277 from Intervention/feature/1253-add-transparency-param-for-place

Add opacity parameter to PlaceModifier
This commit is contained in:
Oliver Vogel
2024-01-20 09:50:30 +01:00
committed by GitHub
7 changed files with 122 additions and 15 deletions

View File

@@ -5,8 +5,10 @@ declare(strict_types=1);
namespace Intervention\Image\Drivers\Gd\Modifiers;
use Intervention\Image\Drivers\DriverSpecialized;
use Intervention\Image\Interfaces\FrameInterface;
use Intervention\Image\Interfaces\ImageInterface;
use Intervention\Image\Interfaces\ModifierInterface;
use Intervention\Image\Interfaces\PointInterface;
/**
* @method mixed getPosition(ImageInterface $image, ImageInterface $watermark)
@@ -14,6 +16,7 @@ use Intervention\Image\Interfaces\ModifierInterface;
* @property string $position
* @property int $offset_x
* @property int $offset_y
* @property int $opacity
*/
class PlaceModifier extends DriverSpecialized implements ModifierInterface
{
@@ -24,6 +27,27 @@ class PlaceModifier extends DriverSpecialized implements ModifierInterface
foreach ($image as $frame) {
imagealphablending($frame->native(), true);
if ($this->opacity === 100) {
$this->placeOpaque($frame, $watermark, $position);
} else {
$this->placeTransparent($frame, $watermark, $position);
}
}
return $image;
}
/**
* Insert watermark with 100% opacity
*
* @param FrameInterface $frame
* @param ImageInterface $watermark
* @param PointInterface $position
* @return void
*/
private function placeOpaque(FrameInterface $frame, ImageInterface $watermark, PointInterface $position): void
{
imagecopy(
$frame->native(),
$watermark->core()->native(),
@@ -36,6 +60,60 @@ class PlaceModifier extends DriverSpecialized implements ModifierInterface
);
}
return $image;
/**
* Insert watermark transparent with current opacity
*
* Unfortunately, the original PHP function imagecopymerge does not work reliably.
* For example, any transparency of the image to be inserted is not applied correctly.
* For this reason, a new GDImage is created into which the original image is inserted
* in the first step and the watermark is inserted with 100% opacity in the second
* step. This combination is then transferred to the original image again with the
* respective opacity.
*
* Please note: Unfortunately, there is still an edge case, when a transparent image
* is placed on a transparent background, the "double" transparent areas appear opaque!
*
* @param FrameInterface $frame
* @param ImageInterface $watermark
* @param PointInterface $position
* @return void
*/
private function placeTransparent(FrameInterface $frame, ImageInterface $watermark, PointInterface $position): void
{
$cut = imagecreatetruecolor($watermark->width(), $watermark->height());
imagecopy(
$cut,
$frame->native(),
0,
0,
$position->x(),
$position->y(),
imagesx($cut),
imagesy($cut)
);
imagecopy(
$cut,
$watermark->core()->native(),
0,
0,
0,
0,
imagesx($cut),
imagesy($cut)
);
imagecopymerge(
$frame->native(),
$cut,
$position->x(),
$position->y(),
0,
0,
$watermark->width(),
$watermark->height(),
$this->opacity
);
}
}

View File

@@ -15,6 +15,7 @@ use Intervention\Image\Interfaces\ModifierInterface;
* @property string $position
* @property int $offset_x
* @property int $offset_y
* @property int $opacity
*/
class PlaceModifier extends DriverSpecialized implements ModifierInterface
{
@@ -23,6 +24,15 @@ class PlaceModifier extends DriverSpecialized implements ModifierInterface
$watermark = $this->driver()->handleInput($this->element);
$position = $this->getPosition($image, $watermark);
// set opacity of watermark
if ($this->opacity < 100) {
$watermark->core()->native()->evaluateImage(
Imagick::EVALUATE_DIVIDE,
$this->opacity > 0 ? (100 / $this->opacity) : 1000,
Imagick::CHANNEL_ALPHA,
);
}
foreach ($image as $frame) {
$frame->native()->compositeImage(
$watermark->core()->native(),

View File

@@ -744,9 +744,10 @@ final class Image implements ImageInterface
mixed $element,
string $position = 'top-left',
int $offset_x = 0,
int $offset_y = 0
int $offset_y = 0,
int $opacity = 100
): ImageInterface {
return $this->modify(new PlaceModifier($element, $position, $offset_x, $offset_y));
return $this->modify(new PlaceModifier($element, $position, $offset_x, $offset_y, $opacity));
}
/**

View File

@@ -5,7 +5,6 @@ declare(strict_types=1);
namespace Intervention\Image\Interfaces;
use Countable;
use Intervention\Image\EncodedImage;
use Intervention\Image\Origin;
use IteratorAggregate;
@@ -522,13 +521,15 @@ interface ImageInterface extends IteratorAggregate, Countable
* @param string $position
* @param int $offset_x
* @param int $offset_y
* @param int $opacity
* @return ImageInterface
*/
public function place(
mixed $element,
string $position = 'top-left',
int $offset_x = 0,
int $offset_y = 0
int $offset_y = 0,
int $opacity = 100
): ImageInterface;
/**

View File

@@ -13,7 +13,8 @@ class PlaceModifier extends SpecializableModifier
public mixed $element,
public string $position,
public int $offset_x,
public int $offset_y
public int $offset_y,
public int $opacity = 100
) {
}

View File

@@ -24,4 +24,12 @@ class PlaceModifierTest extends TestCase
$image->modify(new PlaceModifier(__DIR__ . '/../../../images/circle.png', 'top-right', 0, 0));
$this->assertEquals('32250d', $image->pickColor(300, 25)->toHex());
}
public function testColorChangeOpacity(): void
{
$image = $this->readTestImage('test.jpg');
$this->assertEquals('febc44', $image->pickColor(300, 25)->toHex());
$image->modify(new PlaceModifier(__DIR__ . '/../../../images/circle.png', 'top-right', 0, 0, 50));
$this->assertEquals('987028', $image->pickColor(300, 25)->toHex());
}
}

View File

@@ -24,4 +24,12 @@ class PlaceModifierTest extends TestCase
$image->modify(new PlaceModifier(__DIR__ . '/../../../images/circle.png', 'top-right', 0, 0));
$this->assertEquals('33260e', $image->pickColor(300, 25)->toHex());
}
public function testColorChangeOpacity(): void
{
$image = $this->readTestImage('test.jpg');
$this->assertEquals('febc44', $image->pickColor(300, 25)->toHex());
$image->modify(new PlaceModifier(__DIR__ . '/../../../images/circle.png', 'top-right', 0, 0, 50));
$this->assertEquals('987129', $image->pickColor(300, 25)->toHex());
}
}