PHP:图像叠加,仅在底部图像不透明的情况下将顶部图像应用于底部图像

PHP: image overlay, applying top image to bottom image only where bottom image isn't transparent

提问人:Bill in Kansas City 提问时间:7/17/2023 更新时间:7/17/2023 访问量:34

问:

你用谷歌搜索过吗?是的,十几篇或更多文章。

你搜索过 SO 吗?是的,因为我正在输入我的问题,并且在此之前多次输入。

你搜索过PHP文档吗?是的。

我找到的信息都没有解决我要问的特定问题。

当您访问服装网站并为紧身裤等颜色选择时,只有服装的颜色会发生变化。这是相同的图像,只是对服装应用了滤镜。

我以前在PHP中见过这样做,所以我知道这是可能的。基础层,模型层,然后是具有透明背景的灰度服装。下一层是纯色或具有透明背景的图案,并与服装混合,以保留高光和阴影,然后将混合的服装图层叠加在模型上,模型叠加在背景上。

我尝试过 Imagick、GD 和几个库,但在每种情况下,彩色/图案覆盖层不仅限于服装:它显示为每一层上浮动的颜色/图案块。

COMPOSITE_ATOP让我部分到达那里,但阴影和高光没有显示出来。如何将叠加层限制为服装图层中的非透明像素?我错过了什么?(下图)

我包含了 Imagick 代码,因为它比 GD 更简洁,但此时我对任何事情都持开放态度。

<?php
// PHP8.1

$backgroundImage    = new Imagick('./img/background.png');
$shadows            = new Imagick('./img/feet.png');

$backgroundImage->compositeImage($shadows, Imagick::COMPOSITE_DEFAULT, 0, 0);

$rightleg            = new Imagick('./img/right-leg.png');
$w = $rightleg->getImageWidth();
$h = $rightleg->getImageHeight();

$image = new Imagick('./img/right-leg-color.png');

$rightleg->compositeImage($image,  Imagick::COMPOSITE_OVERLAY, 0, 0);

$backgroundImage->compositeImage($rightleg, Imagick::COMPOSITE_DEFAULT, 0, 0);

$leftleg            = new Imagick('./img/left-leg.png');
$backgroundImage->compositeImage($leftleg, Imagick::COMPOSITE_DEFAULT, 0, 0);

if (true) {
    header('Content-Type: image/png');
    echo $backgroundImage;
} else {
    $rightleg->writeImage('test.png');
}

// Clean up resources
$backgroundImage->clear();
$backgroundImage->destroy();
$shadows->clear();
$shadows->destroy();
$rightleg->clear();
$rightleg->destroy();
$leftleg->clear();
$leftleg->destroy();

Final result of the composite as of now

php imagick

评论


答:

0赞 Bill in Kansas City 7/17/2023 #1

这个问题的解决方案是使用 COMPOSITE_ATOP 将颜色放在目标的副本上:这具有类似蒙版的效果,其中颜色仅限于非透明像素。创建蒙版形状后,您可以将灰色原件合成到彩色蒙版图层上以应用光影。

$rightleg            = new Imagick('./img/right-leg.png');
$rightmask           = new Imagick('./img/right-leg.png');

$colorful = new Imagick('./img/right-leg-color.png');

// composite the colors over original element copy
$rightmask->compositeImage($colorful,  Imagick::COMPOSITE_ATOP, 0, 0);

// now apply highlights and shadows using the original element
$rightmask->compositeImage($rightleg,  Imagick::COMPOSITE_BUMPMAP, 0, 0);

如果有更好的方式,我愿意听到它,但这对我有用。

enter image description here