Сохранение прозрачности PNG в GD2 + PHP
При работе с изображениями PNG-24 с альфа-каналом, при изменении размера или после других манипуляций с помощью библиотеки GD2 пропадает прозрачность.
Изображение без сохранения alpha-канала
Изображение с сохранение alpha-канала
Для решения этой проблемы к ресурсу(в примере — код на PHP) перед любыми манипуляциями с картинкой, фотографией применяем две функции: imageAlphaBlending и imageSaveAlpha.
Пример
Скрипт(неуниверсальный, рассчитан на изменение размера только изображения PNG).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 |
<?php /** Небольшой скрипт для уменьшения изображения */ // Создаём ресурс из исходного изображения - в формает png 24 $res = imageCreateFromPng('file_name.png'); // Узнаём информацию об изображении $prop = getimagesize('file_name.png'); // Задаём в переменных новую ширину и высоту $newWidth = 200; $newHeight = 200; /** * Создаём новый ресурс с нужной шириной и высотой, * в который запишем исходный ресурс, * заметим, что изображение полноцветное - imageCreateTrueColor */ $tmp = imageCreateTrueColor($newWidth, $newHeight); /** Перед тем как произодить опрерации с новым ресурсом, установим некоторые опции imageAlphaBlending - устанавливает режим смешивания(режим смешивания недоступен для изображений с палитрой) по умолчанию для truecolor изображений - true, для изображений с палитрой - false true/false - включен/выключен true - при накладывании одного изображения на другое цвета пикселей нижележащего и накладываемого изображения смешиваются, параметры смешивания определяются прозрачностью пикселя. false - накладываемый пиксель заменяет исходный */ imageAlphaBlending($tmp, false); /* ImageSaveAlpha Сохранять или не сохранять информацию о прозрачности по умолчанию - false, а надо true */ imageSaveAlpha($tmp, true); /* Всё, теперь прозрачность должна сохранятся */ /* копируем исходное изображение с новое, в новый ресурс */ imageCopyResampled($tmp, $res, 0, 0, 0, 0, $newWidth, $newHeight, $prop[0], $prop[1]); // Говорим браузеру о типе изображения. Тип - PNG header("Content-Type: image/png"); // Выводим изображение в буффер imagePng($tmp); ?> |
Вот и всё, оказалось всё просто.
Небольшие проблемы
В процессе использования возникла только одна проблема. Не все png-fix для IE6 фиксили уменьшенные с помощью этого скрипта изображения. На практике привык использовать DD_belatedPNG, но он не помог. Помог IE PNG Fix 2.0 Alpha 4. Вообще последний выигрывает в тех случаях, когда полно всяких извращений с пнгешками( как то изменения размера средствами html/css, навешивания событий на такие изображения и прочее). Я говорю про извращения, так как для немощного IE 6 с применением фикса это всё сложно. Появляются глюки. Надо, когда время будет, сравнить все известные мне png фиксилки.
Спасибо, очень интересная статья. Удобный способ, и главное без потери качества PNG картинки. Автор РЕСПЕКТ!!!
СПАСИБО!!!!!
// Говорим браузеру о типе изображения. Тип — PNG
header(«Content-Type: image/png»);
Нужны ли эти строчки если после уменьшения размера картинка не выводится в браузер, а просто сохраняется на сервере?
нет, при сохранении файла на сервере эта строка не нужна
этот код
header(«Content-Type: image/png»);
просто устанавливает дополнительную информацию в заголовке ответа, отсылаемого веб-сервером, чтобы браузер смог понять, что делать с полученным контентом
в результате альфа канал заменяется черным цветом 🙁
пробовал
$black = imagecolorallocatealpha($filnal, 0, 0, 0, 127);
imagecolortransparent($filnal, $black);
качество теряется…
подскажите, что сделал не так?
$output = imagecreatefrompng($filepath); //$filepath — путь к png
$w_output = 130; //ширина после уменьшения
$h_input = imagesy($output); // y — исходного $w_input = imagesx($output); // x — исходного
if ($w_input > $w_output){
$rait = $w_input / $w_output;
$x_output = round($w_input / $rait, 2); $y_output = round($h_input / $rait, 2);
$filnal = imagecreatetruecolor($x_output, $y_output);
imagealphablending($final, false);
imagesavealpha($final, true);
imagecopyresampled($filnal, $output, 0, 0, 0, 0, $x_output, $y_output, $w_input, $h_input);
$black = imagecolorallocatealpha($filnal, 0, 0, 0, 127);
imagecolortransparent($filnal, $black);
imagepng($filnal, ‘thumb.png’);
}
Посмотрел код. Стало интересно 🙂 У вас вообще весь прозрачный фон заменялся чёрным цветом?
А с применением всё стало работать? Но только качество ухудшилось или то же не работало? Насчёт качества, не знаю, при уменьшении изображения оно всегда теряется, но конечно не до безобразия.
А насчёт приведённого Вами кода, вообще он работающий, если немного подправить. Когда запустил ваш код, у меня из png с прозрачными местами сгенерировался чёрный прямоугольник 🙂
Немного подправил, заработало, вот исправленный мною код
$filepath = '1.png';
$output = imagecreatefrompng($filepath); //$filepath – путь к png
$w_output = 100; //ширина после уменьшения
$h_input = imagesy($output); // y – исходного
$w_input = imagesx($output); // x – исходного
if ($w_input > $w_output){
$rait = $w_input / $w_output;
$x_output = ceil($w_input / $rait);
$y_output = ceil($h_input / $rait);
$final = imagecreatetruecolor($x_output, $y_output);
imagealphablending($final, false);
imagesavealpha($final, true);
imagecopyresampled($final, $output, 0, 0, 0, 0, $x_output, $y_output, $w_input, $h_input);
// $black = imagecolorallocatealpha($final, 0, 0, 0, 127);
// imagecolortransparent($final, $black);
imagepng($final, '1_.png');
}
Собственно что там изменил
1. у вас опечатка, где то пишите $filnal, где то $final, наверное всё таки переменная $final
2. поменял round на ceil — округление в большую сторону
3. закомментил
// $black = imagecolorallocatealpha($final, 0, 0, 0, 127);
// imagecolortransparent($final, $black);
Может что то ещё поменял. Сравните ваш и мой код. Когда включил отображение ошибок error_reporting(E_ALL), там столько полетело ошибок 🙂
У меня этот код работает.
Я делаю погодный информер и задачу поставили не сохранить кучу всяких «картинок» а делать наложением с момощью этих функций в PHP , все вроде работает нормально, все картинки видно и первую и вторую и наложились они нормально , но на фоне во все 40 на 40 пикселей черный фон, что делать? (чего только не перепробовал)
//——————————————————————————
Вывожу через картинку скриптом.
//——————————————————————————
$sun_image = ImageCreateFromPNG(«pic/weather_lblue_big/day.png»);
$res_image = imagecreatetruecolor(40,40);
imagealphablending($res_image, true);
imagesavealpha($res_image, true);
imagecopyresampled($res_image, $sun_image, 0, 0, 0, 0, 40, 40,40,40);
$cloud_image = ImageCreateFromPNG(«pic/weather_lblue_big/bcloud.png»);
imagecopyresampled($res_image, $cloud_image, 0, 0, 0, 0, 40, 40,40,40);
imagejpeg($res_image);
ImageDestroy($res_image);
ImageDestroy($sun_image);
ImageDestroy($cloud_image);
здравствуйте, извините, но сейчас нет времени проверить на практике Ваш скрипт,
думаю надо не imagealphablending($res_image, true);, а imagealphablending($res_image, false);
ещё вы зачем то под конец используете imagejpeg, а не imagepng
ещё перед выводом в браузер не указываете тип контента
я тут поигрался с imagealphablending, с разными параметрами
короче у меня работает следующий скрипт
< ?php //—————————————————————————— // Вывожу через картинку скриптом. //—————————————————————————— $sun_image = ImageCreateFromPNG("sun.png"); $res_image = imagecreatetruecolor(60, 60); imagealphablending($res_image, false); imagesavealpha($res_image, true); imagecopyresampled($res_image, $sun_image, 0, 0, 0, 0, 60, 60,100,100); $cloud_image = ImageCreateFromPNG("cloud.png"); imagealphablending($res_image, true); imagecopyresampled($res_image, $cloud_image, 0, 0, 0, 0, 60, 60,100,100); header("Content-Type: image/png;"); imagepng($res_image); ImageDestroy($res_image); ImageDestroy($sun_image); ImageDestroy($cloud_image); ?>
ну размеры изображения свои подставите, у меня просто были исходные по 100 на 100 пикселей, итоговый на выходе сделал 60 на 60 пикселей
Ура заработало!!!))) СПАСИБО!!!)
Спасибо большое за статью, очень помогла!
Спасибо за
imageAlphaBlending($tmp, false);
imageSaveAlpha($tmp, true);
Помогло!