简体   繁体   English

使用imagecopyresampled()PHP GD圆角透明_smooth_角

[英]Rounded transparent _smooth_ corners using imagecopyresampled() PHP GD

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. 我找到了一个,它除了一件事之外它的效果很好:应用的角落看起来不平滑。 The imageantialias() throws Fatal Error since PHP is running on Debian and re-compiling it is not an option. imageantialias()抛出致命错误,因为PHP在Debian上运行并且重新编译它不是一个选项。

The trick I've found to make those corners look smooth is resizing the image with imagecopyresampled() as the following: 我发现使这些角看起来平滑的技巧是使用imagecopyresampled()调整图像大小,如下所示:

  1. prepare the image; 准备图像;
  2. imagecopyresample it to 10x size; imagecopyresample它到10倍大小;
  3. draw corners with a special colour; 用特殊颜色画角;
  4. make that color transparent; 使颜色透明;
  5. decrease the image to it's original size 将图像缩小到原始大小

But here comes the problem: the corners of the result image (after step 5) are smooth, but not transparent . 但问题出现了:结果图像的角落(在步骤5之后)是平滑的,但不是透明的 When sending to output the image after step 4 (ie before decreasing it's size) – everything's as it should be . 当在步骤4之后发送输出图像时(即在减小它的尺寸之前) - 一切都应该如此

Here's the part of the code responsible for making corners rounded: 这是负责使角落四舍五入的代码的一部分:

//    $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

So as you can see, the problem occurs when enlarged image is being imagecopyresampled to it's original size. 因此,您可以看到,当放大的图像被图像复制到其原始大小时,会出现问题。 The transparent corners get filled with the $colorcode colour. 透明的角落充满了$colorcode颜色。 I've been playing with imagesavealpha() and imagealphablending() as advised , but no result. 我一直在玩imagesavealpha()imagealphablending()建议 ,但没有结果。

Please help me to make this work. 请帮我完成这项工作。

PS This may be useful: when uploaded the large PNG to imgur.com it had it converted to JPG and as you can see all corners got filled with that very restored $colorcode. PS这可能很有用:当将大型PNG上传到imgur.com时,它已将其转换为JPG ,因为您可以看到所有角落都填充了非常恢复的$ colorcode。

PS Hope I won't get banned for overusing the word "enlargement" :) PS希望我不会因过度使用“放大”这个词而被禁止:)

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() . 问题是使用imagecolorallocate()分配透明色。 I did not get it at first sight. 我没有一见钟情。 It was totally wrong approach. 这是完全错误的方法。 However, imagecolorallocatealpha() has helped me alot. 但是, imagecolorallocatealpha()帮了我很多。

Also, alpha blending must be off before saving alpha channel on working layer. 此外,在工作层上保存Alpha通道之前,必须关闭Alpha混合。 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. 我用几个图像测试了它,它返回了每个bg颜色有光滑角落的图像。

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

Output 产量

Original image 原始图像

在此输入图像描述

IN BROWSER (Same png file 'test.png') 在浏览器中(相同的png文件'test.png')

在此输入图像描述

It finally returns fully transparent alpha channel so you can use that image on every background you want. 它最终返回完全透明的alpha通道,因此您可以在所需的每个背景上使用该图像。

I almost forgot to post function code :) 我差点忘了发布功能代码:)

function imageCreateCorners($sourceImageFile, $radius) 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 . 函数返回GD对象false


Function works with solid JPEG, GIF and PNG images. 功能适用于纯JPEG,GIF和PNG图像。 Also, it works great with transparent PNGs and GIFs. 此外,它适用于透明的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);

...

try this one ... 试试这个......

Improved code from @Wh1T3h4Ck5. 来自@ 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. 例如,1024 * 1024图像需要原始代码中的400MB临时图像。 Now only 230 KB. 现在只有230 KB。 (if you use radius 10 px). (如果你使用半径10 px)。

Function take GD image object, radius in px and return GD image object. 函数取GD图像对象,半径为px并返回GD图像对象。 Currently it is same as original GD image object. 目前它与原始GD图像对象相同。

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. 确切地说,任何一方都需要从($radius + 2)*2更大(或相等)。

Also function set imagealphablending to true for this image. 此功能imagealphablending此图像的imagealphablending设置为true If you need save into png, do not forgot set imagesavealpha to 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;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM