Có thể giữ nguyên độ trong suốt của hình ảnh PNG khi sử dụng hình ảnh GDlib của PHP được lấy mẫu không?


101

Đoạn mã PHP sau sử dụng GD để thay đổi kích thước PNG do trình duyệt tải lên thành 128x128. Nó hoạt động tốt, ngoại trừ việc các vùng trong suốt trong hình ảnh gốc đang được thay thế bằng một màu đen đặc trong trường hợp của tôi.

Mặc dù đã imagesavealphađược thiết lập, nhưng có điều gì đó không hoàn toàn đúng.

Cách tốt nhất để duy trì độ trong suốt của hình ảnh được lấy mẫu lại là gì?

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

Câu trả lời:


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

đã làm điều đó cho tôi. Cảm ơn ceejayoz.

lưu ý, hình ảnh đích cần cài đặt alpha, không phải hình ảnh nguồn.

Chỉnh sửa: mã thay thế đầy đủ. Xem thêm câu trả lời bên dưới và nhận xét của họ. Điều này không được đảm bảo là hoàn hảo theo bất kỳ cách nào, nhưng đã đạt được nhu cầu của tôi vào thời điểm đó.

$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, điều này cần phải được thực hiện sau khi hình ảnh đích đã được tạo. Trong trường hợp này, nó sẽ là sau hình ảnh tưởng tượng.
RisingSun

Tự hỏi tại sao lại alphablending = falsequan trọng ở đây? Tài liệu nói rằng ... "Bạn phải hủy đặt bảng chữ cái ( imagealphablending($im, false)), để sử dụng nó."
tám mươi lăm

2
Câu trả lời này không chỉ đúng và hữu ích mà còn đặc biệt hữu ích vì nhận xét đầu tiên (tại thời điểm viết bài) trên tài liệu PHP cho imagecreatefrompng()gợi ý rằng imagealphablendingnên đặt true, điều này rõ ràng là sai. Cảm ơn nhiều.
spikyjt

3
Giải pháp này, trong trường hợp của tôi, GD chỉ hoạt động tốt nếu PNG có vùng trong suốt "thông thường", giống như vùng trong suốt xung quanh, nếu nó có vùng phức tạp, như với các phần bên trong của hình ảnh có độ trong suốt, nó luôn không thành công và đặt nền đen , ví dụ như hình ảnh này không thành công: seomofo.com/downloads/new-google-logo-knockoff.png . Ai có thể thử điều này và xác nhận?
aesede

2
Dường như không hoạt động với một số tệp png trong suốt. Tôi đã cố gắng tạo một hình ảnh từ jpg và sao chép một png trong suốt bên trong. Khi aesede chỉ ra kết quả là một hình vuông màu đen.
RubbelDeCatc

21

Tại sao bạn làm cho mọi thứ trở nên phức tạp? sau đây là những gì tôi sử dụng và cho đến nay nó đã thực hiện công việc cho tôi.

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

Không hoạt động, tôi vẫn nhận được hình nền đen với hình ảnh này: seomofo.com/downloads/new-google-logo-knockoff.png
aesede

Đã thử cả hai giải pháp: của bạn và giải pháp ở trên với hơn 150 phiếu bầu. Các giải pháp của bạn hoạt động tốt cho GIF. Giải pháp trên hoạt động tốt nhất với các tệp PNG trong khi giải pháp của bạn đang mất tính năng khử răng cưa những gì bạn có thể thấy tốt nhất khi tạo hình thu nhỏ (trông có khối, có pixel).
Jonny

11

Tôi tin rằng điều này sẽ thực hiện thủ thuật:

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

chỉnh sửa: Ai đó trong tài liệu PHP tuyên bố imagealphablendingphải đúng, không sai. YMMV.


2
Sử dụng imagealphablendingtrue hoặc false, tôi luôn nhận được nền đen.
aesede

PHP7 - Working đối với tôi
Yehonatan

Đã thử với nó (PHP 7.x): PNG: imagealphablending ($ targetImage, false); // if true trên PNGs: black background GIF: imagealphablending ($ targetImage, true); // nếu sai trên GIF: nền đen
Jonny

9

Một bổ sung có thể giúp một số người:

Có thể chuyển đổi phép trộn hình ảnh trong khi xây dựng hình ảnh. Tôi là trường hợp cụ thể mà tôi cần cái này, tôi muốn kết hợp một số PNG bán trong suốt trên nền trong suốt.

Đầu tiên, bạn đặt imagealphablending thành false và tô màu hình ảnh true mới tạo bằng màu trong suốt. Nếu sự pha trộn hình ảnh là đúng, sẽ không có gì xảy ra vì phần tô trong suốt sẽ hợp nhất với nền mặc định màu đen và dẫn đến màu đen.

Sau đó, bạn chuyển đổi phép trộn hình ảnh thành true và thêm một số hình ảnh PNG vào canvas, để lại một số nền có thể nhìn thấy (tức là không lấp đầy toàn bộ hình ảnh).

Kết quả là một hình ảnh có nền trong suốt và một số hình ảnh PNG kết hợp.


6

Tôi đã thực hiện một chức năng để thay đổi kích thước hình ảnh như JPEG / GIF / PNG copyimageresamplevà hình ảnh PNG vẫn giữ được độ trong suốt:

$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
Thật là khó khăn khi đọc qua tất cả các mã để tìm ra lý do tại sao tính minh bạch được bảo tồn trong mã này so với mã trong câu hỏi.
eh9

Tôi bỏ qua hai dòng này và nó vẫn làm việc: $transparent = imagecolorallocatealpha($tmp, 255, 255, 255, 127); imagefilledrectangle($tmp, 0, 0, $newwidth, $newheight, $transparent);
santiago arizti

Câu trả lời này trông giống như stackoverflow.com/a/279310/470749 .
Ryan

5

Tôi cho rằng điều này có thể thực hiện thủ thuật:

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

Nhược điểm là hình ảnh sẽ bị tước bỏ 100% pixel xanh. Nhưng dù sao, hy vọng nó sẽ giúp :)


Nếu bạn đặt thành một màu cực kỳ xấu mà hầu như không có hình ảnh nào sử dụng, nó có thể rất hữu ích.
Cory

1
Câu trả lời được chấp nhận không phù hợp với tôi. Sử dụng câu trả lời này với imagecreate(...)mặc dù đã hoạt động. Bạn tạo một hình ảnh, được tô bằng màu đầu tiên bạn phân bổ. Sau đó, bạn đặt màu đó thành trong suốt. Nếu bảng chữ cái được đặt thành true cho hình ảnh đích, cả hai hình ảnh sẽ được hợp nhất và độ trong suốt hoạt động chính xác.
Sumurai8

2

Nâng cấp độ trong suốt của bảo toàn, sau đó có như đã nêu trong các bài viết khác imagesavealpha () phải được đặt thành true, để sử dụng cờ alpha, imagealphablending () phải được đặt thành false nếu không nó không hoạt động.

Ngoài ra, tôi đã phát hiện ra hai điều nhỏ trong mã của bạn:

  1. Bạn không cần phải gọi getimagesize()để lấy chiều rộng / chiều cao choimagecopyresmapled()
  2. Giá trị $uploadWidth$uploadHeightnên là -1giá trị, vì các cuộn dây bắt đầu bằng 0và không 1, vì vậy nó sẽ sao chép chúng vào một pixel trống. Thay thế nó bằng: imagesx($targetImage) - 1imagesy($targetImage) - 1, tương đối nên làm :)

0

Đây là tổng số mã kiểm tra của tôi. Nó phù hợp với tôi

$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

Hãy chú ý đến các giá trị widthvà hình ảnh nguồn heightđược chuyển cho imagecopyresampledhàm. Nếu chúng lớn hơn kích thước ảnh nguồn thực tế, phần còn lại của vùng ảnh sẽ được tô bằng màu đen.


0

Tôi đã kết hợp các câu trả lời từ ceejayoz và Cheekysoft, điều này mang lại kết quả tốt nhất cho tôi. Không có imagealphablending () và imagesavealpha (), hình ảnh không rõ ràng:

$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);
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.