Скругленные прозрачные углы _smooth_ с помощью imagecopyresampled () PHP GD - PullRequest
11 голосов
/ 24 апреля 2011

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

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

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

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

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

    //    $dest = image resource


        $q=10;
        // making everything 10x bigger
        $new_width=$width*$q;
        $new_height=$height*$q;
        $radius=$radius*$q;

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

        // picking the unique colour
        $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);

            // drawing corners
            imagearc($magnified, $radius-1, $radius-1, $radius*2, $radius*2, 180, 270, $colorcode);
            imagefilltoborder($magnified, 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($magnified, $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);

        // making the unique colour transparent
        imagecolortransparent($magnified, $colorcode);

        // scaling down the enlarged image to it's original size
        // expecting corners to remain transparent
        imagecopyresampled($dest, $magnified, 0,0, 0,0, ($new_width/$q),($new_height/$q), $new_width,$new_height);
        // but they're not
        // sending $magnified to output for testing purposes
        $dest=$magnified;

    //    outputting $dest as image/png

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

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

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

PS Надеюсь, меня не забанят за злоупотребление словом "расширение":)

Ответы [ 3 ]

21 голосов
/ 24 апреля 2011

После нескольких часов испытаний и ударов головой о стену, я думаю, что нашел решение. Проблема заключалась в выделении прозрачного цвета с помощью 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
  }

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

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

выход

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

enter image description here

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

enter image description here

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

Я почти забыл опубликовать код функции:)

функция 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.

2 голосов
/ 17 октября 2013
...

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

...

попробуйте это ...

1 голос
/ 03 октября 2018

Улучшен код от @ Wh1T3h4Ck5.Эта функция снимает изображение и делает для него круглые углы без лишней памяти.Также он должен работать быстрее на огромных изображениях.Например, для изображения 1024 * 1024 требуется временное изображение 400 МБ в исходном коде.Сейчас всего 230 кб.(если вы используете радиус 10 пикселей).

Функция принимает объект изображения GD, радиус в пикселях и возвращает объект изображения GD.В настоящее время это то же самое, что и исходный объект изображения GD.

Функция предполагает, что размер вашего изображения больше радиуса.Точно оно должно быть больше (или равно) от ($radius + 2)*2 с любой стороны.

Также для этого изображения установите функцию imagealphablending в true.Если вам нужно сохранить в png, не забудьте установить imagesavealpha в true.

function roundCorners($source, $radius) {
    $ws = imagesx($source);
    $hs = imagesy($source);

    $corner = $radius + 2;
    $s = $corner*2;

    $src = imagecreatetruecolor($s, $s);
    imagecopy($src, $source, 0, 0, 0, 0, $corner, $corner);
    imagecopy($src, $source, $corner, 0, $ws - $corner, 0, $corner, $corner);
    imagecopy($src, $source, $corner, $corner, $ws - $corner, $hs - $corner, $corner, $corner);
    imagecopy($src, $source, 0, $corner, 0, $hs - $corner, $corner, $corner);

    $q = 8; # 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);

    $ns = $s * $q;

    $img = imagecreatetruecolor($ns, $ns);
    $alphacolor = imagecolorallocatealpha($img, $r, $g, $b, 127);
    imagealphablending($img, false);
    imagefilledrectangle($img, 0, 0, $ns, $ns, $alphacolor);

    imagefill($img, 0, 0, $alphacolor);
    imagecopyresampled($img, $src, 0, 0, 0, 0, $ns, $ns, $s, $s);
    imagedestroy($src);

    imagearc($img, $radius - 1, $radius - 1, $radius * 2, $radius * 2, 180, 270, $alphacolor);
    imagefilltoborder($img, 0, 0, $alphacolor, $alphacolor);
    imagearc($img, $ns - $radius, $radius - 1, $radius * 2, $radius * 2, 270, 0, $alphacolor);
    imagefilltoborder($img, $ns - 1, 0, $alphacolor, $alphacolor);
    imagearc($img, $radius - 1, $ns - $radius, $radius * 2, $radius * 2, 90, 180, $alphacolor);
    imagefilltoborder($img, 0, $ns - 1, $alphacolor, $alphacolor);
    imagearc($img, $ns - $radius, $ns - $radius, $radius * 2, $radius * 2, 0, 90, $alphacolor);
    imagefilltoborder($img, $ns - 1, $ns - 1, $alphacolor, $alphacolor);
    imagealphablending($img, true);
    imagecolortransparent($img, $alphacolor);

    # resize image down
    $dest = imagecreatetruecolor($s, $s);
    imagealphablending($dest, false);
    imagefilledrectangle($dest, 0, 0, $s, $s, $alphacolor);
    imagecopyresampled($dest, $img, 0, 0, 0, 0, $s, $s, $ns, $ns);
    imagedestroy($img);

    # output image
    imagealphablending($source, false);
    imagecopy($source, $dest, 0, 0, 0, 0, $corner, $corner);
    imagecopy($source, $dest, $ws - $corner, 0, $corner, 0, $corner, $corner);
    imagecopy($source, $dest, $ws - $corner, $hs - $corner, $corner, $corner, $corner, $corner);
    imagecopy($source, $dest, 0, $hs - $corner, 0, $corner, $corner, $corner);
    imagealphablending($source, true);
    imagedestroy($dest);

    return $source;
}
...