我注意到Imagick::paintOpaqueImage
仅对alpha值为1的像素进行操作。这会使转换后的图像留下大量剩余的I' m试图替换的像素。以此测试图像为例
此代码用蓝色像素替换蓝色像素。
$img->paintOpaqueImage('rgb(12,0,245)', 'rgb(255,0,0)', 0);
结果只是替换了纯蓝色像素。
注意该测试图像中的所有像素(除了完全透明的像素)都是相同的蓝色。唯一的区别是alpha值。另请注意,我为$fuzz
参数使用了值0。在我发现真正的问题之前,我最初碰到了这一点,这导致了它自己的不良结果。
我使用ImagickPixelIterator
将解决方案整合在一起;它clones
当前像素,并将当前像素和克隆像素的alpha值设置为1,以强制ImagickPixel::isSimilar
在alpha值方面非常有效地工作。
$img = new Imagick('./test-paint-opaque-image.png');
$iterator = new ImagickPixelIterator($img);
$target = new ImagickPixel('rgb(12,0,245)'); // blue
$fill = new ImagickPixel('rgb(255,0,0)'); // red
$fuzz = 0;
foreach($iterator as $pixels) {
foreach($pixels as $curPixel) {
// Modify the alpha of the comparePixel so it won't throw off the isSimilar() check
$comparePixel = clone $curPixel;
$fOrigAlpha = $curPixel->getColorValue(Imagick::COLOR_ALPHA);
// Bail on fully transparent pixels
if($fOrigAlpha == 0)
continue;
// It seems the only way isSimilar will work is when the alpha is 1 for both pixels...
$comparePixel->setColorValue(Imagick::COLOR_ALPHA, 1);
$curPixel->setColorValue(Imagick::COLOR_ALPHA, 1);
if($comparePixel->isSimilar($target, $fuzz)) {
$curPixel->setColorValue(Imagick::COLOR_RED, $fill->getColorValue(Imagick::COLOR_RED));
$curPixel->setColorValue(Imagick::COLOR_GREEN, $fill->getColorValue(Imagick::COLOR_GREEN));
$curPixel->setColorValue(Imagick::COLOR_BLUE, $fill->getColorValue(Imagick::COLOR_BLUE));
// Set the modified alpha back to what it was after the color change
if($fOrigAlpha > 0) {
echo "Setting alpha to $fOrigAlpha\n";
$curPixel->setColorValue(Imagick::COLOR_ALPHA, $fOrigAlpha);
}
}
}
$iterator->syncIterator();
}
结果是一个闪亮的红色图像,保留了半透明(和完全透明)的像素。
主要问题,最后让我想到的问题是这种方法很慢。有没有办法直接使用PHP Imagick::paintOpaqueImage
进行这种颜色转换?