Можно ли сохранить прозрачность изображения PNG при использовании PHP GDlib imagecopyresampled?
-
09-06-2019 - |
Вопрос
Следующий фрагмент 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 );
Решение
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 );
Другие советы
Почему ты все так усложняешь?ниже приведено то, что я использую, и до сих пор оно выполняло эту работу за меня.
$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]);
Я считаю, что это должно сработать:
$srcImage = imagecreatefrompng($uploadTempFile);
imagealphablending($srcImage, false);
imagesavealpha($srcImage, true);
Редактировать: Кто-то в PHP docs утверждает, что imagealphablending
должно быть правдой, а не ложью.ИММВ.
Дополнение, которое могло бы помочь некоторым людям:
Можно переключить imagealphablending во время создания изображения.В конкретном случае, когда мне это было нужно, я хотел объединить несколько полупрозрачных файлов PNG на прозрачном фоне.
Сначала вы устанавливаете imagealphablending в значение false и заливаете вновь созданное изображение true color прозрачным цветом.Если бы значение 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;
}
Я полагаю, что это могло бы сработать:
$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% зеленых пикселей.Во всяком случае, надеюсь, это поможет :)
Повторно оцениваем сохранение прозрачности, тогда да, как указано в других сообщениях, для imagesavealpha() должно быть установлено значение true, для использования альфа-флага imagealphablending() должно быть установлено значение false, иначе это не сработает.
Кроме того, я заметил две незначительные вещи в вашем коде:
- Тебе не нужно звонить
getimagesize()
чтобы получить ширину / высоту дляimagecopyresmapled()
- Тот Самый
$uploadWidth
и$uploadHeight
должно быть-1
значение, поскольку кординаты начинаются с0
и не1
, таким образом, он скопировал бы их в пустой пиксель.Заменив его на:imagesx($targetImage) - 1
иimagesy($targetImage) - 1
, относительно должно получиться :)
Вот мой общий тестовый код.У меня это работает
$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);