PHP'nin GDlib görüntü kopyası yeniden örneklendiğinde PNG görüntü şeffaflığı korunabilir mi?


101

Aşağıdaki PHP kod parçacığı, tarayıcı tarafından yüklenen bir PNG'yi 128x128 olarak yeniden boyutlandırmak için GD kullanır. Orijinal görüntüdeki saydam alanların benim durumumda düz bir renk-siyahla değiştirilmesi dışında harika çalışıyor.

imagesavealphaAyarlanmış olsa bile , bir şeyler pek doğru değil.

Yeniden örneklenen görüntüde şeffaflığı korumanın en iyi yolu nedir?

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

Yanıtlar:


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

benim için yaptı. Teşekkürler ceejayoz.

not, hedef görüntünün kaynak görüntüye değil alfa ayarlarına ihtiyacı vardır.

Düzenleme: tam değiştirme kodu. Ayrıca aşağıdaki cevaplara ve onların yorumlarına bakın. Bunun hiçbir şekilde mükemmel olacağı garanti edilmez, ancak o sırada ihtiyaçlarımı karşıladı.

$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, bunun hedef görüntü oluşturulduktan sonra olması gerekir. Bu durumda, imagecreatetruecolor'dan sonra olacaktır.
RisingSun

alphablending = falseBurada neden önemli olduğunu merak ediyor musunuz? Doküman şunu belirtir ... "Kullanmak için alphablending ( imagealphablending($im, false)) 'i kaldırmanız gerekir."
seksen beş

2
Sadece PHP dokümanlar üzerinde (yazma anda) ilk açıklama için çünkü özellikle yararlıdır, bu cevap doğru ve faydalı olduğunu imagecreatefrompng()düşündürmektedir imagealphablendingolmalıdır seti trueaçıkça yanlıştır. Çok teşekkürler.
spikyjt

3
Bu çözüm, benim durumumda GD YALNIZCA iyi çalışıyor, PNG çevreleyen saydam alan gibi "normal" bir saydamlık alanına sahipse ve görüntünün şeffaflık içeren iç kısımlarında olduğu gibi karmaşık bir alana sahipse, her zaman başarısız olur ve siyah arka plan koyar , örneğin bu resim başarısız olur: seomofo.com/downloads/new-google-logo-knockoff.png . Bunu deneyip onaylayan var mı?
aesede

2
Bazı şeffaf png dosyalarıyla çalışmıyor gibi görünüyor. Bir jpg'den bir resim oluşturmaya ve içine şeffaf bir png kopyalamaya çalıştım. Aesede'nin işaret ettiği gibi sonuç siyah bir karedir.
RubbelDeCatc

21

Neden işleri bu kadar karmaşık yapıyorsun? aşağıdaki benim kullandığım şey ve şu ana kadar benim için işi yaptı.

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

, Hala bu görüntü ile siyah bir arka plan değil işi aldın: seomofo.com/downloads/new-google-logo-knockoff.png
aesede

Her iki çözümü de deniyordum: sizinki ve 150'den fazla oy alan yukarıdaki çözüm. Çözümleriniz GIF'ler için harika çalışıyor. Yukarıdakiler en iyi PNG dosyalarıyla çalışırken, çözümünüz küçük resimler oluştururken en iyi görebildiğiniz şeyi (bloklu, pikselli görünüyor) kenar yumuşatmayı kaybederken.
Jonny

11

Bunun hile yapması gerektiğine inanıyorum:

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

edit: PHP docs iddialarında biri imagealphablendingyanlış değil doğru olmalıdır. YMMV.


2
imagealphablendingDoğru veya yanlış ile kullanmak her zaman siyah bir arka plan elde ederim.
aesede

PHP7 - Benim için Çalışma
Yehonatan

Bununla oynandı (PHP 7.x): PNG: imagealphablending ($ targetImage, false); // PNG'lerde doğruysa: siyah arka plan GIF: imagealphablending ($ targetImage, true); // GIF'lerde yanlışsa: siyah arka plan
Jonny

9

Bazı insanlara yardımcı olabilecek bir ek:

Görüntüyü oluştururken imagealphablending arasında geçiş yapmak mümkündür. Buna ihtiyacım olan özel durum, bazı yarı şeffaf PNG'leri şeffaf bir arka plan üzerinde birleştirmek istedim.

Önce imagealphablending'i false olarak ayarlarsınız ve yeni oluşturulan gerçek renkli görüntüyü şeffaf bir renkle doldurursunuz. Eğer imajalphablending doğru olsaydı, hiçbir şey olmazdı çünkü şeffaf dolgu siyah varsayılan arka plan ile birleşir ve siyah olur.

Daha sonra, görüntüyü doğruya çevirirsiniz ve bazı PNG görüntülerini tuvale eklersiniz, arka planın bir kısmını görünür halde bırakırsınız (yani, görüntünün tamamını doldurmazsınız).

Sonuç, şeffaf bir arka plana ve birleştirilmiş birkaç PNG görüntüsüne sahip bir görüntüdür.


6

JPEG / GIF / PNG gibi görüntüyü yeniden boyutlandırmak için bir işlev yaptım copyimageresampleve PNG görüntüleri hala şeffaflık sağlıyor:

$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
Bu kodda, sorudaki kod üzerinde neden şeffaflığın korunduğunu anlamak için tüm kodu okumak oldukça zahmetli.
eh9

Bunları iki satır atlanır ve hala çalıştı: $transparent = imagecolorallocatealpha($tmp, 255, 255, 255, 127); imagefilledrectangle($tmp, 0, 0, $newwidth, $newheight, $transparent);
santiago Arizti

Bu cevap, stackoverflow.com/a/279310/470749'a çok benziyor .
Ryan

5

Sanırım bu işe yarayabilir:

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

Olumsuz yanı, görüntünün her% 100 yeşil pikselden sıyrılmasıdır. Her neyse, umarım yardımcı olur :)


Neredeyse hiçbir görüntünün kullanmayacağı son derece çirkin bir renge ayarlarsanız, bu çok yardımcı olabilir.
Cory

1
Kabul edilen cevap benim için işe yaramadı. Bu cevabı kullanmak imagecreate(...)işe yaradı. Tahsis ettiğiniz ilk renkle doldurulan bir görüntü oluşturursunuz. Sonra bu rengi saydam olarak ayarlarsınız. Alfablending, hedef görüntü için doğru olarak ayarlanırsa, her iki görüntü de birleştirilir ve saydamlık doğru şekilde çalışır.
Sumurai8

2

Korunan şeffaflığı yeniden okunduktan sonra, diğer gönderilerde de belirtildiği gibi evet, imagesavealpha () doğru olarak ayarlanmalıdır, alfa bayrağını kullanmak için imagealphablending () false olarak ayarlanmalıdır, aksi takdirde çalışmaz.

Ayrıca kodunuzda iki küçük şey fark ettim:

  1. İçin getimagesize()genişlik / yükseklik almak için aramanıza gerek yokimagecopyresmapled()
  2. $uploadWidthVe $uploadHeightolmalıdır -1cordinates başlar beri, değer 0ve 1boş bir piksel içine kopyalamak diye. Şununla değiştirmek: imagesx($targetImage) - 1ve imagesy($targetImage) - 1göreceli olarak yapmalı :)

0

İşte toplam test kodum. Benim için çalışıyor

$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

İşleve aktarılan kaynak görüntülere widthve heightdeğerlere dikkat edin imagecopyresampled. Gerçek kaynak görüntü boyutundan daha büyüklerse, görüntü alanının geri kalanı siyah renkle doldurulacaktır.


0

Benim için en iyi sonucu veren ceejayoz ve Cheekysoft'un cevaplarını birleştirdim. İmagealphablending () ve imagesavealpha () olmadan görüntü net değildir:

$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);
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.