[英]Rounded transparent _smooth_ corners using imagecopyresampled() PHP GD
我需要一個腳本,在提供的圖像上形成圓角透明角。 我找到了一個,它除了一件事之外它的效果很好:應用的角落看起來不平滑。 imageantialias()
拋出致命錯誤,因為PHP在Debian上運行並且重新編譯它不是一個選項。
我發現使這些角看起來平滑的技巧是使用imagecopyresampled()
調整圖像大小,如下所示:
但問題出現了:結果圖像的角落(在步驟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希望我不會因過度使用“放大”這個詞而被禁止:)
經過幾個小時的測試並將我的頭靠在牆上,我想我已經找到了解決方案。 問題是使用imagecolorallocate()
分配透明色。 我沒有一見鍾情。 這是完全錯誤的方法。 但是, imagecolorallocatealpha()
幫了我很多。
此外,在工作層上保存Alpha通道之前,必須關閉Alpha混合。 但是,必須在創建空白真彩色圖像后立即完成
$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');
原始圖像
它最終返回完全透明的alpha通道,因此您可以在所需的每個背景上使用該圖像。
我差點忘了發布功能代碼:)
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);
...
試試這個......
來自@ Wh1T3h4Ck5的改進代碼。 此功能可以拍攝圖像並為其制作圓角而不會浪費內存。 它也必須在巨大的圖像上更快地工作。 例如,1024 * 1024圖像需要原始代碼中的400MB臨時圖像。 現在只有230 KB。 (如果你使用半徑10 px)。
函數取GD圖像對象,半徑為px並返回GD圖像對象。 目前它與原始GD圖像對象相同。
函數假設圖像的大小從半徑開始變大。 確切地說,任何一方都需要從($radius + 2)*2
更大(或相等)。
此功能imagealphablending
此圖像的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;
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.