使用PHP的GDlib imagecopy重新采样时,能否保留PNG图像的透明度?

使用PHP的GDlib imagecopy重新采样时,能否保留PNG图像的透明度?

Can PNG image transparency be preserved when using PHP's GDlib imagecopyresampled?

以下PHP代码段使用GD将浏览器上传的PNG调整为128x128。 效果很好,只是在我的情况下,原始图像中的透明区域已被替换为纯黑色。

即使设置了imagesavealpha,也不是很正确。

在重新采样的图像中保留透明度的最佳方法是什么?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
$uploadTempFile = $myField[ 'tmp_name' ]
list( $uploadWidth, $uploadHeight, $uploadType )
  = getimagesize( $uploadTempFile );

$srcImage = imagecreatefrompng( $uploadTempFile );    
imagesavealpha( $targetImage, true );

$targetImage = imagecreatetruecolor( 128, 128 );
imagecopyresampled( $targetImage, $srcImage,
                    0, 0,
                    0, 0,
                    128, 128,
                    $uploadWidth, $uploadHeight );

imagepng(  $targetImage, 'out.webp', 9 );

1
2
imagealphablending( $targetImage, false );
imagesavealpha( $targetImage, true );

为我做了。谢谢ceejayoz。

请注意,目标图像需要Alpha设置,而不是源图像。

编辑:
完整的替换代码。另请参见下面的答案及其评论。不能保证这是完美的,但确实满足了我的需求。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
$uploadTempFile = $myField[ 'tmp_name' ]
list( $uploadWidth, $uploadHeight, $uploadType )
  = getimagesize( $uploadTempFile );

$srcImage = imagecreatefrompng( $uploadTempFile );

$targetImage = imagecreatetruecolor( 128, 128 );  
imagealphablending( $targetImage, false );
imagesavealpha( $targetImage, true );

imagecopyresampled( $targetImage, $srcImage,
                    0, 0,
                    0, 0,
                    128, 128,
                    $uploadWidth, $uploadHeight );

imagepng(  $targetImage, 'out.webp', 9 );

你为什么使事情变得如此复杂?以下是我使用的内容,到目前为止,它已经为我完成了工作。

1
2
3
4
$im = ImageCreateFromPNG($source);
$new_im = imagecreatetruecolor($new_size[0],$new_size[1]);
imagecolortransparent($new_im, imagecolorallocate($new_im, 0, 0, 0));
imagecopyresampled($new_im,$im,0,0,0,0,$new_size[0],$new_size[1],$size[0],$size[1]);

我相信这应该可以解决问题:

1
2
3
$srcImage = imagecreatefrompng($uploadTempFile);
imagealphablending($srcImage, false);
imagesavealpha($srcImage, true);

编辑:PHP文档中有人声称imagealphablending应该为true,而不为false。 YMMV。


可能对某些人有帮助的附加功能:

构建图像时可以切换图像alpha混合。对于我需要的特定情况,我想在透明背景上结合一些半透明的PNG。

首先,将imagealphablending设置为false,然后用透明颜色填充新创建的真彩色图像。如果imagealphablending为true,则不会发生任何事情,因为透明填充将与黑色默认背景合并并产生黑色。

然后,将imagealphablending切换为true,然后向画布中添加一些PNG图像,使某些背景可见(即,不会填满整个图像)。

结果是具有透明背景的图像和多个组合的PNG图像。


我提供了一个功能,可以使用copyimageresample调整JPEG / GIF / PNG等图像的大小,而PNG图像仍保持透明:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
$myfile=$_FILES["youimage"];

function ismyimage($myfile) {
    if((($myfile["type"] =="image/gif") || ($myfile["type"] =="image/jpg") || ($myfile["type"] =="image/jpeg") || ($myfile["type"] =="image/png")) && ($myfile["size"] <= 2097152 /*2mb*/) ) return true;
    else return false;
}

function upload_file($myfile) {        
    if(ismyimage($myfile)) {
        $information=getimagesize($myfile["tmp_name"]);
        $mywidth=$information[0];
        $myheight=$information[1];

        $newwidth=$mywidth;
        $newheight=$myheight;
        while(($newwidth > 600) || ($newheight > 400 )) {
            $newwidth = $newwidth-ceil($newwidth/100);
            $newheight = $newheight-ceil($newheight/100);
        }

        $files=$myfile["name"];

        if($myfile["type"] =="image/gif") {
            $tmp=imagecreatetruecolor($newwidth,$newheight);
            $src=imagecreatefromgif($myfile["tmp_name"]);
            imagecopyresampled($tmp, $src, 0, 0, 0, 0, $newwidth, $newheight, $mywidth, $myheight);
            $con=imagegif($tmp, $files);
            imagedestroy($tmp);
            imagedestroy($src);
            if($con){
                return true;
            } else {
                return false;
            }
        } else if(($myfile["type"] =="image/jpg") || ($myfile["type"] =="image/jpeg") ) {
            $tmp=imagecreatetruecolor($newwidth,$newheight);
            $src=imagecreatefromjpeg($myfile["tmp_name"]);
            imagecopyresampled($tmp, $src, 0, 0, 0, 0, $newwidth, $newheight, $mywidth, $myheight);
            $con=imagejpeg($tmp, $files);
            imagedestroy($tmp);
            imagedestroy($src);
            if($con) {  
                return true;
            } else {
                return false;
            }
        } else if($myfile["type"] =="image/png") {
            $tmp=imagecreatetruecolor($newwidth,$newheight);
            $src=imagecreatefrompng($myfile["tmp_name"]);
            imagealphablending($tmp, false);
            imagesavealpha($tmp,true);
            $transparent = imagecolorallocatealpha($tmp, 255, 255, 255, 127);
            imagefilledrectangle($tmp, 0, 0, $newwidth, $newheight, $transparent);
            imagecopyresampled($tmp, $src, 0, 0, 0, 0, $newwidth, $newheight, $mywidth, $myheight);
            $con=imagepng($tmp, $files);
            imagedestroy($tmp);
            imagedestroy($src);
            if($con) {
                return true;
            } else {
                return false;
            }
        }  
    } else
          return false;
}

我想这可以解决问题:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
$uploadTempFile = $myField[ 'tmp_name' ]
list( $uploadWidth, $uploadHeight, $uploadType )
  = getimagesize( $uploadTempFile );

$srcImage = imagecreatefrompng( $uploadTempFile );

$targetImage = imagecreatetruecolor( 128, 128 );

$transparent = imagecolorallocate($targetImage,0,255,0);
imagecolortransparent($targetImage,$transparent);
imagefilledrectangle($targetImage,0,0,127,127,$transparent);

imagecopyresampled( $targetImage, $srcImage,
                    0, 0,
                    0, 0,
                    128, 128,
                    $uploadWidth, $uploadHeight );

imagepng(  $targetImage, 'out.webp', 9 );

缺点是图像将每100%绿色像素被剥离。无论如何,希望对您有所帮助:)


重新设置保留透明性,然后像其他文章中所述,必须将imageavealpha()设置为true,才能使用alpha标志imagealphablending()必须设置为false,否则它将不起作用。

另外,我在您的代码中发现了两个小问题:

  • 您无需调用getimagesize()即可获取imagecopyresmapled()的宽度/高度
  • $uploadWidth$uploadHeight应该是-1的值,因为坐标是从0而不是1开始的,因此它将它们复制到一个空像素中。替换为:imagesx($targetImage) - 1imagesy($targetImage) - 1,应该适当地:)

  • 我结合了ceejayoz和Cheekysoft的答案,这对我来说是最好的结果。如果没有imagealphablending()和imagesavealpha(),则图像不清晰:

    1
    2
    3
    4
    5
    6
    $img3 = imagecreatetruecolor(128, 128);
    imagecolortransparent($img3, imagecolorallocate($img3, 0, 0, 0));
    imagealphablending( $img3, false );
    imagesavealpha( $img3, true );
    imagecopyresampled($img3, $srcImage, 0, 0, 0, 0, 128, 128, $uploadWidth, $uploadHeight);
    imagepng($img3, 'filename.webp', 9);

    请注意传递给imagecopyresampled函数的源图像的widthheight值。如果它们大于实际的源图像大小,则图像的其余区域将填充为黑色。


    这是我的总测试代码。这个对我有用

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    $imageFileType = pathinfo($_FILES["image"]["name"], PATHINFO_EXTENSION);
    $filename = 'test.' . $imageFileType;
    move_uploaded_file($_FILES["image"]["tmp_name"], $filename);

    $source_image = imagecreatefromjpeg($filename);

    $source_imagex = imagesx($source_image);
    $source_imagey = imagesy($source_image);

    $dest_imagex = 400;
    $dest_imagey = 600;
    $dest_image = imagecreatetruecolor($dest_imagex, $dest_imagey);

    imagecopyresampled($dest_image, $source_image, 0, 0, 0, 0, $dest_imagex, $dest_imagey, $source_imagex, $source_imagey);

    imagesavealpha($dest_image, true);
    $trans_colour = imagecolorallocatealpha($dest_image, 0, 0, 0, 127);
    imagefill($dest_image, 0, 0, $trans_colour);

    imagepng($dest_image,"test1.webp",1);


    推荐阅读