驗證碼、水印、動態簽名檔、圖表標籤、社群分享圖 (OG Image) 等需求,伺服器端即時繪製文字輸出 PNG。
<?php
/**
* 文字轉 PNG 圖片類別
* 用法:
*/
class TextPNG
{
// 預設屬性
private $font = __DIR__ . '/fonts/DejaVuSans.ttf'; // 必須存在 TTF 檔
private $text = 'Sample';
private $size = 24;
private $angle = 0; // 旋轉角度 (度)
private $padding = 10; // 邊距
private $transparent = true; // 背景透明
private $color = [0, 0, 0]; // RGB 文字色
private $bgColor = [255, 255, 255]; // RGB 背景色
// 設定器 (鏈式呼叫)
public function setFont($font) { $this->font = $font; return $this; }
public function setText($text) { $this->text = $text; return $this; }
public function setSize($size) { $this->size = (int)$size; return $this; }
public function setAngle($angle) { $this->angle = (int)$angle; return $this; }
public function setPadding($padding) { $this->padding = (int)$padding; return $this; }
public function setTransparent($bool) { $this->transparent = (bool)$bool; return $this; }
public function setColor(array $rgb) { $this->color = $rgb; return $this; }
public function setBgColor(array $rgb) { $this->bgColor = $rgb; return $this; }
// 解析 GET 參數 (方便直接
)
public function parseRequest()
{
$map = [
'font' => 'setFont',
'msg' => 'setText',
'size' => 'setSize',
'rot' => 'setAngle',
'pad' => 'setPadding',
'tr' => 'setTransparent',
'r' => fn($v) => $this->setColor([(int)$v, $this->color[1], $this->color[2]]),
'g' => fn($v) => $this->setColor([$this->color[0], (int)$v, $this->color[2]]),
'b' => fn($v) => $this->setColor([$this->color[0], $this->color[1], (int)$v]),
'br' => fn($v) => $this->setBgColor([(int)$v, $this->bgColor[1], $this->bgColor[2]]),
'bg' => fn($v) => $this->setBgColor([$this->bgColor[0], (int)$v, $this->bgColor[2]]),
'bb' => fn($v) => $this->setBgColor([$this->bgColor[0], $this->bgColor[1], (int)$v]),
];
foreach ($_GET as $k => $v) {
if (isset($map[$k])) {
$map[$k]($v);
}
}
}
// 核心繪圖
public function render()
{
// 1. 計算邊界
$box = imagettfbbox($this->size, $this->angle, $this->font, $this->text);
if (!$box) throw new RuntimeException("字型載入失敗: {$this->font}");
// 文字實際寬高
$textWidth = max($box[2], $box[4]) - min($box[0], $box[6]);
$textHeight = max($box[1], $box[3]) - min($box[5], $box[7]);
// 旋轉後畫布尺寸計算 (簡化:以外接矩形)
$width = $textWidth + $this->padding * 2;
$height = $textHeight + $this->padding * 2;
// 2. 建立畫布
$img = imagecreatetruecolor($width, $height);
$bg = imagecolorallocate($img, ...$this->bgColor);
$fg = imagecolorallocate($img, ...$this->color);
if ($this->transparent) {
imagecolortransparent($img, $bg);
} else {
imagefill($img, 0, 0, $bg);
}
// 3. 繪製文字 (基準點 左下角)
$x = $this->padding - min($box[0], $box[6]);
$y = $this->padding + $textHeight - min($box[1], $box[3]); // 基線校正
imagettftext($img, $this->size, $this->angle, $x, $y, $fg, $this->font, $this->text);
// 4. 輸出
header('Content-Type: image/png');
header('Cache-Control: public, max-age=31536000'); // 1 年快取
imagepng($img);
imagedestroy($img);
}
}
// ===== 入口腳本 =====
$png = new TextPNG();
$png->parseRequest()->render();
?>
fonts/ 目錄,確保 PHP 讀取權限。__DIR__ . '/fonts/DejaVuSans.ttf',可透過 ?font=fonts/YourFont.ttf 覆蓋。| 參數 | 說明 | 範例 |
|---|---|---|
msg | 文字內容 (URL encode) | msg=Hello%20World |
size | 字體大小 (pt) | size=32 |
rot | 旋轉角度 (度) | rot=15 |
pad | 邊距 (px) | pad=20 |
tr | 透明背景 (0/1) | tr=0 |
r,g,b | 文字 RGB (0-255) | r=255&g=0&b=0 (紅色) |
br,bg,bb | 背景 RGB | br=0&bg=0&bb=0 (黑底) |
font | 字型相對路徑 | font=fonts/NotoSansCJKtc-Regular.otf |
<img src="text_png.php?msg=PHP%20GD%20%E5%8B%95%E6%85%8B%E5%9C%96%E7%89%87&size=28&r=ffffff&br=000000&pad=15" alt="動態圖片">
<!-- 驗證碼範例 -->
<img id="captcha" src="captcha.php" onclick="this.src='captcha.php?'+Date.now()">
<script>
// captcha.php 內部 Session 儲存驗證碼,文字透過 $png->setText($_SESSION['captcha'])
</script>
imagettftext。imagefttext (FreeType2) 參數控制,或縮放高解析度再 imagecopyresampled 縮小。msg 長度、過濾控制字元、設定 Content-Security-Policy。