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

Следующий фрагмент кода 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 );
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Symfony Station Communiqué - 7 июля 2023 г
Symfony Station Communiqué - 7 июля 2023 г
Это коммюнике первоначально появилось на Symfony Station .
Оживление вашего приложения Laravel: Понимание режима обслуживания
Оживление вашего приложения Laravel: Понимание режима обслуживания
Здравствуйте, разработчики! В сегодняшней статье мы рассмотрим важный аспект управления приложениями, который часто упускается из виду в суете...
Установка и настройка Nginx и PHP на Ubuntu-сервере
Установка и настройка Nginx и PHP на Ubuntu-сервере
В этот раз я сделаю руководство по установке и настройке nginx и php на Ubuntu OS.
Коллекции в Laravel более простым способом
Коллекции в Laravel более простым способом
Привет, читатели, сегодня мы узнаем о коллекциях. В Laravel коллекции - это способ манипулировать массивами и играть с массивами данных. Благодаря...
Как установить PHP на Mac
Как установить PHP на Mac
PHP - это популярный язык программирования, который используется для разработки веб-приложений. Если вы используете Mac и хотите разрабатывать...
102
0
95 835
10
Перейти к ответу Данный вопрос помечен как решенный

Ответы 10

Я считаю, что это должно помочь:

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

редактировать: Кто-то в документации PHP утверждает, что imagealphablending должен быть истинным, а не ложным. YMMV.

Используя imagealphablending с истинным или ложным значением, я всегда получаю черный фон.

aesede 29.09.2014 19:17

PHP7 - Работает на меня

Yehonatan 25.01.2017 13:59

Поигрался с ним (PHP 7.x): PNG: imagealphablending ($ targetImage, false); // если true для PNG: черный фон GIF: imagealphablending ($ targetImage, true); // если false на гифках: черный фон

Jonny 18.04.2017 15:07
Ответ принят как подходящий

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

FIY, это должно быть после создания целевого изображения. В этом случае это будет после imagecreatetruecolor.

RisingSun 25.02.2013 11:03

Хотите знать, почему здесь важен alphablending = false? В документе говорится об этом ... "Чтобы использовать альфа-блендирование (imagealphablending($im, false)), необходимо отключить его."

eightyfive 27.06.2014 13:50

Этот ответ не только правильный и полезный, но и особенно полезен, потому что первый комментарий (на момент написания) документации PHP для imagecreatefrompng() предполагает, что imagealphablending должен быть установлен как true, что явно неверно. Большое спасибо.

spikyjt 23.07.2014 13:09

imagesavealpha () уже должно быть достаточно. нет необходимости использовать imagealphablending большую часть времени, особенно если вы будете использовать imagefttext () позже

fedmich 26.07.2014 09:52

Это решение, в моем случае GD работает нормально ТОЛЬКО в том случае, если PNG имеет «обычную» область прозрачности, такую ​​как окружающая прозрачная область, если она имеет сложную область, например, с внутренними частями изображения с прозрачностью, она всегда терпит неудачу и помещает черный фон , например, это изображение не работает: seomofo.com/downloads/new-google-logo-knockoff.png. Кто-нибудь может попробовать это и подтвердить?

aesede 29.09.2014 19:01

@aesede Изображение, которое вы предоставили, у меня работает на 100% с использованием PHP 5.4 - не тестировалось с другими версиями.

Floris 30.03.2015 22:10

Вау. imagealphablending ($ targetImage, ложь); imagesavealpha ($ targetImage, истина); Только эти 2 утверждения решили мою проблему. Спасибо Cheekysoft ...

Raj 13.07.2015 15:16

Кажется, не работает с некоторыми прозрачными файлами png. Я попытался создать изображение из jpg и скопировать прозрачный png внутри. Как отмечает Аседе, в результате получается черный квадрат.

RubbelDeCatc 11.10.2015 14:58

Лучшее / самое короткое решение, которое я нашел для изображений PNG. Сглаживание сохраняется. Лучшее / простое решение для GIF - это то, что чуть ниже: imagecolortransparent ($ new_im, imagecolorallocate ($ new_im, 0, 0, 0));

Jonny 18.04.2017 15:12

У меня был довольно сложный сценарий с кадрированием, поворотом и изменением размера с использованием нескольких копий изображений. Как только я добавил перед каждым из этих шагов простые строки imagealphablending ($ targetImage, false); imagesavealpha ($ targetImage, истина); PNG остаются совершенно прозрачными в том виде, в котором они появились. Работает префект и несложно.

Oliver 17.12.2019 20:19

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

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

  1. Вам не нужно звонить getimagesize(), чтобы получить ширину / высоту для imagecopyresmapled()
  2. $uploadWidth и $uploadHeight должны иметь значение -1, поскольку координаты начинаются с 0, а не 1, поэтому они будут скопированы в пустой пиксель. Заменив его на: imagesx($targetImage) - 1 и imagesy($targetImage) - 1, относительно должно работать :)

Почему вы все так усложняете? следующее - то, что я использую, и до сих пор это помогло мне.

$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 29.09.2014 19:15

Пробовал оба решения: ваше и указанное выше, набрав более 150 голосов. Ваши решения отлично подходят для GIF. Вышеупомянутый лучше всего работает с файлами PNG, в то время как ваше решение теряет сглаживание, что вы лучше всего видите при создании эскизов (выглядит блочно, пикселизированным).

Jonny 18.04.2017 15:04

Я полагаю, это может помочь:

$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 15.11.2010 20:18

Принятый ответ у меня не сработал. Однако использование этого ответа с imagecreate(...) сработало. Вы создаете изображение, которое заполняется первым выделенным вами цветом. Затем вы устанавливаете этот цвет на прозрачный. Если для целевого изображения установлено значение true, оба изображения будут объединены, и прозрачность будет работать правильно.

Sumurai8 22.10.2013 15:10

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

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

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

Затем вы переключаете imagealphablending на true и добавляете некоторые изображения PNG на холст, оставляя часть фона видимой (то есть не заполняя все изображение).

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

Я сделал функцию изменения размера изображения, такого как 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;
}

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

eh9 09.11.2012 22:29

Я пропустил эти две строчки, но все еще работало: $transparent = imagecolorallocatealpha($tmp, 255, 255, 255, 127);imagefilledrectangle($tmp, 0, 0, $newwidth, $newheight, $transparent);

santiago arizti 13.04.2017 23:06

Этот ответ очень похож на stackoverflow.com/a/279310/470749.

Ryan 22.02.2020 20:52

Вот мой общий тестовый код. Меня устраивает

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

Обратите внимание на значения width и height исходного изображения, которые передаются в функцию imagecopyresampled. Если они больше фактического размера исходного изображения, остальная часть изображения будет заполнена черным цветом.

Я объединил ответы 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);

Другие вопросы по теме