Dapatkah transparansi gambar PNG dipertahankan saat menggunakan image copyresampled GDlib PHP?

101

Cuplikan kode PHP berikut menggunakan GD untuk mengubah ukuran PNG yang diunggah browser menjadi 128x128. Ini berfungsi dengan baik, kecuali bahwa area transparan pada gambar asli diganti dengan warna solid- hitam dalam kasus saya.

Meskipun imagesavealphasudah diatur, ada sesuatu yang tidak beres.

Apa cara terbaik untuk menjaga transparansi pada gambar yang telah diubah sampelnya?

$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
sumber

Jawaban:

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

melakukannya untuk saya. Terima kasih ceejayoz.

perhatikan, gambar target membutuhkan pengaturan alpha, bukan gambar sumber.

Edit: kode pengganti penuh. Lihat juga jawaban di bawah dan komentar mereka. Ini tidak dijamin sempurna dalam hal apa pun, tetapi memenuhi kebutuhan saya pada saat itu.

$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
sumber
5
FIY, ini harus dilakukan setelah gambar target dibuat. Dalam hal ini, itu akan menjadi setelah gambar-gambar yang indah.
RisingSun
Ingin tahu mengapa alphablending = falsepenting di sini? Doc menyatakan itu ... "Anda harus membatalkan alphablending ( imagealphablending($im, false)), untuk menggunakannya."
delapan puluh lima
2
Jawaban ini tidak hanya benar dan berguna, tetapi juga sangat membantu karena komentar pertama (pada saat penulisan) pada dokumen PHP imagecreatefrompng()menyarankan yang imagealphablendingharus disetel true, yang jelas salah. Terima kasih banyak.
spikyjt
3
Solusi ini, dalam kasus saya, GD berfungsi dengan baik HANYA jika PNG memiliki area transparansi "biasa", seperti area transparan di sekitarnya, jika memiliki area yang kompleks, seperti bagian dalam gambar dengan transparansi, selalu gagal dan menempatkan latar belakang hitam , misalnya gambar ini gagal: seomofo.com/downloads/new-google-logo-knockoff.png . Adakah yang bisa mencoba ini dan mengkonfirmasi?
aesede
2
Tampaknya tidak berfungsi dengan beberapa file png transparan. Saya mencoba membuat gambar dari jpg dan menyalin png transparan di dalamnya. Seperti yang ditunjukkan aesede, hasilnya adalah kotak hitam.
RubbelDeCatc
21

Mengapa Anda membuat hal-hal menjadi begitu rumit? berikut ini adalah apa yang saya gunakan dan sejauh ini telah berhasil untuk saya.

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

sumber
Tidak berhasil, saya masih mendapatkan latar belakang hitam dengan gambar ini: seomofo.com/downloads/new-google-logo-knockoff.png
aesede
Sedang mencoba kedua solusi: milik Anda dan yang di atas dengan lebih dari 150 suara. Solusi Anda berfungsi dengan baik untuk GIF. Yang di atas berfungsi paling baik dengan file PNG sementara solusi Anda kehilangan anti-aliasing apa yang dapat Anda lihat paling baik dalam membuat thumbnail (terlihat kuning, pixelated).
Jonny
11

Saya yakin ini akan berhasil:

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

edit: Klaim seseorang di dokumen PHP imagealphablendingseharusnya benar, bukan salah. YMMV.

ceejayoz
sumber
2
Menggunakan imagealphablendingbaik dengan benar atau salah saya selalu mendapatkan latar belakang hitam.
aesede
PHP7 - Bekerja untuk saya
Yehonatan
Bermain-main dengannya (PHP 7.x): PNG: imagealphablending ($ targetImage, false); // jika true pada PNG: GIF latar belakang hitam: imagealphablending ($ targetImage, true); // jika salah pada GIF: latar belakang hitam
Jonny
9

Tambahan yang mungkin membantu beberapa orang:

Hal ini dimungkinkan untuk mengubah gambaralphablending sambil membangun gambar. Saya kasus khusus yang saya butuhkan ini, saya ingin menggabungkan beberapa PNG semi-transparan pada latar belakang transparan.

Pertama Anda mengatur imagealphablending ke false dan mengisi gambar warna asli yang baru dibuat dengan warna transparan. Jika imagealphablending benar, tidak ada yang akan terjadi karena isian transparan akan bergabung dengan latar belakang default hitam dan menghasilkan hitam.

Kemudian Anda mengubah gambar menjadi berubah menjadi true dan menambahkan beberapa gambar PNG ke kanvas, membiarkan beberapa latar belakang terlihat (yaitu. Tidak memenuhi seluruh gambar).

Hasilnya adalah gambar dengan latar transparan dan beberapa gambar PNG gabungan.

Jorrit Schippers
sumber
6

Saya telah membuat fungsi untuk mengubah ukuran gambar seperti JPEG / GIF / PNG dengan copyimageresampledan gambar PNG tetap menjaga transparansi:

$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
sumber
3
Agak sulit untuk membaca semua kode untuk mencari tahu mengapa transparansi dipertahankan dalam kode ini di atas kode dalam pertanyaan.
eh9
Saya melewatkan dua baris ini dan masih berhasil: $transparent = imagecolorallocatealpha($tmp, 255, 255, 255, 127); imagefilledrectangle($tmp, 0, 0, $newwidth, $newheight, $transparent);
santiago arizti
Jawaban ini sangat mirip dengan stackoverflow.com/a/279310/470749 .
Ryan
5

Saya kira ini mungkin berhasil:

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

Sisi negatifnya adalah bahwa gambar akan dihilangkan dari setiap 100% piksel hijau. Bagaimanapun, semoga membantu :)

Linus Unnebäck
sumber
Jika Anda menyetel ke warna yang sangat jelek sehingga hampir tidak ada gambar yang menggunakannya, itu bisa sangat membantu.
Cory
1
Jawaban yang diterima tidak berhasil untuk saya. Menggunakan jawaban ini dengan imagecreate(...)berhasil. Anda membuat gambar, yang diisi dengan warna pertama yang Anda alokasikan. Kemudian Anda mengatur warna itu menjadi transparan. Jika alphablending diatur ke true untuk gambar target, kedua gambar akan digabungkan dan transparansi berfungsi dengan benar.
Sumurai8
2

Regrading menjaga transparansi, maka ya seperti yang dinyatakan dalam posting lain imagesavealpha () harus disetel ke true, untuk menggunakan bendera alpha imagealphablending () harus disetel ke false jika tidak itu tidak berfungsi.

Saya juga melihat dua hal kecil di kode Anda:

  1. Anda tidak perlu memanggil getimagesize()untuk mendapatkan lebar / tinggiimagecopyresmapled()
  2. The $uploadWidthdan $uploadHeightharus -1nilai, karena cordinates dimulai pada 0dan tidak 1, sehingga akan menyalinnya ke dalam pixel kosong. Menggantinya dengan: imagesx($targetImage) - 1dan imagesy($targetImage) - 1, secara relatif harus dilakukan :)
Kalle
sumber
0

Ini adalah total kode tes saya. Ini bekerja untuk saya

$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
sumber
0

Perhatikan gambar sumber widthdan heightnilai yang diteruskan ke imagecopyresampledfungsi. Jika lebih besar dari ukuran gambar sumber sebenarnya, area gambar lainnya akan diisi dengan warna hitam.

Stefan
sumber
0

Saya menggabungkan jawaban dari ceejayoz dan Cheekysoft, yang memberikan hasil terbaik untuk saya. Tanpa imagealphablending () dan imagesavealpha () gambar tidak jelas:

$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
sumber