PHPのGDlib imagecopyresampledを使用する場合、PNG画像の透明度を維持できますか?


101

次のPHPコードスニペットは、GDを使用して、ブラウザにアップロードされたPNGを128x128にサイズ変更します。元の画像の透明な領域が私の場合は黒一色に置き換えられていることを除いて、それは素晴らしい働きをします。

imagesavealphaセットされているのに、何かがおかしい。

リサンプリングされた画像の透明度を維持する最良の方法は何ですか?

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

回答:


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

私のためにやった。ありがとうceejayoz。

ターゲット画像には、ソース画像ではなくアルファ設定が必要であることに注意してください。

編集:完全な置換コード。以下の回答とそのコメントも参照してください。これは決して完璧であるとは限りませんが、当時の私のニーズを満たしました。

$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、これはターゲットイメージが作成された後である必要があります。この場合、それはimagecreatetruecolorの後です。
RisingSun 2013

alphablending = falseここでなぜ重要なのでしょうか。文書には、imagealphablending($im, false)それを使用するには、alphablending()の設定を解除する必要があります。」
85年

2
この回答は正確で有用であるだけでなく、PHPドキュメントの最初のコメント(執筆時)がを設定imagecreatefrompng()するimagealphablending必要があることを示唆しているので特に役立ちますがtrue、これは明らかに間違っています。どうもありがとうございました。
spikyjt 2014

3
この解決策、私の場合、GDは、PNGに「通常の」透明領域(周囲の透明領域など)がある場合にのみ正常に機能します。画像の内部に透明部分があるなど、複雑な領域がある場合、常に失敗し、黒い背景が表示されます。たとえば、次の画像は失敗します:seomofo.com/downloads/new-google-logo-knockoff.png。誰かがこれを試して確認できますか?
aesede 2014

2
一部の透明なpngファイルでは動作しないようです。jpgから画像を作成し、内部に透明なpngをコピーしようとしました。aesedeが指摘するように、結果は黒い四角になります。
RubbelDeCatc 2015年

21

なぜあなたは物事をそんなに複雑にするのですか?以下は私が使用しているもので、これまでのところ私のために仕事をしてくれました。

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

動作しませんでした。この画像の背景が黒のままです:seomofo.com/downloads/new-google-logo-knockoff.png
aesede

両方の解決策を試してみました:あなたの解決策と上記の解決策は150票を超えました ソリューションはGIFに最適です。上記の1つはPNGファイルで最適に機能しますが、ソリューションはサムネイルの作成で最もよく見えるもの(ブロック状、ピクセル化されたように見える)のアンチエイリアスを失います。
ジョニー2017

11

私はこれでうまくいくと思います:

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

編集: PHPドキュメントの主張の誰かは、imagealphablending偽ではなく真であるべきです。YMMV。


2
imagealphablendingtrueまたはfalseのいずれかを使用すると、常に黒い背景になります。
aesede 2014

PHP7 -私のために働い
Yehonatan

それをいじってみました(PHP 7.x):PNG:imagealphablending($ targetImage、false); // PNGでtrueの場合:黒の背景GIF:imagealphablending($ targetImage、true); // GIFがfalseの場合:黒の背景
ジョニー2017

9

一部の人々を助けるかもしれない追加:

画像の構築中にimagealphablendingを切り替えることができます。私はこれが必要な特定のケースで、透明な背景にいくつかの半透明のPNGを組み合わせたかったのです。

まず、imagealphablendingをfalseに設定し、新しく作成されたTrue Color画像を透明色で塗りつぶします。imagealphablendingがtrueの場合、透明な塗りつぶしがデフォルトの黒の背景と結合して黒になるため、何も起こりません。

次に、imagealphablendingをtrueに切り替えて、いくつかのPNG画像をキャンバスに追加し、背景の一部を表示したままにします(つまり、画像全体を塗りつぶしません)。

結果は、透明な背景といくつかの結合されたPNG画像を持つ画像です。


6

JPEG / GIF / PNGのような画像のサイズを変更する機能を作成しましたがcopyimageresample、PNG画像は透明性を保ちます:

$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
問題のコードに対してこのコードで透過性が維持される理由を理解するためにすべてのコードを読むのはかなり面倒です。
eh9

私はこれらの2行をスキップしましたが、それでも機能しました: $transparent = imagecolorallocatealpha($tmp, 255, 255, 255, 127); imagefilledrectangle($tmp, 0, 0, $newwidth, $newheight, $transparent);
santiago arizti

この回答は、stackoverflow.com / a / 279310/470749によく似ています。
ライアン

5

私はこれがトリックをするかもしれないと思います:

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

欠点は、画像から100%緑のピクセルがすべて取り除かれるということです。とにかく、それが役に立てば幸い:)


画像がほとんど使用されないような非常に醜い色に設定すると、非常に役立ちます。
コリー

1
受け入れられた答えは私にとってはうまくいきませんでした。とimagecreate(...)はいえ、この答えを使ってうまくいきました。割り当てた最初の色で塗りつぶされる画像を作成します。次に、その色を透明に設定します。ターゲット画像のalphablendingがtrueに設定されている場合、両方の画像がマージされ、透明度が正しく機能します。
Sumurai8 2013年

2

透明度の保持を再調整し、他の投稿で述べたように、アルファフラグを使用するには、imagesavealpha()をtrueに設定する必要があります。imagealphablending()をfalseに設定する必要があります。

また、私はあなたのコードに2つの小さなことを見つけました:

  1. getimagesize()の幅/高さを取得するために呼び出す必要はありませんimagecopyresmapled()
  2. あるべきcordinatesがで始まるため、値ではなく、それは空のピクセルにそれらをコピーするので、。でそれを置き換える:と、relativily行う必要があります:)$uploadWidth$uploadHeight-101imagesx($targetImage) - 1imagesy($targetImage) - 1

0

これが私の合計テストコードです。わたしにはできる

$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

関数に渡されるソース画像widthheight値に注意してくださいimagecopyresampled。実際のソース画像サイズよりも大きい場合、残りの画像領域は黒色で塗りつぶされます。


0

ceejayozとCheekysoftの回答を組み合わせたので、最高の結果が得られました。imagealphablending()とimagesavealpha()を使用しない場合、画像は明確ではありません。

$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);
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.