Rounded transparent _smooth_ corners using imagecopyresampled() PHP GD

后端 未结 3 518
隐瞒了意图╮
隐瞒了意图╮ 2020-12-09 06:14

I need a script which makes rounded transparent corners on supplied image. I\'ve found one and it works good except the one thing: the applied corners do not look smooth. Th

相关标签:
3条回答
  • 2020-12-09 06:28

    After couple of hours of testing and kicking my head against the wall, I think I've found solution. Problem was about allocating transparent color using imagecolorallocate(). I did not get it at first sight. It was totally wrong approach. However, imagecolorallocatealpha() has helped me alot.

    Also, alpha blending must be off before saving alpha channel on working layer. However, it must be done right after creating blank true-color image, like

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

    This code is a key for getting smooth corners in transparent area after resize-down.

    After all, I've wrote this function

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

    I've tested it with couple of images and it returned image with smooth corners for every bg color.

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

    Output

    Original image

    enter image description here

    IN BROWSER (Same png file 'test.png')

    enter image description here

    It finally returns fully transparent alpha channel so you can use that image on every background you want.

    I almost forgot to post function code :)

    function 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;
        }
    

    Function returns GD object or false.


    Function works with solid JPEG, GIF and PNG images. Also, it works great with transparent PNGs and GIFs.

    0 讨论(0)
  • 2020-12-09 06:28
    ...
    
    /* 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);
    
    ...
    

    try this one ...

    0 讨论(0)
  • 2020-12-09 06:29

    Improved code from @Wh1T3h4Ck5. This function take image and make round corners for it without waste memory. Also it must work faster on huge images. For example 1024*1024 image need 400MB temp image in original code. Now only 230 KB. (if you use radius 10 px).

    Function take GD image object, radius in px and return GD image object. Currently it is same as original GD image object.

    Function assume size of your image is bigger from radius. Exactly it need to be greater (or equal) from ($radius + 2)*2 on any side.

    Also function set imagealphablending to true for this image. If you need save into png, do not forgot set imagesavealpha to 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;
    }
    
    0 讨论(0)
提交回复
热议问题