用PHP替换透明色

时间:2012-04-20 12:28:19

标签: php png gd alpha-transparency

我有一组图像。在此图像中存在绿色alpha颜色。我需要将透明色替换为另一种颜色(我想要替换为白色alpha颜色)。

我的代码:

$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 个答案:

答案 0 :(得分:18)

如果没有看到你的形象,我不确定是否有一种简单的方法可以做到。

编辑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');

enter image description here - &gt;原始没有透明度

enter image description here - &GT;以透明度开始图像

enter image description here - &gt;得到的图像。注意绿色边缘。对于红色和绿色使用相似的不透明度,我可能会很幸运。白色部分是透明的

编辑:

我更多地考虑了这一点,并且我发现了这个链接:How to calculate an RGB colour by specifying an alpha blending amount?

这有助于我了解如何解决您的问题。虽然这取决于您是否只有一个在图像上透明的纯色。如果是渐变则更难。

<?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)

OLD ANSWER:

为什么这条线不起作用:

$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文件不带有图层信息。
  3. 我不确定你是如何解决问题的。这取决于你的形象。我认为可以获得你想要的颜色,但显然你的图像越复杂就越难。例如,我的两个重叠的正方形有两种颜色,而不是照片。

答案 1 :(得分: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

产生的图像

resulting image
(背景实际上是透明的,但在这里无法看到)

我想说现在,它用这种完全透明的白色取代所有透明色。如果您希望使用具有相同alpha值的透明白色替换所有彩色透明度,则可以执行以下操作:

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

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