PNG สามารถรักษาความโปร่งใสของภาพเมื่อใช้ GDlib imagecopyresampled ของ PHP ได้หรือไม่


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

คำตอบ:


200
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

สงสัยว่าทำไมalphablending = falseที่นี่จึงสำคัญ? เอกสารระบุว่า ... "คุณต้องยกเลิกการตั้งค่าตัวอักษร ( imagealphablending($im, false)) จึงจะใช้ได้"
eightyfive

2
คำตอบนี้ไม่เพียง แต่ถูกต้องและมีประโยชน์เท่านั้น แต่ยังมีประโยชน์อย่างยิ่งเนื่องจากความคิดเห็นแรก (ในขณะที่เขียน) บนเอกสาร PHP สำหรับคำimagecreatefrompng()แนะนำที่imagealphablendingควรตั้งค่าtrueซึ่งผิดอย่างชัดเจน ขอบคุณมาก.
spikyjt

3
วิธีนี้ในกรณีของฉัน GD จะทำงานได้ดีก็ต่อเมื่อ PNG มีพื้นที่โปร่งใส "ปกติ" เช่นพื้นที่โปร่งใสโดยรอบหากมีพื้นที่ที่ซับซ้อนเช่นเดียวกับส่วนด้านในของภาพที่มีความโปร่งใสจะล้มเหลวเสมอและทำให้พื้นหลังเป็นสีดำ ยกตัวอย่างเช่นภาพนี้ล้มเหลว: seomofo.com/downloads/new-google-logo-knockoff.png มีใครลองยืนยันได้ไหม
aesede

2
ดูเหมือนจะไม่ทำงานกับไฟล์ png โปร่งใสบางไฟล์ ฉันพยายามสร้างภาพจาก jpg และคัดลอก png โปร่งใสภายใน ในฐานะที่เป็น aesede ชี้ให้เห็นผลลัพธ์คือสี่เหลี่ยมสีดำ
RubbelDeCatc

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 ไฟล์ข้างต้นทำงานได้ดีที่สุดกับไฟล์ PNG ในขณะที่โซลูชันของคุณกำลังสูญเสียการลบรอยหยักสิ่งที่คุณเห็นได้ดีที่สุดในการสร้างภาพขนาดย่อ (มีลักษณะเป็นบล็อคพิกเซล)
จอนนี่

11

ฉันเชื่อว่าสิ่งนี้ควรใช้เคล็ดลับ:

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

แก้ไข: มีคนอ้างสิทธิ์ในเอกสาร PHP imagealphablendingควรเป็นจริงไม่ใช่เท็จ YMMV.


2
ใช้imagealphablendingกับจริงหรือเท็จฉันมักจะได้พื้นหลังสีดำ
aesede

PHP7 - ทำงานให้ฉัน
Yehonatan

เล่นกับมัน (PHP 7.x): PNG: imagealphablending ($ targetImage, false); // ถ้าเป็นจริงใน PNGs: พื้นหลังสีดำ GIF: imagealphablending ($ targetImage, true); // if false on GIFs: black background
Jonny

9

นอกจากนี้ที่อาจช่วยบางคน:

เป็นไปได้ที่จะสลับการแสดงภาพในขณะที่สร้างภาพ ฉันเป็นกรณีเฉพาะที่ฉันต้องการสิ่งนี้ฉันต้องการรวม PNG แบบกึ่งโปร่งใสเข้ากับพื้นหลังโปร่งใส

ขั้นแรกให้คุณตั้งค่า imagealphablending เป็น false และเติมภาพสีจริงที่สร้างขึ้นใหม่ด้วยสีโปร่งใส หากการเรียงลำดับรูปภาพเป็นจริงจะไม่มีอะไรเกิดขึ้นเนื่องจากการเติมแบบโปร่งใสจะผสานเข้ากับพื้นหลังเริ่มต้นสีดำและส่งผลให้เป็นสีดำ

จากนั้นให้คุณสลับภาพเป็นจริงและเพิ่มภาพ 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
การอ่านโค้ดทั้งหมดค่อนข้างยุ่งยากเพื่อหาสาเหตุว่าทำไมความโปร่งใสจึงถูกเก็บรักษาไว้ในโค้ดนี้เหนือโค้ดในคำถาม
เอ๊ะ

ฉันข้ามสองบรรทัดนี้ไปแล้วและมันก็ยังใช้งานได้: $transparent = imagecolorallocatealpha($tmp, 255, 255, 255, 127); imagefilledrectangle($tmp, 0, 0, $newwidth, $newheight, $transparent);
santiago arizti

คำตอบนี้มีลักษณะมากเช่นstackoverflow.com/a/279310/470749
Ryan

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% หวังว่ามันจะช่วยได้ :)


หากคุณตั้งค่าเป็นสีที่น่าเกลียดมากจนแทบไม่มีภาพใดเลยที่จะใช้มันจะมีประโยชน์มาก
Cory

1
คำตอบที่ยอมรับไม่ได้ผลสำหรับฉัน ใช้คำตอบนี้กับการimagecreate(...)ทำงานแม้ว่า คุณสร้างภาพซึ่งเต็มไปด้วยสีแรกที่คุณจัดสรร จากนั้นตั้งค่าสีนั้นให้โปร่งใส หากตั้งค่าตัวอักษรเป็นจริงสำหรับภาพเป้าหมายภาพทั้งสองจะถูกรวมเข้าด้วยกันและความโปร่งใสจะทำงานได้อย่างถูกต้อง
Sumurai8

2

การจัดลำดับความโปร่งใสของการเก็บรักษาใหม่แล้วใช่เช่นเดียวกับที่ระบุไว้ในโพสต์อื่น ๆ imagesavealpha () ต้องตั้งค่าเป็นจริงเพื่อใช้ค่าสถานะอัลฟา imagealphablending () ต้องตั้งค่าเป็นเท็จมิฉะนั้นจะไม่ทำงาน

นอกจากนี้ฉันพบสิ่งเล็กน้อยสองอย่างในรหัสของคุณ:

  1. คุณไม่จำเป็นต้องเรียกgetimagesize()เพื่อรับความกว้าง / ความสูงสำหรับimagecopyresmapled()
  2. ค่า$uploadWidthและ$uploadHeightควรเป็น-1ค่าเนื่องจาก Cordinates เริ่มต้นที่0ไม่ใช่1ดังนั้นจึงจะคัดลอกไปยังพิกเซลว่าง แทนที่ด้วย: imagesx($targetImage) - 1และimagesy($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

ให้ความสนใจกับภาพต้นฉบับwidthและheightค่าที่ส่งผ่านไปยัง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.