Kann die PNG-Bildtransparenz bei Verwendung der GDlib-Bildkopie von PHP beibehalten werden?

101

Das folgende PHP-Code-Snippet verwendet GD, um die Größe eines vom Browser hochgeladenen PNG auf 128 x 128 zu ändern. Es funktioniert hervorragend, außer dass die transparenten Bereiche im Originalbild in meinem Fall durch einfarbiges Schwarz ersetzt werden.

Obwohl imagesavealphafestgelegt, stimmt etwas nicht ganz.

Was ist der beste Weg, um die Transparenz im neu abgetasteten Bild zu erhalten?

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

Antworten:

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

habe es für mich getan. Danke ceejayoz.

Beachten Sie, dass das Zielbild die Alpha-Einstellungen benötigt, nicht das Quellbild.

Bearbeiten: vollständiger Ersatzcode. Siehe auch die Antworten unten und ihre Kommentare. Dies ist in keiner Weise garantiert perfekt, hat aber meine damaligen Bedürfnisse erfüllt.

$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 );
Cheekysoft
quelle
5
FIY, dies muss sein, nachdem das Zielbild erstellt wurde. In diesem Fall wäre es nach imagecreatetruecolor.
RisingSun
Fragen Sie sich, warum hier alphablending = falsewichtig ist? Das Dokument gibt es an ... "Sie müssen alphablending ( imagealphablending($im, false)) deaktivieren , um es zu verwenden."
fünfundachtzig
2
Diese Antwort ist nicht nur richtig und nützlich, sondern auch besonders hilfreich, da der erste Kommentar (zum Zeitpunkt des Schreibens) in den PHP-Dokumenten für imagecreatefrompng()vorschlägt, dass imagealphablendingdies festgelegt werden sollte true, was eindeutig falsch ist. Vielen Dank.
Spikyjt
3
Diese Lösung, in meinem Fall GD, funktioniert NUR, wenn PNG einen "regulären" Transparenzbereich hat, wie einen umgebenden transparenten Bereich, wenn es einen komplexen Bereich hat, wie bei inneren Teilen des Bildes mit Transparenz, schlägt es immer fehl und setzt schwarzen Hintergrund Dieses Bild schlägt beispielsweise fehl: seomofo.com/downloads/new-google-logo-knockoff.png . Kann jemand dies versuchen und bestätigen?
Aesede
2
Scheint mit einigen transparenten PNG-Dateien nicht zu funktionieren. Ich habe versucht, ein Bild aus einem JPG zu erstellen und ein transparentes PNG darin zu kopieren. Wie Aesede betont, ist das Ergebnis ein schwarzes Quadrat.
RubbelDeCatc
21

Warum machst du die Dinge so kompliziert? Folgendes verwende ich und bisher hat es die Arbeit für mich erledigt.

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

quelle
Hat nicht funktioniert, ich bekomme immer noch schwarzen Hintergrund mit diesem Bild: seomofo.com/downloads/new-google-logo-knockoff.png
aesede
Ich habe beide Lösungen ausprobiert: Ihre und die oben genannte mit über 150 Stimmen. Ihre Lösungen eignen sich hervorragend für GIFs. Das obige funktioniert am besten mit PNG-Dateien, während Ihre Lösung das Anti-Aliasing verliert, was Sie beim Erstellen von Miniaturansichten am besten sehen können (sieht blockig und pixelig aus).
Jonny
11

Ich glaube, das sollte den Trick machen:

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

Bearbeiten: Jemand in den PHP-Dokumenten Behauptungen imagealphablendingsollte wahr sein, nicht falsch. YMMV.

ceejayoz
quelle
2
Wenn imagealphablendingich entweder mit wahr oder falsch benutze, bekomme ich immer einen schwarzen Hintergrund.
Aesede
PHP7 - Arbeiten für mich
Yehonatan
Spielte damit herum (PHP 7.x): PNG: imagealphablending ($ targetImage, false); // wenn wahr auf PNGs: schwarzer Hintergrund GIF: imagealphablending ($ targetImage, true); // wenn falsch auf GIFs: schwarzer Hintergrund
Jonny
9

Eine Ergänzung, die einigen Menschen helfen könnte:

Es ist möglich, die Bildbearbeitung beim Erstellen des Bildes umzuschalten. In dem speziellen Fall, in dem ich dies brauchte, wollte ich einige halbtransparente PNGs auf einem transparenten Hintergrund kombinieren.

Zuerst setzen Sie imagealphablending auf false und füllen das neu erstellte True-Color-Bild mit einer transparenten Farbe. Wenn imagealphablending wahr wäre, würde nichts passieren, da die transparente Füllung mit dem schwarzen Standardhintergrund verschmelzen und zu Schwarz führen würde.

Dann schalten Sie imagealphablending auf true um und fügen der Leinwand einige PNG-Bilder hinzu, wobei ein Teil des Hintergrunds sichtbar bleibt (dh nicht das gesamte Bild ausfüllt).

Das Ergebnis ist ein Bild mit transparentem Hintergrund und mehreren kombinierten PNG-Bildern.

Jorrit Schippers
quelle
6

Ich habe eine Funktion zum Ändern der Bildgröße wie JPEG / GIF / PNG mit copyimageresampleund PNG-Bilder haben immer noch Transparenz:

$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;
}
pricopz
quelle
3
Es ist ziemlich mühsam, den gesamten Code durchzulesen, um herauszufinden, warum in diesem Code Transparenz über den fraglichen Code erhalten bleibt.
eh9
Ich habe diese beiden Zeilen übersprungen und es hat immer noch funktioniert: $transparent = imagecolorallocatealpha($tmp, 255, 255, 255, 127); imagefilledrectangle($tmp, 0, 0, $newwidth, $newheight, $transparent);
Santiago Arizona
Diese Antwort ähnelt sehr der Funktion stackoverflow.com/a/279310/470749 .
Ryan
5

Ich nehme an, dass dies den Trick tun könnte:

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

Der Nachteil ist, dass das Bild alle 100% grünen Pixel entfernt wird. Wie auch immer, hoffe es hilft :)

Linus Unnebäck
quelle
Wenn Sie eine extrem hässliche Farbe einstellen, die fast kein Bild verwenden würde, kann dies sehr hilfreich sein.
Cory
1
Die akzeptierte Antwort hat bei mir nicht funktioniert. Die Verwendung dieser Antwort hat jedoch imagecreate(...)funktioniert. Sie erstellen ein Bild, das mit der ersten Farbe gefüllt wird, die Sie zuweisen. Dann setzen Sie diese Farbe auf transparent. Wenn Alphablending für das Zielbild auf true gesetzt ist, werden beide Bilder zusammengeführt und die Transparenz funktioniert ordnungsgemäß.
Sumurai8
2

Wenn die Transparenz beibehalten wird, muss ja, wie in anderen Posts angegeben, imagesavealpha () auf true gesetzt werden, um das Alpha-Flag imagealphablending () zu verwenden, muss false gesetzt werden, sonst funktioniert es nicht.

Außerdem habe ich in Ihrem Code zwei kleinere Dinge entdeckt:

  1. Sie müssen nicht anrufen getimagesize(), um die Breite / Höhe für zu erhaltenimagecopyresmapled()
  2. Das $uploadWidthund $uploadHeightsollte -1der Wert sein, da die Koordinaten bei beginnen 0und nicht 1, damit sie in ein leeres Pixel kopiert werden. Ersetzen Sie es durch: imagesx($targetImage) - 1und imagesy($targetImage) - 1sollte es relativ tun :)
Kalle
quelle
0

Hier ist mein gesamter Testcode. Für mich geht das

$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);
Md. Imadul Islam
quelle
0

Achten Sie auf die Quellbilder widthund heightWerte, die an die imagecopyresampledFunktion übergeben werden. Wenn sie größer als die tatsächliche Quellbildgröße sind, wird der Rest des Bildbereichs mit schwarzer Farbe gefüllt.

Stefan
quelle
0

Ich kombinierte die Antworten von Ceejayoz und Cheekysoft, was das beste Ergebnis für mich ergab. Ohne imagealphablending () und imagesavealpha () ist das Bild nicht klar:

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