PHP中如何替换透明颜色

5

我有一组图片。其中包含绿色透明色。我需要将透明颜色替换为另一种颜色(我想换成白色透明色)。

这是我的代码:

$img = imagecreatefrompng($path . $file); 
$white_color_transparent = imagecolorallocatealpha($img, 255, 255, 255, 127);
for ($y = 0; $y < imagesy($img); $y++) {
    for ($x = 0; $x < imagesx($img); $x++) {
        $rgb = imagecolorat($img, $x, $y);
        $pixel_color = imagecolorsforindex($img, $rgb);
        if ($pixel_color['alpha'] != 0 && $pixel_color['alpha'] != 127){
            imagesetpixel($img, $x, $y, $white_color_transparent);
        }
    }
}

imagealphablending($img, false);
imagesavealpha($img, true);            
imagepng($img, $path .  $file);

我的结果颜色和原始图片的ID相同,当我在前面添加时。
imagesetpixel($img, $x, $y, $white_color_transparent);

那一行:
imagesetpixel($img, $x, $y, $white_color);

我只得到了白色而没有透明度。

2
你能提供一个输入样本图像吗? - lorenzo-s
一个样本图像会非常有用! - mpratt
2个回答

19

如果没有看到你的图像,我不确定有没有容易的方法可以做到这一点。

编辑2:

我从我的第一个编辑中注意到一件事情,那就是它对于具有透明度并且没有不透明层的图像不起作用。

这是我尝试处理具有一些透明度的图像的方式。正如你可以从示例中看到的那样。它并没有完美地解决问题。

<?php
//These colors here are the rgba values of the green transparency I used in my test image. You will need to know this to reverse the rgb blending.
$red = 28;
$green = 198;
$blue = 72;
$alpha = .48;

$img = imagecreatefrompng('test.png');

//Adding in the image blending that Zombaya brought up. Need this so it overwrites the pixel instead of blending it
imagealphablending($img, false);
for ($y = 0; $y < imagesy($img); $y++) {
    for ($x = 0; $x < imagesx($img); $x++) {
        $rgb = imagecolorat($img, $x, $y);
        $pixel_color = imagecolorsforindex($img, $rgb);

        //If pixel color matches our alpha layer color, we change it white transparent
        //Not sure how accurate the rounding for the alpha conversion is. Maybe the reason for the green edges in this example:
        if($pixel_color['red'] == $red && 
            $pixel_color['green'] == $green &&
            $pixel_color['blue'] == $blue &&
            $pixel_color['alpha'] == round(127 - ($alpha * 127))){
            $color = imagecolorallocatealpha($img, 255, 255, 255, 127);
        } else {
            //This is the algorithm from the link. But reordered to get the old color before the transparent color went over it.
            $oldR = ($pixel_color['red'] - $alpha * $red) /  (1 - $alpha);
            $oldG = ($pixel_color['green'] - $alpha * $green ) / (1 - $alpha);
            $oldB = ($pixel_color['blue'] - $alpha * $blue) / (1 - $alpha);

            $color = imagecolorallocatealpha($img, $oldR, $oldG, $oldB, $pixel_color['alpha']);
        }
        imagesetpixel($img, $x, $y, $color);
    }
}
imagesavealpha($img, true);            
imagepng($img, 'test_result.png');

在没有透明度的情况下的原始图像 -> 原始图像(无透明度)

以透明度开始的图像-> 以透明度开始的图像

生成的图像。请注意绿色边缘。我可能会很幸运地使用相似的不透明度来表示红色和绿色。白色部分是透明的 -> 生成的图像。请注意绿色边缘。我可能会很幸运地使用相似的不透明度来表示红色和绿色。白色部分是透明的

编辑:

我考虑了一些,并遇到了这个链接:如何通过指定alpha混合量计算RGB颜色?

这帮助我理解如何解决你的问题。尽管这取决于您是否只有一个在图像上透明的实心颜色。如果是渐变则更加困难。

<?php
//These colors here are the rgba values of the green transparency I used in my test image. You will need to know this to reverse the rgb blending.
$red = 44;
$green = 215;
$blue = 56;
$alpha = .45;

$img = imagecreatefrompng('test2.png');

for ($y = 0; $y < imagesy($img); $y++) {
    for ($x = 0; $x < imagesx($img); $x++) {
        $rgb = imagecolorat($img, $x, $y);
        $pixel_color = imagecolorsforindex($img, $rgb);
            //This is the algorithm from the link. But reordered to get the old color before the transparent color went over it.
        $oldR = ($pixel_color['red'] - $alpha * $red) /  (1 - $alpha);
        $oldG = ($pixel_color['green'] - $alpha * $green ) / (1 - $alpha);
        $oldB = ($pixel_color['blue'] - $alpha * $blue) / (1 - $alpha);

        $color = imagecolorallocate($img, $oldR, $oldG, $oldB);
        imagesetpixel($img, $x, $y, $color);
    }
}
imagesavealpha($img, true);            
imagepng($img, 'test_result.png');

enter image description here - 起始图像

enter image description here - 改变后的图像

上面代码中使用的rgb计算方法的解释如下。链接显示了基本公式:

out = alpha * new + (1 - alpha) * old

out 是原始颜色与新颜色混合后的结果颜色。

因此,我们需要重新排列公式以获得旧颜色,具体如下:

old = (out - alpha * new) / (1 - alpha)

旧答案:

为什么这行代码不起作用:

$white_color_transparent = imagecolorallocatealpha($img, 255, 255, 255, 127);

127表示完全透明,这意味着它是不可见的。这就是为什么结果图像与起始图像相同的原因。

为什么这行代码会创建一个完全白色的图像:

$white_color = imagecolorallocatealpha($img, 255, 255, 255, 0); 
或者
$white_color = imagecolorallocate($img, 255, 255, 255);

这基本上只是在所选像素上放置一个白色像素(0表示无透明度),这就是为什么所选像素变成完全白色的原因。

现在,如果你执行以下操作:

$white_color_semi_transparent = imagecolorallocatealpha($img, 255, 255, 255, 40); 

不要用半透明的白色替换透明的绿色,现在你得到了一种浅绿色而不是半透明的白色。

看我的测试例子:

Starting Image - 开始的图像

enter image description here - 具有颜色255,255,255,40的结果图像

所以这告诉我们两件事:

  1. 首先是颜色基本上是应用在现有像素的颜色之上的,因此变成了浅的透明绿色而不是透明的白色。
  2. 其次,请注意,棕色部分没有受到影响。棕色部分实际上是在绿色不透明层下面的不透明红色颜色。这说明图像没有考虑像Photoshop那样的图层,基本上将棕色颜色读作棕色,而不是在绿色透明颜色后面的红色颜色。这是有道理的,因为PNG文件不带有图层信息。

我不确定如何解决您的问题。这取决于您的图像。我认为可以获得所需的着色,但是对于比如我的两个有两种颜色的重叠正方形与一张照片之类的更复杂的图像来说,它显然会更加困难。


0

我使用Gohn67的图像作为工作对象。

诀窍是在尝试变换图像之前关闭alpha混合。这样,您可以使用imagesetpixel()将像素设置为您想要的确切值。

根据imagealphablending手册:

在非混合模式下,绘画颜色与其alpha通道信息一起被精确地复制到目标像素上。

这导致了以下代码:

$img = imagecreatefrompng($path.$file);
imagealphablending($img, false); // Turn off blending
$white_color_transparent = imagecolorallocatealpha($img, 255, 255, 255, 127);
for ($y = 0; $y < imagesy($img); $y++) {
    for ($x = 0; $x < imagesx($img); $x++) {
        $rgb = imagecolorat($img, $x, $y);
        $pixel_color = imagecolorsforindex($img, $rgb);
        if ($pixel_color['alpha'] != 0 && $pixel_color['alpha'] != 127){
            imagesetpixel($img, $x, $y, $white_color_transparent);
        }
    }
}
imagesavealpha($img, true);            
imagepng($img, $path.$file);

原始图像

original image

生成的图像

生成的图像
(这里实际上是透明的背景,但无法看到)

我想说的是,现在它用完全透明的白色替换了所有透明颜色。如果您希望将所有有色透明度替换为具有相同 alpha 值的透明白色,则可以执行以下操作:

imagesetpixel($img, $x, $y, imagecolorallocatealpha($img, 255, 255, 255, $pixel_color['alpha']));

为了仅选择绿色透明像素,我会计算每个像素的色调并检查它是否落在指定范围内。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接