imageantialias

(PHP 4 >= 4.3.2, PHP 5, PHP 7, PHP 8)

imageantialias是否应该使用抗锯齿函数

描述

imageantialias(GdImage $image, bool $enable): bool

为线和带线的多边形激活快速绘制抗锯齿方法。它不支持 alpha 分量。它使用直接混合操作。它仅适用于真彩色图像。

不支持粗细和样式。

使用具有透明背景色的抗锯齿基元可能会导致一些意外的结果。混合方法将背景色与其他颜色一样对待。缺少 alpha 分量支持不允许基于 alpha 的抗锯齿方法。

参数

image

一个 GdImage 对象,由图像创建函数之一返回,例如 imagecreatetruecolor()

enable

是否启用抗锯齿。

返回值

成功时返回 true,失败时返回 false

变更日志

版本 描述
8.0.0 image 现在期望一个 GdImage 实例;以前,期望一个有效的 gd resource
7.2.0 imageantialias() 现在普遍可用。以前只有在 PHP 使用捆绑版本的 GD 库编译时才可用。

示例

示例 #1 比较两条线,其中一条启用了抗锯齿

<?php
// 设置抗锯齿图像和普通图像
$aa = imagecreatetruecolor(400, 100);
$normal = imagecreatetruecolor(200, 100);

// 为其中一个图像启用抗锯齿
imageantialias($aa, true);

// 分配颜色
$red = imagecolorallocate($normal, 255, 0, 0);
$red_aa = imagecolorallocate($aa, 255, 0, 0);

// 绘制两条线,一条启用 AA
imageline($normal, 0, 0, 200, 100, $red);
imageline($aa, 0, 0, 200, 100, $red_aa);

// 将两张图像并排合并以输出 (AA:左,Normal:右)
imagecopymerge($aa, $normal, 200, 0, 0, 0, 200, 100, 100);

// 输出图像
header('Content-type: image/png');

imagepng($aa);
imagedestroy($aa);
imagedestroy($normal);
?>

上面的例子将输出类似于

Output of example : A comparison of two lines, one with anti-aliasing switched on

参见

添加说明

用户贡献的说明 8 说明

17
padigan
17 年前
如果你不想创建(或搜索)一个完整的屏幕抗锯齿函数。
你实际上可以作弊(好吧,这只是一个有点脏的低效技巧!)
并在图像上执行假抗锯齿,使用 'imagecopyresampled'...

首先,创建比你真正想要的尺寸大两倍的源图像。

然后使用 'imagecopyresampled' 将其缩小到一半的大小,该函数
会自动对像素进行插值以创建抗锯齿效果!

我在一个饼图函数中使用过它,效果很好,
速度并没有像我想象的那么慢!

下面的粗略代码应该能让你明白...

<?php
$realWidth
= 500;
$realHeight = 500;
$srcWidth = $realWidth * 2;
$srcHeight = $realHeight * 2;

// 创建更大的源图像
$srcImage = imagecreatetruecolor($srcWidth,$srcHeight);

// 创建真实/最终图像
$destImage = imagecreatetruecolor($realWidth,$realHeight);

// 现在在源图像中绘制任何你想要的东西
// blah....

// 现在图像已完成,进行缩小...
imagecopyresampled($destImage,$srcImage,0,0,0,0,
$realWidth,$realHeight,$srcWidth,$srcHeight);

// 现在只需对 '$destImage' 执行任何你想要的操作(例如,显示或输出到文件!)
?>
6
trimbo
18 年前
到目前为止,使用 PHP 5.0.4,我已经成功地让 Imageantialias() 与以下函数一起使用:
ImageLine()
ImagePolygon()

但不能与以下函数一起使用:
ImageArc()
ImageEllipse()
ImageFilled*()

你仍然可以通过在具有相同尺寸的填充多边形上绘制一个空心多边形来绘制抗锯齿填充多边形。
<?php
$points
=array($x,$y, $x2,$y2, $x3,$y3);
imageFilledPolygon($im, $points, 3, $gray );
imagePolygon($im, $points, 3, $gray );
?>
2
n-dream at gmx dot ch
18 年前
以下函数绘制一个抗锯齿(未填充)椭圆。
它与 nomral ImageEllipse 函数的使用方式相同。
可选参数设置段数...

function ImageEllipseAA( &$img, $x, $y, $w, $h,$color,$segments=70)
{
$w=$w/2;
$h=$h/2;
$jump=2*M_PI/$segments;
$oldx=$x+sin(-$jump)*$w;
$oldy=$y+cos(-$jump)*$h;
for($i=0;$i<2*(M_PI);$i+=$jump)
{
$newx=$x+sin($i)*$w;
$newy=$y+cos($i)*$h;
ImageLine($img,$newx,$newy,$oldx,$oldy,$color);
$oldx=$newx;
$oldy=$newy;
}
}
0
verdy_p at wanadoo dot fr
14 年前
快速算法(“快 20 倍”)中的这些行存在一个小的编辑错误。

imageLine( $img, $cx + $ix, $cy + $iy - 1, $cx + $ix, $cy + $ix, $fill );
imageLine( $img, $cx + $ix, $cy - $iy + 1, $cx + $ix, $cy - $ix, $fill );
imageLine( $img, $cx - $ix, $cy + $iy - 1, $cx - $ix, $cy + $ix, $fill );
imageLine( $img, $cx - $ix, $cy - $iy + 1, $cx - $ix, $cy - $ix, $fill );
imageLine( $img, $cx + $iy - 1, $cy + $ix, $cx + $ix, $cy + $ix, $fill );
imageLine( $img, $cx + $iy - 1, $cy - $ix, $cx + $ix, $cy - $ix, $fill );
imageLine( $img, $cx - $iy + 1, $cy + $ix, $cx - $ix, $cy + $ix, $fill );
imageLine( $img, $cx - $iy + 1, $cy - $ix, $cx - $ix, $cy - $ix, $fill );

每个调用参数中的“$ix”(紧接在“,$fill”参数之前)应有时为“$iy”。

此算法使用 Bresenham 中点算法来绘制圆,但以递增方式在第一个象限中计算连续像素位置($ix, $iy),相对于圆心($cx, $cy),然后通过交换它们或改变符号来应用 8 种对称性。

椭圆存在类似的算法:当椭圆焦轴与图像的两个轴对齐或正交时,它使用象限对称而不是八分圆对称,通过将每个象限细分为两个区域(由弧上切线斜率为 1 的点界定)。

对于一般的椭圆(在平面上任意旋转),也有 4 个象限对称,但计算起来稍微复杂一些,因为您需要计算旋转,因此您只能使用 2 个对称性,但递增算法仍然存在:您可能会认为这将基于对来自两个焦点的长度之和的评估,该和是恒定的;但是两个距离的和不能那么容易地平方(您需要计算两个距离的平方,然后在添加它们并使用精确长度测试差值之前分别取它们各自的平方根。更简洁的解决方案使用 NURBS(非均匀有理 B 样条曲线),因为它们在数值上是稳定的,并且计算速度仍然非常快(您只需要一些浮点数作为分隔每个象限的结常数,然后使用椭圆的简单二次参数方程来计算,而不是隐式方程,鉴于二次(多项式)方程的一阶和二阶导数很容易求界限,以获得所需的精度并减少不必要的像素绘图次数:这样的参数方程将在弧线上绘制点,其运动速度在每增量步长 1 到 4 个子像素距离之间变化,但实际上仅在 1 到 2 个子像素之间变化,当您将象限细分为两个区域时)。

或者,您还可以绘制一个带有双分辨率的抗锯齿“直线”椭圆,然后旋转抗锯齿图像,同时将其重新缩放到一半大小,并同时将其与目标组合:根据实现(以及使用的计算语言),它可能更快(但它可能需要更多内存用于 2 倍比例的中间图像)...
0
dsl101
15 年前
经过长时间努力尝试获得一个体面的抗锯齿圆函数后,我终于放弃了,从头开始写了一个。它非常非常幼稚 - 基本上检查了包围正方形中的每个像素,但结果产生了非常好的抗锯齿,并对笔触宽度、抗锯齿量和抗锯齿的紧密程度有很好的控制。我相信它可以得到相当大的优化,但它对我正在做的事情来说足够快了。希望它有用。

<?php

function imagecircleaa($img, $cx, $cy, $r, $w, $s, $t, $color) // image, centerX, centerY, radius, stroke width, aa width, tightness, color
{
$adj = $w + $s;
$sCol = imagecolorallocate($img, $color['r'], $color['g'], $color['b']);
for(
$x = -$r - $adj; $x <= $r + $adj; $x++)
{
for(
$y = -$r - $adj; $y <= $r + $adj; $y++)
{
$d = sqrt($x * $x + $y * $y); // distance from pixel to center
$err = abs($d - $r); // absolute distance from pixel to circle edge
if($err <= $w / 2 + $s) // within the stroke width + smoothing radius
{
if(
$err <= $w / 2) // inside the stroke width so make it solid color
{
$aaCol = $sCol;
}
else
// in the antialisaing region so make it a blended color
{
$err -= $w / 2; // adjust to the aliased part
$err = 1 - $err / $s; // adjust to between 0 and 1
$err = ($err - 0.5) * $t * 2; // adjust to -$t to +$t for tightness
$err = ($err / sqrt(1 + $err * $err) + 1) / 2; // sigmoid curve to smooth edges
$rgb = imagecolorat($img, $x + $cx, $y + $cy); // Get current background color
$rB = ($rgb >> 16) & 0xFF;
$gB = ($rgb >> 8) & 0xFF;
$bB = $rgb & 0xFF;
$rDelta = ($rB - $color['r']); // change in Red from background
$rComp = $rB - $rDelta * $err; // mix Red
$gDelta = ($gB - $color['g']); // change in Red from background
$gComp = $gB - $gDelta * $err; // mix Red
$bDelta = ($bB - $color['b']); // change in Red from background
$bComp = $bB - $bDelta * $err; // mix Red
$aaCol = imagecolorallocate($img, $rComp, $gComp, $bComp);
}
imagesetpixel($img, $x + $cx, $y + $cy, $aaCol);
}
}
}
}

$img = imagecreatetruecolor(500,500);

$cBlack = imagecolorallocate($img, 0, 0, 0);
$cGrey = imagecolorallocate($img, 120, 120, 120);
$cWhite = imagecolorallocate($img, 255, 255, 255);

imagefill($img, 0, 0, $cWhite);
imagepolygon($img, array(0, 0,200, 0, 200, 200, 0, 200), 4, cBlack);

$aWhite = array('r'=>255, 'g'=>255, 'b'=>255);
$aBlack = array('r'=>0, 'g'=>0, 'b'=>0);
$aRed = array('r'=>200, 'g'=>0, 'b'=>0);
$aGreen = array('r'=>0, 'g'=>200, 'b'=>0);
$aBlue = array('r'=>0, 'g'=>0, 'b'=>255);

// standard ellipse function for comparison
imageellipse($img, 100, 100, 50, 50, $cBlack);

// compare different tightnesses - good values are between 2 and 8
// note overall width is stroke width + 2 * aa width (e.g. 12 pixels below)
imagecircleaa($img, 50, 50, 25, 2, 5, 2, $aBlue);
imagecircleaa($img, 50, 150, 25, 2, 5, 8, $aBlue);

// different coloured background to show blending
imagefilledrectangle($img, 150,150, 200, 200, $cGrey);
imagecircleaa($img, 150, 150, 25, 3, 2, 2, $aRed);

// overlapping circles still aa nicely, although the colour blending algorithm produces quite dark intermediate shades
imagecircleaa($img, 150, 60, 25, 2, 3, 2, $aBlue);
imagecircleaa($img, 150, 50, 25, 2, 3, 2, $aGreen);

header("Content-type: image/png");
imagepng($img);
imagedestroy($img);
?>
0
klaas at kosmokrator dot com
18 年前
这是 sebbi 抗锯齿圆函数的优化版本的优化版本(快 20 倍以上)...

<?php

function imageSmoothCircle( &$img, $cx, $cy, $cr, $color ) {
$ir = $cr;
$ix = 0;
$iy = $ir;
$ig = 2 * $ir - 3;
$idgr = -6;
$idgd = 4 * $ir - 10;
$fill = imageColorExactAlpha( $img, $color[ 'R' ], $color[ 'G' ], $color[ 'B' ], 0 );
imageLine( $img, $cx + $cr - 1, $cy, $cx, $cy, $fill );
imageLine( $img, $cx - $cr + 1, $cy, $cx - 1, $cy, $fill );
imageLine( $img, $cx, $cy + $cr - 1, $cx, $cy + 1, $fill );
imageLine( $img, $cx, $cy - $cr + 1, $cx, $cy - 1, $fill );
$draw = imageColorExactAlpha( $img, $color[ 'R' ], $color[ 'G' ], $color[ 'B' ], 42 );
imageSetPixel( $img, $cx + $cr, $cy, $draw );
imageSetPixel( $img, $cx - $cr, $cy, $draw );
imageSetPixel( $img, $cx, $cy + $cr, $draw );
imageSetPixel( $img, $cx, $cy - $cr, $draw );
while (
$ix <= $iy - 2 ) {
if (
$ig < 0 ) {
$ig += $idgd;
$idgd -= 8;
$iy--;
} else {
$ig += $idgr;
$idgd -= 4;
}
$idgr -= 4;
$ix++;
imageLine( $img, $cx + $ix, $cy + $iy - 1, $cx + $ix, $cy + $ix, $fill );
imageLine( $img, $cx + $ix, $cy - $iy + 1, $cx + $ix, $cy - $ix, $fill );
imageLine( $img, $cx - $ix, $cy + $iy - 1, $cx - $ix, $cy + $ix, $fill );
imageLine( $img, $cx - $ix, $cy - $iy + 1, $cx - $ix, $cy - $ix, $fill );
imageLine( $img, $cx + $iy - 1, $cy + $ix, $cx + $ix, $cy + $ix, $fill );
imageLine( $img, $cx + $iy - 1, $cy - $ix, $cx + $ix, $cy - $ix, $fill );
imageLine( $img, $cx - $iy + 1, $cy + $ix, $cx - $ix, $cy + $ix, $fill );
imageLine( $img, $cx - $iy + 1, $cy - $ix, $cx - $ix, $cy - $ix, $fill );
$filled = 0;
for (
$xx = $ix - 0.45; $xx < $ix + 0.5; $xx += 0.2 ) {
for (
$yy = $iy - 0.45; $yy < $iy + 0.5; $yy += 0.2 ) {
if (
sqrt( pow( $xx, 2 ) + pow( $yy, 2 ) ) < $cr ) $filled += 4;
}
}
$draw = imageColorExactAlpha( $img, $color[ 'R' ], $color[ 'G' ], $color[ 'B' ], ( 100 - $filled ) );
imageSetPixel( $img, $cx + $ix, $cy + $iy, $draw );
imageSetPixel( $img, $cx + $ix, $cy - $iy, $draw );
imageSetPixel( $img, $cx - $ix, $cy + $iy, $draw );
imageSetPixel( $img, $cx - $ix, $cy - $iy, $draw );
imageSetPixel( $img, $cx + $iy, $cy + $ix, $draw );
imageSetPixel( $img, $cx + $iy, $cy - $ix, $draw );
imageSetPixel( $img, $cx - $iy, $cy + $ix, $draw );
imageSetPixel( $img, $cx - $iy, $cy - $ix, $draw );
}
}

$img = imageCreateTrueColor( 320, 240 );

imageSmoothCircle( $img, 160, 120, 100, array( 'R' => 0xCC, 'G' => 0x33, 'B' => 0x00 ) );
imageSmoothCircle( $img, 170, 110, 75, array( 'R' => 0xDD, 'G' => 0x66, 'B' => 0x00 ) );
imageSmoothCircle( $img, 180, 100, 50, array( 'R' => 0xEE, 'G' => 0x99, 'B' => 0x00 ) );
imageSmoothCircle( $img, 190, 90, 25, array( 'R' => 0xFF, 'G' => 0xCC, 'B' => 0x00 ) );

header( 'Content-Type: image/png' );
imagePNG( $img );

?>
0
sebbi at conceptT dot com
18 年前
我在谷歌上搜索了一下,得到了以下网址
http://www.isocalc.com/tutorials/antialias.htm
通过本教程,我能够编写一个函数将此算法转换为 php,填充圆的结果如下
<?php
function imagefilledcircleantialiased(&$im, $cx, $cy, $r, $fgcolor, $bgcolor) {
$fgcolors = imagecolorsforindex($im,$fgcolor);
$bgcolors = imagecolorsforindex($im,$bgcolor);
for (
$x = $cx - $r; $x <= $cx + $r; $x++ ) {
for (
$y = $cy - $r; $y <= $cy + $r; $y++ ) {
$rx = $x - $cx; $ry = $y - $cy;
$ir = sqrt(( $rx == 0 ? 0 : pow($rx - 0.5*abs($rx)/$rx, 2) ) + ( $ry == 0 ? 0 : pow($ry - 0.5*abs($ry)/$ry, 2) ));
$or = sqrt(( $rx == 0 ? 0 : pow($rx + 0.5*abs($rx)/$rx, 2) ) + ( $ry == 0 ? 0 : pow($ry + 0.5*abs($ry)/$ry, 2) ));
if (
$or <= $r ) {
imagesetpixel($im, $x, $y, $fgcolor);
}
elseif (
$ir < $r ) {
$filled = 0;
for (
$xx = $x - 0.45; $xx < $x + 0.5; $xx+=0.1 ) {
for (
$yy = $y - 0.45; $yy < $y + 0.5; $yy+=0.1 ) {
$rxx = $xx - $cx; $ryy = $yy - $cy;
if (
sqrt(pow($rxx, 2) + pow($ryy, 2)) < $r ) $filled++;
}
}
$red = round($bgcolors['red'] + ( $fgcolors['red'] - $bgcolors['red'] ) * $filled / 100);
$green = round($bgcolors['green'] + ( $fgcolors['green'] - $bgcolors['green'] ) * $filled / 100);
$blue = round($bgcolors['blue'] + ( $fgcolors['blue'] - $bgcolors['blue'] ) * $filled / 100);
imagesetpixel($im, $x, $y, imagecolorclosest($im, $red, $green, $blue));
}
}
}
}

$width = 160;
$height = 200;
$r = 20;
$bgc = "651713";
$fgc = "b12b2c";

$im = imagecreate($width, $height);
$bgcolor = imagecolorallocate($im, hexdec(substr($bgc, 0, 2)), hexdec(substr($bgc, 2, 2)), hexdec(substr($bgc, 4, 2)));
for(
$i = 0; $i < 100; $i++ ) {
imagecolorallocate($im, ( hexdec(substr($fgc, 0, 2)) + $i*hexdec(substr($bgc, 0, 2))) / ($i + 1), ( hexdec(substr($fgc, 2, 2)) + $i*hexdec(substr($bgc, 2, 2))) / ($i + 1), ( hexdec(substr($fgc, 4, 2)) + $i*hexdec(substr($bgc, 4, 2))) / ($i + 1));
}
$fgcolor = imagecolorclosest($im, hexdec(substr($fgc, 0, 2)), hexdec(substr($fgc, 2, 2)), hexdec(substr($fgc, 4, 2)));

imagefilledcircleantialiased($im, 80, 100, $r, $fgcolor, $bgcolor);

header("Content-Type: image/png");
imagepng($im);
?>
An improvement would be to draw the inner rectangle or more rectangles in the circle with the builtin rectangle function to reduce the usage of imagesetpixel() from (2*r)^2 to 2*Pi*(r + epsilon), in other words, the dependency on r would break down from square to linear.
另一个改进是确定观察到的像素中的填充和未填充三角形,并计算它们的面积,这样我们就可以摆脱获取填充/未填充分数的内部循环。
可以很容易地修改此函数来解决其他问题,如直线、未填充圆等。
-3
voinic at NOSgmailPAM dot com
18 年前
我发现的唯一绘制抗锯齿多边形并保持其透明(例如,将其用作 Google 地图中的叠加层)的技巧是... 创建两个图像并将其合并。操作顺序很重要,并且最终图像的透明颜色必须在合并后设置

<?
header("Content-type: image/png");

$values = array(
40, 50, // 点 1 (x, y)
20, 240, // 点 2 (x, y)
60, 60, // 点 3 (x, y)
240, 20, // 点 4 (x, y)
50, 40, // 点 5 (x, y)
10, 10 // 点 6 (x, y)
);

$im = imagecreate(250, 250);
$bg = imagecolorallocate($im, 255, 255, 255);

$im2 = imagecreatetruecolor(250, 250);
$bg2 = imagecolorallocate($im2, 255, 255, 255);
imagefilledrectangle($im2,0,0,249,249,$bg2);
imagecolortransparent($im2, $bg);
imageantialias($im2, true);
$c_red = imagecolorallocate($im2, 255, 0, 0);
imagepolygon($im2, $values, 6, $c_red);
imageantialias($im2, false);

imagecopymerge($im, $im2,0,0,0,0,250,250,50);

imagecolortransparent($im, $bg);
$c_red_alpha = imagecolorallocatealpha($im, 255, 0, 0, 60);
imagefilledpolygon($im, $values, 6, $c_red_alpha);

imagepng($im);
imagedestroy($im);
imagedestroy($im2);
?>
To Top