[英]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()
调整图像大小,如下所示:
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');
Original image 原始图像
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) {
# 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.