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


101

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

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

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

$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.png', 9 );

Answers:


199
imagealphablending( $targetImage, false );
imagesavealpha( $targetImage, true );

为我做了。谢谢ceejayoz。

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

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

$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.png', 9 );

5
FIY,这需要在创建目标图像之后进行。在这种情况下,将在imagecreatetruecolor之后。
RisingSun

想知道为什么alphablending = false在这里很重要?该文档指出:“您必须取消设置alphablending(imagealphablending($im, false))才能使用它。”
2014

2
这个答案不仅是正确和有用的,而且特别有用,因为关于PHP文档的第一条评论(在撰写本文时)imagecreatefrompng()建议imagealphablending应该设置true,这显然是错误的。非常感谢。
spikyjt 2014年

3
在我的情况下,这种解决方案仅在PNG具有“常规”透明区域(如周围的透明区域),GD具有复杂区域(例如具有透明图像的内部部分)的情况下才可以正常工作,并且始终放置黑色背景,例如,此图片失败:seomofo.com/downloads/new-google-logo-knockoff.png。有人可以尝试并确认吗?
aesede 2014年

2
似乎不适用于某些透明的png文件。我试图从jpg创建图像并在其中复制透明png。正如aesede指出的那样,结果是一个黑色正方形。
RubbelDeCatc 2015年

21

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

$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]);


正在尝试两种解决方案:您的解决方案以及上面获得150票以上的解决方案。您的解决方案非常适合GIF。上面的方法最适合PNG文件,而您的解决方案则失去了抗锯齿功能,您可以在创建缩略图时看到的效果最好(看起来块状,像素化)。
Jonny

11

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

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

编辑: PHP docs声明中的某人imagealphablending应为true,而不为false。YMMV。


2
使用imagealphablendingtrue或false总是得到黑色背景。
aesede 2014年

PHP7-为我工作
Yehonatan

玩过它(PHP 7.x):PNG:imagealphablending($ targetImage,false); //如果在PNG上为true,则为黑色背景; GIF:imagealphablending($ targetImage,true); //如果在GIF上为假:黑色背景
Jonny

9

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

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

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

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

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


6

我做了一个函数来调整JPEG / GIF / PNG等图像的大小,copyimageresample而PNG图像仍然保持透明:

$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;
}

3
仔细阅读所有代码以找出为什么在该代码中保留了透明性而不是问题中的代码是相当繁琐的。
eh9 2012年

我跳过了这两行,它仍然有效: $transparent = imagecolorallocatealpha($tmp, 255, 255, 255, 127); imagefilledrectangle($tmp, 0, 0, $newwidth, $newheight, $transparent);
圣地亚哥·亚利桑那2017年

这个答案看起来很像stackoverflow.com/a/279310/470749
瑞安

5

我想这可以解决问题:

$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.png', 9 );

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


如果您将颜色设置为极其丑陋,几乎没有图像会使用它,则将非常有帮助。
科里(Cory)2010年

1
接受的答案对我不起作用。使用此答案imagecreate(...)虽然有效。您创建一个图像,其中将填充您分配的第一种颜色。然后将颜色设置为透明。如果将目标图像的alphablending设置为true,则两个图像都将合并并且透明度可以正常工作。
Sumurai13年

2

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

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

  1. 您无需调用getimagesize()即可获取以下控件的宽度/高度imagecopyresmapled()
  2. $uploadWidth$uploadHeight-1的值,因为cordinates开始于0而不是1,所以这将它们复制到一个空像素。用:imagesx($targetImage) - 1和替换它imagesy($targetImage) - 1,就应该这样做:)

0

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

$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.png",1);

0

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


0

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

$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.png', 9);
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.