Следующий фрагмент кода 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 );






Я считаю, что это должно помочь:
$srcImage = imagecreatefrompng($uploadTempFile);
imagealphablending($srcImage, false);
imagesavealpha($srcImage, true);
редактировать: Кто-то в документации PHP утверждает, что imagealphablending должен быть истинным, а не ложным. YMMV.
PHP7 - Работает на меня
Поигрался с ним (PHP 7.x): PNG: imagealphablending ($ targetImage, false); // если true для PNG: черный фон GIF: imagealphablending ($ targetImage, true); // если false на гифках: черный фон
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.
Хотите знать, почему здесь важен alphablending = false? В документе говорится об этом ... "Чтобы использовать альфа-блендирование (imagealphablending($im, false)), необходимо отключить его."
Этот ответ не только правильный и полезный, но и особенно полезен, потому что первый комментарий (на момент написания) документации PHP для imagecreatefrompng() предполагает, что imagealphablending должен быть установлен как true, что явно неверно. Большое спасибо.
imagesavealpha () уже должно быть достаточно. нет необходимости использовать imagealphablending большую часть времени, особенно если вы будете использовать imagefttext () позже
Это решение, в моем случае GD работает нормально ТОЛЬКО в том случае, если PNG имеет «обычную» область прозрачности, такую как окружающая прозрачная область, если она имеет сложную область, например, с внутренними частями изображения с прозрачностью, она всегда терпит неудачу и помещает черный фон , например, это изображение не работает: seomofo.com/downloads/new-google-logo-knockoff.png. Кто-нибудь может попробовать это и подтвердить?
@aesede Изображение, которое вы предоставили, у меня работает на 100% с использованием PHP 5.4 - не тестировалось с другими версиями.
Вау. imagealphablending ($ targetImage, ложь); imagesavealpha ($ targetImage, истина); Только эти 2 утверждения решили мою проблему. Спасибо Cheekysoft ...
Кажется, не работает с некоторыми прозрачными файлами png. Я попытался создать изображение из jpg и скопировать прозрачный png внутри. Как отмечает Аседе, в результате получается черный квадрат.
Лучшее / самое короткое решение, которое я нашел для изображений PNG. Сглаживание сохраняется. Лучшее / простое решение для GIF - это то, что чуть ниже: imagecolortransparent ($ new_im, imagecolorallocate ($ new_im, 0, 0, 0));
У меня был довольно сложный сценарий с кадрированием, поворотом и изменением размера с использованием нескольких копий изображений. Как только я добавил перед каждым из этих шагов простые строки imagealphablending ($ targetImage, false); imagesavealpha ($ targetImage, истина); PNG остаются совершенно прозрачными в том виде, в котором они появились. Работает префект и несложно.
При повторной оценке сохранения прозрачности, да, как указано в других сообщениях, для imagesavealpha () необходимо установить значение true, для использования альфа-флага imagealphablending () необходимо установить значение false, иначе это не сработает.
Также я заметил в вашем коде две незначительные вещи:
getimagesize(), чтобы получить ширину / высоту для imagecopyresmapled()$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
Пробовал оба решения: ваше и указанное выше, набрав более 150 голосов. Ваши решения отлично подходят для GIF. Вышеупомянутый лучше всего работает с файлами PNG, в то время как ваше решение теряет сглаживание, что вы лучше всего видите при создании эскизов (выглядит блочно, пикселизированным).
Я полагаю, это может помочь:
$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% зеленых пикселей. Во всяком случае, надеюсь, это поможет :)
Если вы установите чрезвычайно уродливый цвет, который почти не будет использоваться в изображении, это может быть очень полезно.
Принятый ответ у меня не сработал. Однако использование этого ответа с imagecreate(...) сработало. Вы создаете изображение, которое заполняется первым выделенным вами цветом. Затем вы устанавливаете этот цвет на прозрачный. Если для целевого изображения установлено значение true, оба изображения будут объединены, и прозрачность будет работать правильно.
Дополнение, которое может помочь некоторым людям:
При построении изображения можно переключать альфваблинг изображения. В конкретном случае, когда мне это было нужно, я хотел объединить несколько полупрозрачных 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;
}
Довольно сложно прочитать весь код, чтобы понять, почему в этом коде сохраняется прозрачность по сравнению с кодом в вопросе.
Я пропустил эти две строчки, но все еще работало: $transparent = imagecolorallocatealpha($tmp, 255, 255, 255, 127);imagefilledrectangle($tmp, 0, 0, $newwidth, $newheight, $transparent);
Этот ответ очень похож на stackoverflow.com/a/279310/470749.
Вот мой общий тестовый код. Меня устраивает
$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);
Используя
imagealphablendingс истинным или ложным значением, я всегда получаю черный фон.