直線是幾何繪圖的最小單元。PHP GD 的 imageline() 函數雖參數簡單,但掌握其座標系、顏色分配、線型樣式 (虛線/點線/粗線) 及組合幾何邏輯,是繪製坐標系、折線圖、幾何圖形、網格、連接線等所有線條類視覺元件的基礎。本文將從基礎參數到進階線型模擬、抗鋸齒策略全方位講解。
bool imageline (
resource $image,
int $x1, int $y1, // 起點座標
int $x2, int $y2, // 終點座標
int $color // 線條顏色 (imagecolorallocate 返回)
);
<?php
$im = imagecreatetruecolor(400, 300);
$white = imagecolorallocate($im, 255,255,255);
$black = imagecolorallocate($im, 0,0,0);
$red = imagecolorallocate($im, 255,0,0);
$blue = imagecolorallocate($im, 0,0,255);
imagefill($im, 0, 0, $white);
// 1. 基本直線:左上(30,30) 到 右下(370,270)
imageline($im, 30, 30, 370, 270, $red);
// 2. 水平線:Y固定
imageline($im, 50, 150, 350, 150, $blue);
// 3. 垂直線:X固定
imageline($im, 200, 50, 200, 250, $blue);
// 4. 對角線 (45度) - 視覺上因像素比例可能不呈現標準45度
imageline($im, 100, 100, 300, 300, $black); // 實際超出畫布
header('Content-Type: image/png');
imagepng($im);
imagedestroy($im);
?>
function imageline_thick($im, $x1, $y1, $x2, $y2, $color, $thickness = 3) {
if ($thickness <= 1) return imageline($im, $x1, $y1, $x2, $y2, $color);
// 計算垂直於線條的單位向量 (dx, dy)
$dx = $x2 - $x1;
$dy = $y2 - $y1;
$len = sqrt($dx*$dx + $dy*$dy);
if ($len == 0) return;
// 單位法向量 (垂直於線段)
$nx = -$dy / $len;
$ny = $dx / $len;
$half = ($thickness - 1) / 2;
for ($i = -$half; $i <= $half; $i++) {
$offsetX = $nx * $i;
$offsetY = $ny * $i;
imageline($im,
$x1 + $offsetX, $y1 + $offsetY,
$x2 + $offsetX, $y2 + $offsetY,
$color
);
}
}
function imageline_dashed($im, $x1, $y1, $x2, $y2, $color, $dashLen = 10, $gapLen = 5) {
$dx = abs($x2 - $x1);
$dy = abs($y2 - $y1);
$sx = ($x1 < $x2) ? 1 : -1;
$sy = ($y1 < $y2) ? 1 : -1;
$err = $dx - $dy;
$len = 0; // 當前虛線段長度
$draw = true; // 是否繪製像素
while (true) {
if ($draw) imagesetpixel($im, $x1, $y1, $color);
$len++;
if ($draw && $len >= $dashLen) { $draw = false; $len = 0; }
elseif (!$draw && $len >= $gapLen) { $draw = true; $len = 0; }
if ($x1 === $x2 && $y1 === $y2) break;
$e2 = 2 * $err;
if ($e2 > -$dy) { $err -= $dy; $x1 += $sx; }
if ($e2 < $dx) { $err += $dx; $y1 += $sy; }
}
}
function imageline_arrow($im, $x1, $y1, $x2, $y2, $color, $arrowSize = 10, $arrowAngle = 30) {
imageline($im, $x1, $y1, $x2, $y2, $color); // 主線
$angle = atan2($y1 - $y2, $x2 - $x1); // 線段角度 (注意 Y 軸反轉)
$arrowAngleRad = deg2rad($arrowAngle);
// 箭頭兩翼終點
$x3 = $x2 + $arrowSize * cos($angle + $arrowAngleRad);
$y3 = $y2 - $arrowSize * sin($angle + $arrowAngleRad); // Y反轉
$x4 = $x2 + $arrowSize * cos($angle - $arrowAngleRad);
$y4 = $y2 - $arrowSize * sin($angle - $arrowAngleRad);
imageline($im, $x2, $y2, $x3, $y3, $color);
imageline($im, $x2, $y2, $x4, $y4, $color);
// 可選:填滿箭頭三角形
// imagefilledpolygon($im, [$x2,$y2, $x3,$y3, $x4,$y4], 3, $color);
}
| 方法 | 原理 | 優點 | 缺點 |
|---|---|---|---|
imageantialias($im, true) | GD 內建抗鋸齒 (僅支援真彩色、線條/多邊形) | 零成本開啟 | 效果有限,僅邊緣像素混合,不支援粗線/虛線 |
| 超採樣 (2x/4x 縮放) | 大畫布繪製 → imagescale($im, $w/2, $h/2, IMG_BICUBIC) | 效果最佳,接近向量級 | 記憶體/CPU 成倍增長 |
| ImageMagick (Imagick) | 專業圖形庫,真正向量渲染 | 完美抗鋸齒、粗線、虛線、漸變線 | 需安裝擴展,部署較複雜 |
| 前端 Canvas/SVG | 瀏覽器原生向量繪圖 | 零後端負擔、互動動畫、完美畫質 | 需前端實現,無法直接生成圖片下載 |
function drawLineChart($data, $width=600, $height=400, $padding=50) {
$im = imagecreatetruecolor($width, $height);
imageantialias($im, true);
$white = imagecolorallocate($im, 255,255,255);
$grid = imagecolorallocate($im, 230,230,230);
$axis = imagecolorallocate($im, 100,100,100);
$line = imagecolorallocate($im, 52, 152, 219);
imagefill($im, 0, 0, $white);
$maxVal = max($data); $minVal = min($data);
$range = $maxVal - $minVal ?: 1;
$count = count($data);
$stepX = ($width - 2*$padding) / max(1, $count-1);
// 畫網格與座標軸 ...
// 畫折線
for ($i = 0; $i < $count-1; $i++) {
$x1 = $padding + $i * $stepX;
$y1 = $height - $padding - (($data[$i] - $minVal) / $range) * ($height - 2*$padding);
$x2 = $padding + ($i+1) * $stepX;
$y2 = $height - $padding - (($data[$i+1] - $minVal) / $range) * ($height - 2*$padding);
imageline($im, $x1, $y1, $x2, $y2, $line);
}
return $im;
}
function drawPolygon($im, $cx, $cy, $radius, $sides, $color, $rotation = -90) {
$points = [];
for ($i = 0; $i < $sides; $i++) {
$angle = deg2rad($rotation + $i * 360 / $sides);
$points[] = $cx + $radius * cos($angle);
$points[] = $cy + $radius * sin($angle); // GD Y向下,sin 正常
}
// 使用 imagepolygon (自動閉合) 或 imageline 迴圈
imagepolygon($im, $points, $sides, $color); // 空心
// imagefilledpolygon($im, $points, $sides, $color); // 實心
}
function drawGrid($im, $step = 20, $color = 0xEEEEEE, $majorStep = 100, $majorColor = 0xDDDDDD) {
$w = imagesx($im); $h = imagesy($im);
// 垂直線
for ($x = 0; $x <= $w; $x += $step) {
$c = ($x % $majorStep === 0) ? $majorColor : $color;
imageline($im, $x, 0, $x, $h, $c);
}
// 水平線
for ($y = 0; $y <= $h; $y += $step) {
$c = ($y % $majorStep === 0) ? $majorColor : $color;
imageline($im, 0, $y, $w, $y, $c);
}
}
sin/cos 配合 GD 時,Y 分量**不取反** (因為數學 Y 向上,GD Y 向下,sin 正好抵消)。但 atan2($dy, $dx) 計算角度時,$dy = $y1 - $y2 (目標 - 起點,補償 Y 反轉)。imageantialias($im, true);大尺度場景採用超採樣縮放。imagealphablending(true) + imagesavealpha(true) + imagecolorallocatealpha(..., alpha)。imageline() 是 GD 繪圖的**幾何原子**。核心掌握點:
imageline 迴圈組合而成。若專案對線條畫質、樣式豐富度、效能有高要求,**強烈建議遷移至 ImageMagick (Imagick 擴展) 或前端 Canvas/SVG**。GD 適合簡單、低併發、無複雜線型需求的圖片生成場景。