在 PHP GD 圖形處理中,向圖片寫入文字是高頻需求。GD 提供了兩組核心函數:imagestring() (內建字體) 與 imagettftext() (TrueType 字體)。兩者在**中文支援、字體靈活度、文字大小、旋轉角度**等方面存在本質差異。本文將透過實戰代碼對比,幫助你選擇最適合的方案。
<?php
// 1. 建立真彩色畫布 (300x200)
$im = imagecreatetruecolor(300, 200);
// 2. 分配顏色:紅色
$red = imagecolorallocate($im, 255, 0, 0);
// 3. 寫入英文字串
$str = "Hello, World!";
/* imagestring 參數:
$im, $font(1-5), $x, $y, $string, $color
座標 (x,y) 為文字左上角基準點
*/
imagestring($im, 5, 30, 60, $str, $red);
// 4. 輸出並銷毀
header("Content-Type: image/png");
imagepng($im);
imagedestroy($im);
?>
| 特性 | imagestring() | imagettftext() |
|---|---|---|
| 中文支援 | ❌ 不支援 | ✅ 完美支援 (需 UTF-8) |
| 字體選擇 | 僅 5 種內建 | 任意 .ttf/.ttc 字體檔 |
| 字體大小 | 固定 1-5 號 | 任意點數 (pt),無上限 |
| 文字旋轉 | 僅水平 | 任意角度 (度數) |
| 抗鋸齒 | 無 | 自動抗鋸齒,渲染品質高 |
| 效能 | 極高 | 較低 (需解析字體輪廓) |
<?php
// 1. 建立畫布
$im = imagecreatetruecolor(400, 200);
$red = imagecolorallocate($im, 255, 0, 0);
// 2. 【關鍵】確保字串為 UTF-8 編碼
// 若 PHP 檔案已儲存為 UTF-8,直接賦值即可
$str = "北京,你好!Hello, World!";
/*
若檔案為 GB2312/Big5 編碼,必須轉換:
$str = iconv('GB2312', 'UTF-8', '北京,你好!Hello, World!');
*/
// 3. 字體路徑 (需確保檔案存在且可讀)
$fontPath = __DIR__ . '/fonts/msjh.ttc'; // 微軟正黑體
// 4. 繪製文字
/* imagettftext 參數:
$im, $size(pt), $angle(度), $x, $y, $color, $fontfile, $text
座標 (x,y) 為文字**基準線左端點** (非左上角)
$angle: 0=水平,正值=逆時針旋轉
*/
imagettftext($im, 24, 0, 20, 80, $red, $fontPath, $str);
// 5. 輸出
header("Content-Type: image/png");
imagepng($im);
imagedestroy($im);
?>
需自行計算字寬,拆分字串。參考邏輯:
function imagettftext_wrap($im, $size, $angle, $x, $y, $color, $font, $text, $maxWidth, $lineHeight) {
$words = preg_split('/(?<=.)/u', $text); // 按字符分割 (支援中文)
$line = '';
$lines = [];
foreach ($words as $char) {
$testLine = $line . $char;
$bbox = imagettfbbox($size, $angle, $font, $testLine);
$width = $bbox[2] - $bbox[0];
if ($width > $maxWidth && $line !== '') {
$lines[] = $line;
$line = $char;
} else {
$line = $testLine;
}
}
$lines[] = $line;
foreach ($lines as $i => $line) {
$lineY = $y + $i * $lineHeight;
imagettftext($im, $size, $angle, $x, $lineY, $color, $font, $line);
}
return count($lines);
}
利用 imagettfbbox() 獲取文字邊界框,計算實際寬高,反推起始座標:
$bbox = imagettfbbox($size, $angle, $font, $text);
$textWidth = $bbox[2] - $bbox[0];
$textHeight = $bbox[1] - $bbox[7];
// 置中對齊
$x = ($imgWidth - $textWidth) / 2;
$y = ($imgHeight + $textHeight) / 2; // 近似垂直置中
imagettftext($im, $size, $angle, $x, $y, $color, $font, $text);
$shadowColor = imagecolorallocate($im, 0, 0, 0); // 黑色陰影
$offset = 2;
// 先畫陰影 (偏移 2px)
imagettftext($im, $size, $angle, $x+$offset, $y+$offset, $shadowColor, $font, $text);
// 再畫主文字
imagettftext($im, $size, $angle, $x, $y, $color, $font, $text);
| 場景 | 推薦函數 | 理由 |
|---|---|---|
| 純英文/數字/簡單驗證碼 | imagestring() | 零依賴、極速、代碼極簡 |
| 含中文、需自訂字體、商業海報、水印 | imagettftext() | 專業渲染、完整中文支援、無限擴展性 |
| 高性能、高並發圖片生成 | 考慮 Swoole + GD 或 ImageMagick | GD 為同步阻塞,高併發下易成瓶頸 |
**結論**:現代 Web 開發中,**imagettftext() 應為預設首選**。除非極度簡單的純英文場景,否則其靈活度與渲染品質遠超 `imagestring()`。請務必採用 **UTF-8 編碼** 專案與 **開源授權字體**,構建健壯的圖文生成服務。