A transparência da imagem PNG pode ser preservada ao usar o imagecopyresampled GDlib do PHP?

StackOverflow https://stackoverflow.com/questions/32243

Pergunta

O seguinte trecho de código PHP usa GD para redimensionar um PNG carregado pelo navegador para 128x128.Funciona muito bem, exceto que as áreas transparentes da imagem original estão sendo substituídas por uma cor sólida – preto no meu caso.

Embora imagesavealpha está definido, algo não está certo.

Qual é a melhor maneira de preservar a transparência na imagem reamostrada?

$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 );
Foi útil?

Solução

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

fez isso por mim.Obrigado ceejayoz.

observe que a imagem de destino precisa das configurações alfa, não da imagem de origem.

Editar:código de substituição completo.Veja também as respostas abaixo e seus comentários.Não há garantia de que seja perfeito de forma alguma, mas atendeu às minhas necessidades na época.

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

Outras dicas

Por que você complica tanto as coisas?o seguinte é o que eu uso e até agora fez o trabalho para mim.

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

Eu acredito que isso deve funcionar:

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

editar: Alguém nos documentos do PHP afirma imagealphablending deveria ser verdadeira e não falsa.YMMV.

Uma adição que pode ajudar algumas pessoas:

É possível alternar a finalização alfabética da imagem durante a construção da imagem.No caso específico em que precisava disso, queria combinar alguns PNGs semitransparentes em um fundo transparente.

Primeiro você define imagealphablending como false e preenche a imagem true color recém-criada com uma cor transparente.Se imagealphablending fosse verdadeiro, nada aconteceria porque o preenchimento transparente se fundiria com o fundo preto padrão e resultaria em preto.

Em seguida, você alterna o imagealphablending para true e adiciona algumas imagens PNG à tela, deixando parte do fundo visível (ou seja,não preenchendo a imagem inteira).

O resultado é uma imagem com fundo transparente e várias imagens PNG combinadas.

Eu criei uma função para redimensionar imagens como JPEG/GIF/PNG com copyimageresample e as imagens PNG ainda mantêm sua transparência:

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

Suponho que isso possa resolver o problema:

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

A desvantagem é que a imagem será despojada de todos os pixels 100% verdes.De qualquer forma, espero que ajude :)

Reclassificando a transparência de preservação, então sim, como afirmado em outras postagens, imagesavealpha() deve ser definido como verdadeiro, para usar o sinalizador alfa, imagealphablending() deve ser definido como falso, caso contrário não funciona.

Também descobri duas pequenas coisas no seu código:

  1. Você não precisa ligar getimagesize() para obter a largura/altura de imagecopyresmapled()
  2. O $uploadWidth e $uploadHeight deveria estar -1 o valor, já que as coordenadas começam em 0 e não 1, então ele os copiaria em um pixel vazio.Substituindo por: imagesx($targetImage) - 1 e imagesy($targetImage) - 1, relativamente deveria servir :)

Aqui está meu código de teste total.Funciona para mim

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

Preste atenção à imagem de origem width e height valores que são passados ​​para imagecopyresampled função.Se forem maiores que o tamanho real da imagem de origem, o restante da área da imagem será preenchido com cor preta.

Combinei as respostas do ceejayoz e do Cheekysoft, que deram o melhor resultado para mim.Sem imagealphablending() e imagesavealpha() a imagem não fica clara:

$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);
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top