La trasparenza dell'immagine PNG può essere preservata quando si utilizza la ricampionatura GDlib di PHP?


101

Il seguente frammento di codice PHP utilizza GD per ridimensionare un PNG caricato dal browser a 128x128. Funziona benissimo, tranne per il fatto che le aree trasparenti nell'immagine originale vengono sostituite con un colore nero solido nel mio caso.

Anche se imagesavealphaè impostato, qualcosa non va bene.

Qual è il modo migliore per preservare la trasparenza nell'immagine ricampionata?

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

Risposte:


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

l'ha fatto per me. Grazie ceejayoz.

nota, l'immagine di destinazione richiede le impostazioni alfa, non l'immagine di origine.

Modifica: codice sostitutivo completo. Vedi anche le risposte di seguito ei loro commenti. Non è garantito che sia perfetto in alcun modo, ma ha soddisfatto le mie esigenze in quel momento.

$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, questo deve essere dopo che l'immagine di destinazione è stata creata. In questo caso, sarebbe dopo imagecreatetruecolor.
RisingSun

Ti chiedi perché è alphablending = falseimportante qui? Il documento afferma che ... "Devi disattivare alphablending ( imagealphablending($im, false)), per usarlo."
ottantacinque

2
Non solo questa risposta è corretta e utile, ma è particolarmente utile perché il primo commento (al momento della stesura) sulla documentazione PHP imagecreatefrompng()suggerisce che imagealphablendingdovrebbe essere impostato true, il che è chiaramente sbagliato. Grazie mille
spikyjt

3
Questa soluzione, nel mio caso GD funziona bene SOLO se PNG ha un'area di trasparenza "regolare", come un'area trasparente circostante, se ha un'area complessa, come le parti interne dell'immagine con trasparenza, fallisce sempre e mette lo sfondo nero , ad esempio questa immagine non riesce: seomofo.com/downloads/new-google-logo-knockoff.png . Qualcuno può provarlo e confermare?
aesede

2
Non sembra funzionare con alcuni file png trasparenti. Ho provato a creare un'immagine da un jpg e copiare un png trasparente all'interno. Come sottolinea Aesede, il risultato è un quadrato nero.
RubbelDeCatc

21

Perché rendi le cose così complicate? quello che segue è quello che uso e finora ha fatto il lavoro per me.

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

Non ha funzionato, ottengo ancora lo sfondo nero con questa immagine: seomofo.com/downloads/new-google-logo-knockoff.png
aesede

Stavo provando entrambe le soluzioni: la tua e quella sopra con oltre 150 voti. Le tue soluzioni funzionano alla grande per le GIF. Quello sopra funziona meglio con i file PNG mentre la tua soluzione sta perdendo l'anti-aliasing ciò che puoi vedere meglio durante la creazione di miniature (sembra a blocchi, pixelato).
Jonny

11

Credo che questo dovrebbe fare il trucco:

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

modifica: qualcuno nelle affermazioni dei documenti PHP imagealphablendingdovrebbe essere vero, non falso. YMMV.


2
Usando imagealphablendingsia vero che falso ottengo sempre uno sfondo nero.
aesede

PHP7 - Working for me
Yehonatan

Ci ho giocato (PHP 7.x): PNG: imagealphablending ($ targetImage, false); // se true su PNG: sfondo nero GIF: imagealphablending ($ targetImage, true); // se false sulle GIF: sfondo nero
Jonny

9

Un'aggiunta che potrebbe aiutare alcune persone:

È possibile attivare o disattivare il mutamento dell'immagine durante la creazione dell'immagine. Nel caso specifico in cui ne avevo bisogno, volevo combinare alcuni PNG semitrasparenti su uno sfondo trasparente.

Per prima cosa imposti imagealphablending su false e riempi la nuova immagine True Color con un colore trasparente. Se imagealphablending fosse vero, non accadrebbe nulla perché il riempimento trasparente si fonderebbe con lo sfondo nero predefinito e risulterebbe nero.

Quindi si passa a imagealphablending su true e si aggiungono alcune immagini PNG alla tela, lasciando visibile parte dello sfondo (cioè non riempiendo l'intera immagine).

Il risultato è un'immagine con uno sfondo trasparente e diverse immagini PNG combinate.


6

Ho creato una funzione per ridimensionare un'immagine come JPEG / GIF / PNG con copyimageresamplee le immagini PNG mantengono ancora la trasparenza:

$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
È piuttosto oneroso leggere tutto il codice per capire perché la trasparenza è preservata in questo codice rispetto al codice nella domanda.
eh9

Ho saltato queste due righe e ha funzionato ancora: $transparent = imagecolorallocatealpha($tmp, 255, 255, 255, 127); imagefilledrectangle($tmp, 0, 0, $newwidth, $newheight, $transparent);
santiago arizti

Questa risposta assomiglia molto a stackoverflow.com/a/279310/470749 .
Ryan,

5

Suppongo che questo potrebbe fare il trucco:

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

Lo svantaggio è che l'immagine verrà spogliata di ogni pixel verde al 100%. Comunque, spero che aiuti :)


Se imposti un colore estremamente brutto che quasi nessuna immagine utilizzerebbe, può essere molto utile.
Cory

1
La risposta accettata non ha funzionato per me. Usare questa risposta con ha imagecreate(...)funzionato però. Crei un'immagine, che viene riempita con il primo colore che assegni. Quindi imposti quel colore su trasparente. Se alphablending è impostato su true per l'immagine di destinazione, entrambe le immagini verranno unite e la trasparenza funzionerà correttamente.
Sumurai8

2

Regolando la trasparenza di conservazione, allora sì, come affermato in altri post, imagesavealpha () deve essere impostato su true, per usare il flag alpha imagealphablending () deve essere impostato su false altrimenti non funziona.

Inoltre ho notato due cose minori nel tuo codice:

  1. Non è necessario chiamare getimagesize()per ottenere la larghezza / altezza perimagecopyresmapled()
  2. La $uploadWidthe $uploadHeightdovrebbe essere -1il valore, in quanto le cordinate inizia a 0e non 1, quindi li copia in un pixel vuoto. Sostituendolo con: imagesx($targetImage) - 1e imagesy($targetImage) - 1, relativamente dovrebbe fare :)

0

Ecco il mio codice di prova totale. Per me funziona

$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

Presta attenzione all'immagine sorgente widthe ai heightvalori che vengono passati alla imagecopyresampledfunzione. Se sono più grandi della dimensione effettiva dell'immagine sorgente, il resto dell'area dell'immagine verrà riempita di colore nero.


0

Ho combinato le risposte di ceejayoz e Cheekysoft, che hanno dato il miglior risultato per me. Senza imagealphablending () e imagesavealpha () l'immagine non è chiara:

$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);
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.