Можно ли сохранить прозрачность изображения PNG при использовании PHP GDlib imagecopyresampled?

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 );
Cheekysoft
источник

Ответы:

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 );
Cheekysoft
источник
5
FIY, это должно быть после создания целевого изображения. В этом случае это будет после imagecreatetruecolor.
RisingSun
Хотите знать, почему alphablending = falseздесь важно? В документе говорится : « imagealphablending($im, false)Чтобы использовать его, нужно отключить alphablending ( )».
восемьдесят пять,
2
Этот ответ не только правильный и полезный, но и особенно полезен, потому что первый комментарий (на момент написания) к документации PHP для imagecreatefrompng()предполагает, что это imagealphablendingследует установить true, что явно неверно. Большое спасибо.
spikyjt
3
Это решение, в моем случае GD работает нормально ТОЛЬКО в том случае, если PNG имеет «обычную» область прозрачности, такую ​​как окружающая прозрачная область, если она имеет сложную область, например, с внутренними частями изображения с прозрачностью, он всегда терпит неудачу и помещает черный фон , например, это изображение не работает: seomofo.com/downloads/new-google-logo-knockoff.png . Кто-нибудь может попробовать это и подтвердить?
aesede
2
Не работает с некоторыми прозрачными файлами png. Я попытался создать изображение из jpg и скопировать прозрачный png внутри. Как отмечает Аседе, в результате получается черный квадрат.
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);

edit: Кто-то в документах PHP утверждает, imagealphablendingчто это правда, а не ложь. YMMV.

Ceejayoz
источник
2
Используя imagealphablendingлибо true, либо false, я всегда получаю черный фон.
aesede
PHP7 - Работает на меня
Йехонатан
Поигрался с ним (PHP 7.x): PNG: imagealphablending ($ targetImage, false); // если true для PNG: черный фон GIF: imagealphablending ($ targetImage, true); // если false на гифках: черный фон
Джонни
9

Дополнение, которое может помочь некоторым людям:

Во время построения изображения можно переключать альфваблинг изображения. В конкретном случае, когда мне это было нужно, я хотел объединить несколько полупрозрачных PNG на прозрачном фоне.

Сначала вы устанавливаете imagealphablending на false и заполняете только что созданное изображение истинного цвета прозрачным цветом. Если бы imagealphablending было истинным, ничего бы не произошло, потому что прозрачная заливка слилась бы с черным фоном по умолчанию и в результате была бы черной.

Затем вы переключаете 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;
}
pricopz
источник
3
Довольно сложно прочитать весь код, чтобы понять, почему в этом коде сохраняется прозрачность по сравнению с кодом в вопросе.
eh9 09
Я пропустил эти две строчки, и это все еще работало: $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(...)работал. Вы создаете изображение, которое заполняется первым выделенным вами цветом. Затем вы устанавливаете этот цвет на прозрачный. Если для целевого изображения задано значение true, оба изображения будут объединены, и прозрачность будет работать правильно.
Sumurai8,
2

Пересортировка сохранения прозрачности, тогда да, как указано в других сообщениях, для imagesavealpha () необходимо установить значение true, для использования альфа-флага imagealphablending () необходимо установить значение false, иначе это не сработает.

Также я заметил в вашем коде две незначительные вещи:

  1. Вам не нужно звонить getimagesize() чтобы получить ширину / высоту дляimagecopyresmapled()
  2. $uploadWidthИ $uploadHeightдолжно быть -1значение, так как cordinates начинается 0и не 1, поэтому было бы скопировать их в пустой пиксель. Заменив его на: imagesx($targetImage) - 1и imagesy($targetImage) - 1, относительно должно быть :)
Kalle
источник
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);
Md. Imadul Islam
источник
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);
Марко
источник