mirror of
https://github.com/Intervention/image.git
synced 2025-08-12 17:03:59 +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:
@@ -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,18 +27,93 @@ class PlaceModifier extends DriverSpecialized implements ModifierInterface
|
||||
|
||||
foreach ($image as $frame) {
|
||||
imagealphablending($frame->native(), true);
|
||||
imagecopy(
|
||||
$frame->native(),
|
||||
$watermark->core()->native(),
|
||||
$position->x(),
|
||||
$position->y(),
|
||||
0,
|
||||
0,
|
||||
$watermark->width(),
|
||||
$watermark->height()
|
||||
);
|
||||
|
||||
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(),
|
||||
$position->x(),
|
||||
$position->y(),
|
||||
0,
|
||||
0,
|
||||
$watermark->width(),
|
||||
$watermark->height()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@@ -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(),
|
||||
|
@@ -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));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -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;
|
||||
|
||||
/**
|
||||
|
@@ -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
|
||||
) {
|
||||
}
|
||||
|
||||
|
@@ -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());
|
||||
}
|
||||
}
|
||||
|
@@ -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());
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user