Skip to content

Commit ecafa80

Browse files
[2.3-develop] Forwardport of #11060
1 parent 15d1a96 commit ecafa80

File tree

5 files changed

+177
-20
lines changed

5 files changed

+177
-20
lines changed

dev/tests/integration/testsuite/Magento/Framework/Image/Adapter/InterfaceTest.php

Lines changed: 94 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -337,6 +337,97 @@ public function rotateDataProvider()
337337
);
338338
}
339339

340+
/**
341+
* Test if alpha transparency is correctly handled
342+
*
343+
* @param string $image
344+
* @param string $watermark
345+
* @param int $alphaPercentage
346+
* @param array $comparePoint1
347+
* @param array $comparePoint2
348+
* @param string $adapterType
349+
*
350+
* @dataProvider imageWatermarkWithAlphaTransparencyDataProvider
351+
* @depends testOpen
352+
* @depends testImageSize
353+
*/
354+
public function testWatermarkWithAlphaTransparency(
355+
$image,
356+
$watermark,
357+
$alphaPercentage,
358+
$comparePoint1,
359+
$comparePoint2,
360+
$adapterType
361+
) {
362+
$imageAdapter = $this->_getAdapter($adapterType);
363+
$imageAdapter->open($image);
364+
365+
$watermarkAdapter = $this->_getAdapter($adapterType);
366+
$watermarkAdapter->open($watermark);
367+
368+
list($comparePoint1X, $comparePoint1Y) = $comparePoint1;
369+
list($comparePoint2X, $comparePoint2Y) = $comparePoint2;
370+
371+
$imageAdapter
372+
->setWatermarkImageOpacity($alphaPercentage)
373+
->setWatermarkPosition(\Magento\Framework\Image\Adapter\AbstractAdapter::POSITION_TOP_LEFT)
374+
->watermark($watermark);
375+
376+
$comparePoint1Color = $imageAdapter->getColorAt($comparePoint1X, $comparePoint1Y);
377+
unset($comparePoint1Color['alpha']);
378+
379+
$comparePoint2Color = $imageAdapter->getColorAt($comparePoint2X, $comparePoint2Y);
380+
unset($comparePoint2Color['alpha']);
381+
382+
$result = $this->_compareColors($comparePoint1Color, $comparePoint2Color);
383+
$message = sprintf(
384+
'%s should be different to %s due to alpha transparency',
385+
join(',', $comparePoint1Color),
386+
join(',', $comparePoint2Color)
387+
);
388+
$this->assertFalse($result, $message);
389+
}
390+
391+
public function imageWatermarkWithAlphaTransparencyDataProvider()
392+
{
393+
return $this->_prepareData(
394+
[
395+
// Watermark with alpha channel, 25%
396+
[
397+
$this->_getFixture('watermark_alpha_base_image.jpg'),
398+
$this->_getFixture('watermark_alpha.png'),
399+
25,
400+
[ 23, 3 ],
401+
[ 23, 30 ]
402+
],
403+
// Watermark with alpha channel, 50%
404+
[
405+
$this->_getFixture('watermark_alpha_base_image.jpg'),
406+
$this->_getFixture('watermark_alpha.png'),
407+
50,
408+
[ 23, 3 ],
409+
[ 23, 30 ]
410+
],
411+
// Watermark with no alpha channel, 50%
412+
[
413+
$this->_getFixture('watermark_alpha_base_image.jpg'),
414+
$this->_getFixture('watermark.png'),
415+
50,
416+
[ 3, 3 ],
417+
[ 23,3 ]
418+
],
419+
// Watermark with no alpha channel, 100%
420+
[
421+
$this->_getFixture('watermark_alpha_base_image.jpg'),
422+
$this->_getFixture('watermark.png'),
423+
100,
424+
[ 3, 3 ],
425+
[ 3, 60 ]
426+
],
427+
]
428+
);
429+
}
430+
340431
/**
341432
* Checks if watermark exists on the right position
342433
*
@@ -350,10 +441,10 @@ public function rotateDataProvider()
350441
* @param int $colorY
351442
* @param string $adapterType
352443
*
353-
* @dataProvider imageWatermarkDataProvider
444+
* @dataProvider imageWatermarkPositionDataProvider
354445
* @depends testOpen
355446
*/
356-
public function testWatermark(
447+
public function testWatermarkPosition(
357448
$image,
358449
$watermark,
359450
$width,
@@ -387,7 +478,7 @@ public function testWatermark(
387478
$this->assertFalse($result, $message);
388479
}
389480

390-
public function imageWatermarkDataProvider()
481+
public function imageWatermarkPositionDataProvider()
391482
{
392483
return $this->_prepareData(
393484
[
Loading
Loading

lib/internal/Magento/Framework/Image/Adapter/Gd2.php

Lines changed: 72 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -407,7 +407,7 @@ public function rotate($angle)
407407
*/
408408
public function watermark($imagePath, $positionX = 0, $positionY = 0, $opacity = 30, $tile = false)
409409
{
410-
list($watermarkSrcWidth, $watermarkSrcHeight, $watermarkFileType, ) = $this->_getImageOptions($imagePath);
410+
list($watermarkSrcWidth, $watermarkSrcHeight, $watermarkFileType,) = $this->_getImageOptions($imagePath);
411411
$this->_getFileAttributes();
412412
$watermark = call_user_func(
413413
$this->_getCallback('create', $watermarkFileType, 'Unsupported watermark image format.'),
@@ -468,7 +468,7 @@ public function watermark($imagePath, $positionX = 0, $positionY = 0, $opacity =
468468
} elseif ($this->getWatermarkPosition() == self::POSITION_CENTER) {
469469
$positionX = $this->_imageSrcWidth / 2 - imagesx($watermark) / 2;
470470
$positionY = $this->_imageSrcHeight / 2 - imagesy($watermark) / 2;
471-
imagecopymerge(
471+
$this->imagecopymergeWithAlphaFix(
472472
$this->_imageHandler,
473473
$watermark,
474474
$positionX,
@@ -481,7 +481,7 @@ public function watermark($imagePath, $positionX = 0, $positionY = 0, $opacity =
481481
);
482482
} elseif ($this->getWatermarkPosition() == self::POSITION_TOP_RIGHT) {
483483
$positionX = $this->_imageSrcWidth - imagesx($watermark);
484-
imagecopymerge(
484+
$this->imagecopymergeWithAlphaFix(
485485
$this->_imageHandler,
486486
$watermark,
487487
$positionX,
@@ -493,7 +493,7 @@ public function watermark($imagePath, $positionX = 0, $positionY = 0, $opacity =
493493
$this->getWatermarkImageOpacity()
494494
);
495495
} elseif ($this->getWatermarkPosition() == self::POSITION_TOP_LEFT) {
496-
imagecopymerge(
496+
$this->imagecopymergeWithAlphaFix(
497497
$this->_imageHandler,
498498
$watermark,
499499
$positionX,
@@ -507,7 +507,7 @@ public function watermark($imagePath, $positionX = 0, $positionY = 0, $opacity =
507507
} elseif ($this->getWatermarkPosition() == self::POSITION_BOTTOM_RIGHT) {
508508
$positionX = $this->_imageSrcWidth - imagesx($watermark);
509509
$positionY = $this->_imageSrcHeight - imagesy($watermark);
510-
imagecopymerge(
510+
$this->imagecopymergeWithAlphaFix(
511511
$this->_imageHandler,
512512
$watermark,
513513
$positionX,
@@ -520,7 +520,7 @@ public function watermark($imagePath, $positionX = 0, $positionY = 0, $opacity =
520520
);
521521
} elseif ($this->getWatermarkPosition() == self::POSITION_BOTTOM_LEFT) {
522522
$positionY = $this->_imageSrcHeight - imagesy($watermark);
523-
imagecopymerge(
523+
$this->imagecopymergeWithAlphaFix(
524524
$this->_imageHandler,
525525
$watermark,
526526
$positionX,
@@ -534,7 +534,7 @@ public function watermark($imagePath, $positionX = 0, $positionY = 0, $opacity =
534534
}
535535

536536
if ($tile === false && $merged === false) {
537-
imagecopymerge(
537+
$this->imagecopymergeWithAlphaFix(
538538
$this->_imageHandler,
539539
$watermark,
540540
$positionX,
@@ -550,7 +550,7 @@ public function watermark($imagePath, $positionX = 0, $positionY = 0, $opacity =
550550
$offsetY = $positionY;
551551
while ($offsetY <= $this->_imageSrcHeight + imagesy($watermark)) {
552552
while ($offsetX <= $this->_imageSrcWidth + imagesx($watermark)) {
553-
imagecopymerge(
553+
$this->imagecopymergeWithAlphaFix(
554554
$this->_imageHandler,
555555
$watermark,
556556
$offsetX,
@@ -781,4 +781,68 @@ protected function _createEmptyImage($width, $height)
781781
$this->imageDestroy();
782782
$this->_imageHandler = $image;
783783
}
784+
785+
/**
786+
* Fix an issue with the usage of imagecopymerge where the alpha channel is lost
787+
*
788+
* @param resource $dst_im
789+
* @param resource $src_im
790+
* @param int $dst_x
791+
* @param int $dst_y
792+
* @param int $src_x
793+
* @param int $src_y
794+
* @param int $src_w
795+
* @param int $src_h
796+
* @param int $pct
797+
*
798+
* @return bool
799+
*/
800+
private function imagecopymergeWithAlphaFix(
801+
$dst_im,
802+
$src_im,
803+
$dst_x,
804+
$dst_y,
805+
$src_x,
806+
$src_y,
807+
$src_w,
808+
$src_h,
809+
$pct
810+
) {
811+
if ($pct >= 100) {
812+
return imagecopy($dst_im, $src_im, $dst_x, $dst_y, $src_x, $src_y, $src_w, $src_h);
813+
}
814+
815+
if ($pct < 0) {
816+
return false;
817+
}
818+
819+
$sizeX = imagesx($src_im);
820+
$sizeY = imagesy($src_im);
821+
if (false === $sizeX || false === $sizeY) {
822+
return false;
823+
}
824+
825+
$tmpImg = imagecreatetruecolor($src_w, $src_h);
826+
if (false === $tmpImg) {
827+
return false;
828+
}
829+
830+
if (false === imagealphablending($tmpImg, false)) {
831+
return false;
832+
}
833+
834+
if (false === imagecopy($tmpImg, $src_im, 0, 0, 0, 0, $sizeX, $sizeY)) {
835+
return false;
836+
}
837+
838+
$transparancy = 127 - (($pct*127)/100);
839+
if (false === imagefilter($tmpImg, IMG_FILTER_COLORIZE, 0, 0, 0, $transparancy)) {
840+
return false;
841+
}
842+
843+
$result = imagecopy($dst_im, $tmpImg, $dst_x, $dst_y, $src_x, $src_y, $src_w, $src_h);
844+
imagedestroy($tmpImg);
845+
846+
return $result;
847+
}
784848
}

lib/internal/Magento/Framework/Image/Adapter/ImageMagick.php

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -269,15 +269,17 @@ public function watermark($imagePath, $positionX = 0, $positionY = 0, $opacity =
269269
);
270270
}
271271

272-
if (method_exists($watermark, 'setImageOpacity')) {
273-
// available from imagick 6.3.1
274-
$watermark->setImageOpacity($opacity);
275-
} else {
276-
// go to each pixel and make it transparent
277-
$watermark->paintTransparentImage($watermark->getImagePixelColor(0, 0), 1, 65530);
278-
$watermark->evaluateImage(\Imagick::EVALUATE_SUBTRACT, 1 - $opacity, \Imagick::CHANNEL_ALPHA);
272+
if (method_exists($watermark, 'getImageAlphaChannel')) {
273+
// available from imagick 6.4.0
274+
if ($watermark->getImageAlphaChannel() == 0) {
275+
$watermark->setImageAlphaChannel(\Imagick::ALPHACHANNEL_OPAQUE);
276+
}
279277
}
280278

279+
$compositeChannels = \Imagick::CHANNEL_ALL;
280+
$watermark->evaluateImage(\Imagick::EVALUATE_MULTIPLY, $opacity, \Imagick::CHANNEL_OPACITY);
281+
$compositeChannels &= ~(\Imagick::CHANNEL_OPACITY);
282+
281283
switch ($this->getWatermarkPosition()) {
282284
case self::POSITION_STRETCH:
283285
$watermark->sampleImage($this->_imageSrcWidth, $this->_imageSrcHeight);
@@ -309,14 +311,14 @@ public function watermark($imagePath, $positionX = 0, $positionY = 0, $opacity =
309311
$offsetY = $positionY;
310312
while ($offsetY <= $this->_imageSrcHeight + $watermark->getImageHeight()) {
311313
while ($offsetX <= $this->_imageSrcWidth + $watermark->getImageWidth()) {
312-
$this->_imageHandler->compositeImage($watermark, \Imagick::COMPOSITE_OVER, $offsetX, $offsetY);
314+
$this->_imageHandler->compositeImage($watermark, \Imagick::COMPOSITE_OVER, $offsetX, $offsetY, $compositeChannels);
313315
$offsetX += $watermark->getImageWidth();
314316
}
315317
$offsetX = $positionX;
316318
$offsetY += $watermark->getImageHeight();
317319
}
318320
} else {
319-
$this->_imageHandler->compositeImage($watermark, \Imagick::COMPOSITE_OVER, $positionX, $positionY);
321+
$this->_imageHandler->compositeImage($watermark, \Imagick::COMPOSITE_OVER, $positionX, $positionY, $compositeChannels);
320322
}
321323
} catch (\ImagickException $e) {
322324
throw new \Exception('Unable to create watermark.', $e->getCode(), $e);

0 commit comments

Comments
 (0)