Округлые прозрачные _smooth_ углы с использованием imagecopyresampled () PHP GD

Мне нужен скрипт, который создает округлые прозрачные углы на поставляемом изображении. Я нашел один, и он работает хорошо, за исключением одного: применяемые углы не выглядят гладкими. imageantialias() выдает Fatal Error, поскольку PHP работает на Debian, и повторная компиляция не является вариантом.

Трюк, который я нашел, чтобы заставить эти углы выглядеть гладкими, – это изменение размера изображения с помощью imagecopyresampled() следующим образом:

  1. подготовить изображение;
  2. imagecopyresample его до размера 10x;
  3. нарисуйте углы со специальным цветом;
  4. сделать этот цвет прозрачным;
  5. уменьшите изображение до его первоначального размера

Но здесь возникает проблема: углы изображения результата (после шага 5) являются гладкими, но не прозрачными . При отправке для вывода изображения после шага 4 (т. Е. До уменьшения его размера) – все так, как должно быть .

Вот часть кода, ответственного за округление углов:

     // $ dest = ресурс изображения


         $ Д = 10;
         // делает все в 10 раз больше
         $ New_width = $ ширина * $ Q;
         $ New_height = $ высота * $ д;
         $ Радиус = $ радиус * $ д;

         $ magnified = imagecreatetruecolor ($ new_width, $ new_height);
         imagecopyresampled ($ magnified, $ dest, 0,0, 0,0, $ new_width, $ new_height, ($ new_width / $ q), ($ new_height / $ q));

         // выбор уникального цвета
         $ found = false;
         while ($ found == false) {
             $ r = rand (0, 255);
             $ g = rand (0, 255);
             $ b = rand (0, 255);
             if (imagecolorexact ($ magnified, $ r, $ g, $ b)! = (-1)) {
                 $ found = true;
             }
         }
         $ colorcode = imagecolorallocate ($ magnified, $ r, $ g, $ b);

             // рисование углов
             imagearc ($ увеличенный, $ radius-1, $ radius-1, $ radius * 2, $ radius * 2, 180, 270, $ colorcode);
             imagefilltoborder ($ увеличенный, 0, 0, $ colorcode, $ colorcode);
             imagearc ($ magnified, $ new_width- $ radius, $ radius-1, $ radius * 2, $ radius * 2, 270, 0, $ colorcode);
             imagefilltoborder ($ magnified, $ new_width-1, 0, $ colorcode, $ colorcode);
             imagearc ($ увеличенный, $ radius-1, $ new_height- $ radius, $ radius * 2, $ radius * 2, 90, 180, $ colorcode);
             imagefilltoborder ($ magnified, 0, $ new_height-1, $ colorcode, $ colorcode);
             imagearc ($ magnified, $ new_width- $ radius, $ new_height- $ radius, $ radius * 2, $ radius * 2, 0, 90, $ colorcode);
             imagefilltoborder ($ magnified, $ new_width-1, $ new_height-1, $ colorcode, $ colorcode);

         // делает уникальный цвет прозрачным
         imagecolortransparent ($ увеличенный, $ colorcode);

         // уменьшая увеличенное изображение до его первоначального размера
         // ожидаем, что углы останутся прозрачными
         imagecopyresampled ($ dest, $ magnified, 0,0, 0,0, ($ new_width / $ q), ($ new_height / $ q), $ new_width, $ new_height);
         // но они не
         // отправка $ увеличенной для вывода для целей тестирования
         $ Dest = $ возвеличил;

     // вывод $ dest как image / png 

Таким образом, как вы можете видеть, проблема возникает, когда увеличенное изображение imagecopyresampled до его первоначального размера. Прозрачные углы заполняются цветом $colorcode . Я играю с imagesavealpha() и imagealphablending() в соответствии с рекомендациями , но без результата.

Пожалуйста, помогите мне сделать эту работу.

PS Это может быть полезно: при загрузке большого PNG на imgur.com он преобразовал его в JPG, и, как вы можете видеть, все углы заполнены очень восстановленным $ colorcode.

PS Надеюсь, мне не будет запрещено использовать слово «расширение» ðŸ™‚

После нескольких часов тестирования и удариться головой о стену, я думаю, что нашел решение. Проблема заключалась в распределении прозрачного цвета с использованием imagecolorallocate() . Я не понял это с первого взгляда. Это был совершенно неправильный подход. Однако imagecolorallocatealpha() мне очень помог.

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

  $im = imagecreatetruecolor($w, $h); $alphacolor = imagecolorallocatealpha($img, $r, $g, $b, 127); imagealphablending($im, false); imagesavealpha($im, true); 

Этот код является ключом для получения гладких углов в прозрачной области после изменения размера.

В конце концов, я написал эту функцию

  function imageCreateCorners($sourceImageFile, $radius) { # function body } 

Я тестировал его с помощью нескольких изображений, и он возвращал изображение с гладкими углами для каждого цвета bg.

  imagepng(imageCreateCorners('jan_vesely_and_james_gist.jpg', 9), 'test.png'); 

Вывод

Исходное изображение

введите описание изображения здесь

IN BROWSER (тот же файл png 'test.png')

введите описание изображения здесь

Он, наконец, возвращает полностью прозрачный альфа-канал, поэтому вы можете использовать это изображение на каждом желаемом фоне.

Я почти забыл написать код функции 🙂

Функция imageCreateCorners ($ sourceImageFile, $ radius)

  function imageCreateCorners($sourceImageFile, $radius) { # test source image if (file_exists($sourceImageFile)) { $res = is_array($info = getimagesize($sourceImageFile)); } else $res = false; # open image if ($res) { $w = $info[0]; $h = $info[1]; switch ($info['mime']) { case 'image/jpeg': $src = imagecreatefromjpeg($sourceImageFile); break; case 'image/gif': $src = imagecreatefromgif($sourceImageFile); break; case 'image/png': $src = imagecreatefrompng($sourceImageFile); break; default: $res = false; } } # create corners if ($res) { $q = 10; # change this if you want $radius *= $q; # find unique color do { $r = rand(0, 255); $g = rand(0, 255); $b = rand(0, 255); } while (imagecolorexact($src, $r, $g, $b) < 0); $nw = $w*$q; $nh = $h*$q; $img = imagecreatetruecolor($nw, $nh); $alphacolor = imagecolorallocatealpha($img, $r, $g, $b, 127); imagealphablending($img, false); imagesavealpha($img, true); imagefilledrectangle($img, 0, 0, $nw, $nh, $alphacolor); imagefill($img, 0, 0, $alphacolor); imagecopyresampled($img, $src, 0, 0, 0, 0, $nw, $nh, $w, $h); imagearc($img, $radius-1, $radius-1, $radius*2, $radius*2, 180, 270, $alphacolor); imagefilltoborder($img, 0, 0, $alphacolor, $alphacolor); imagearc($img, $nw-$radius, $radius-1, $radius*2, $radius*2, 270, 0, $alphacolor); imagefilltoborder($img, $nw-1, 0, $alphacolor, $alphacolor); imagearc($img, $radius-1, $nh-$radius, $radius*2, $radius*2, 90, 180, $alphacolor); imagefilltoborder($img, 0, $nh-1, $alphacolor, $alphacolor); imagearc($img, $nw-$radius, $nh-$radius, $radius*2, $radius*2, 0, 90, $alphacolor); imagefilltoborder($img, $nw-1, $nh-1, $alphacolor, $alphacolor); imagealphablending($img, true); imagecolortransparent($img, $alphacolor); # resize image down $dest = imagecreatetruecolor($w, $h); imagealphablending($dest, false); imagesavealpha($dest, true); imagefilledrectangle($dest, 0, 0, $w, $h, $alphacolor); imagecopyresampled($dest, $img, 0, 0, 0, 0, $w, $h, $nw, $nh); # output image $res = $dest; imagedestroy($src); imagedestroy($img); } return $res; } 

Функция возвращает объект GD или false .


Функция работает со сплошными изображениями JPEG, GIF и PNG. Кроме того, он отлично работает с прозрачными PNG и GIF.

 ... /* rounded corner */ $radius = 20; // find ghost color do { $r = rand(0, 255); $g = rand(0, 255); $b = rand(0, 255); } while (imagecolorexact($img_resource, $r, $g, $b) < 0); $ghost_color = imagecolorallocate($img_resource, $r, $g, $b); imagearc($img_resource, $radius-1, $radius-1, $radius*2, $radius*2, 180, 270, $ghost_color); imagefilltoborder($img_resource, 0, 0, $ghost_color, $ghost_color); imagearc($img_resource, $img_width-$radius, $radius-1, $radius*2, $radius*2, 270, 0, $ghost_color); imagefilltoborder($img_resource, $img_width-1, 0, $ghost_color, $ghost_color); imagearc($img_resource, $radius-1, $img_height-$radius, $radius*2, $radius*2, 90, 180, $ghost_color); imagefilltoborder($img_resource, 0, $img_height-1, $ghost_color, $ghost_color); imagearc($img_resource, $img_width-$radius, $img_height-$radius, $radius*2, $radius*2, 0, 90, $ghost_color); imagefilltoborder($img_resource, $img_width-1, $img_height-1, $ghost_color, $ghost_color); imagecolortransparent($img_resource, $ghost_color); ... 

Попробуй это …