利用 GD 函式庫動態產生圓形印章圖片,包含外框、內圓、環繞文字與五角星。本文提供兩種實作:物件導向類別與程式碼直寫版,皆支援自訂文字、半徑、字體、顏色等參數。
封裝所有繪圖邏輯,建構子可傳入印章文字、半徑、邊框寬度、五角星半徑、傾斜角度、字體大小、內圓半徑等參數。核心步驟:
createImg():建立真彩色畫布,設定透明背景與紅色筆刷drawRim():以多層 imagearc 疊加形成粗邊框drawInnerCircle():繪製內圓drawString():將文字拆字,依角度平均分佈於圓周,使用 imagettftext 繪製 TrueType 字體drawStart():計算五角星頂點與內凹點座標,以 imagefilledpolygon 填滿outPut():輸出 PNG 並銷毀資源<?php
class circleSeal {
private $sealString, $strMaxLeng=12, $sealRadius, $rimWidth, $innerRadius;
private $startRadius, $startAngle, $charAngle, $centerDot;
private $img, $font, $fontSize, $width, $height, $points, $charRadius, $spacing=1;
private $backGround;
public function __construct($str='', $rad=75, $rmwidth=6, $strad=24, $stang=0, $crang=0, $fsize=16, $inrad=0) {
$this->sealString = empty($str) ? '印章測試字符串' : $str;
$this->sealRadius = $rad; $this->rimWidth = $rmwidth;
$this->startRadius = $strad; $this->startAngle = $stang;
$this->charAngle = $crang; $this->innerRadius = $inrad;
$this->centerDot = array('x'=>$rad, 'y'=>$rad);
$this->font = __DIR__ . '/simkai.ttf'; // 需自備楷體字體檔
$this->fontSize = $fsize;
}
private function createImg() {
$this->width = $this->height = 2 * $this->sealRadius;
$this->img = imagecreate($this->width, $this->height);
imagecolorresolvealpha($this->img, 255,255,255,127); // 透明背景
$this->backGround = imagecolorallocate($this->img, 255,0,0); // 紅色
}
private function drawRim() {
for ($i=0; $i<$this->rimWidth; $i++) {
imagearc($this->img, $this->centerDot['x'], $this->centerDot['y'],
$this->width-$i, $this->height-$i, 0, 360, $this->backGround);
}
}
private function drawInnerCircle() {
if ($this->innerRadius > 0) {
imagearc($this->img, $this->centerDot['x'], $this->centerDot['y'],
2*$this->innerRadius, 2*$this->innerRadius, 0, 360, $this->backGround);
}
}
private function drawString() {
// 編碼轉 UTF-8
$charset = mb_detect_encoding($this->sealString);
if ($charset != 'UTF-8') $this->sealString = mb_convert_encoding($this->sealString, 'UTF-8', 'GBK');
$this->charRadius = $this->sealRadius - $this->rimWidth - $this->fontSize;
$len = mb_strlen($this->sealString, 'utf8');
if ($len > $this->strMaxLeng) $len = $this->strMaxLeng;
$avgAngle = 360 / $this->strMaxLeng;
for ($i=0; $i<$len; $i++) {
$ch = mb_substr($this->sealString, $i, 1, 'utf8');
$r = 630 + $this->charAngle + $avgAngle*($i - $len/2) + $this->spacing*($i-1);
$R = 720 - $this->charAngle + $avgAngle*($len-2*$i-1)/2 + $this->spacing*(1-$i);
$x = $this->centerDot['x'] + $this->charRadius * cos(deg2rad($r));
$y = $this->centerDot['y'] + $this->charRadius * sin(deg2rad($r));
imagettftext($this->img, $this->fontSize, $R, $x, $y, $this->backGround, $this->font, $ch);
}
}
private function drawStart() {
$ang_out = 18 + $this->startAngle;
$ang_in = 56 + $this->startAngle;
$rad_out = $this->startRadius;
$rad_in = $rad_out * 0.382;
$this->points = array();
for ($i=0; $i<5; $i++) {
$this->points[] = $rad_out * cos(2*M_PI/5*$i - deg2rad($ang_out)) + $this->centerDot['x'];
$this->points[] = $rad_out * sin(2*M_PI/5*$i - deg2rad($ang_out)) + $this->centerDot['y'];
$this->points[] = $rad_in * cos(2*M_PI/5*($i+1) - deg2rad($ang_in)) + $this->centerDot['x'];
$this->points[] = $rad_in * sin(2*M_PI/5*($i+1) - deg2rad($ang_in)) + $this->centerDot['y'];
}
imagefilledpolygon($this->img, $this->points, 10, $this->backGround);
}
private function outPut() {
header('Content-type:image/png');
imagepng($this->img);
imagedestroy($this->img);
}
public function doImg() {
$this->createImg();
$this->drawRim();
$this->drawInnerCircle();
$this->drawString();
$this->drawStart();
$this->outPut();
}
}
// 使用範例
// $seal = new circleSeal('你我他坐站走東西南北中', 75, 6, 24, 0, 0, 16, 40);
// $seal->doImg();
?>
透過 $_GET['hos'] 接收文字參數,直接輸出印章圖片。邏輯與類別版相似,但將計算寫在流程中,適合不需複用的場合。
<?php
$hos = isset($_GET['hos']) ? iconv('GBK', 'UTF-8', $_GET['hos']) : '';
if (!$hos) exit;
$im = imagecreate(150,150);
$gray = imagecolorresolvealpha($im,200,200,200,127);
$red = imagecolorallocate($im,230,150,150);
for ($i=0; $i<6; $i++) imagearc($im,75,75,148-$i,148-$i,0,360,$red);
$font = 'C:/Windows/Fonts/simkai.ttf'; // 請依伺服器環境調整路徑
$size = 30;
imagettftext($im,$size,0,72-$size/2,72+$size/2,$red,$font,'★');
$a=75; $b=-75; $r=65; $m=40; $size=16;
$r -= $size;
$word = array();
$max = 18;
$count = mb_strlen($hos,'utf8');
if ($count > $max) $count = $max;
if ($count > 12) $m = floor(360/$count);
elseif ($count > 5) $m -= $count;
for ($i=0; $i<$count; $i++) $word[] = mb_substr($hos,$i,1,'utf8');
$j = floor($count/2);
if ($j != $count/2) { // 奇數字
for ($i=$j; $i>=0; $i--) {
$arc = $m*($j-$i) + $size/2;
$x = round($r*cos((90+$arc)*M_PI/180)) + $a;
$y = -1*(round($r*sin((90+$arc)*M_PI/180)) + $b);
if ($arc < 10) $arc = 0;
imagettftext($im,$size,$arc,$x,$y,$red,$font,$word[$i]);
$arc = $m*($j-$i) - $size/2;
$x = round($r*cos((90-$arc)*M_PI/180)) + $a;
$y = -1*(round($r*sin((90-$arc)*M_PI/180)) + $b);
if ($arc < 10) $arc = 0;
imagettftext($im,$size,-$arc,$x,$y,$red,$font,$word[$j+$j-$i]);
}
} else { // 偶數字
$j--;
for ($i=$j; $i>=0; $i--) {
$arc = $m/2 + $m*($j-$i) + $size/2;
$x = round($r*cos((90+$arc)*M_PI/180)) + $a;
$y = -1*(round($r*sin((90+$arc)*M_PI/180)) + $b);
imagettftext($im,$size,$arc,$x,$y,$red,$font,$word[$i]);
$arc = $m/2 + $m*($j-$i) - $size/2;
$x = round($r*cos((90-$arc)*M_PI/180)) + $a;
$y = -1*(round($r*sin((90-$arc)*M_PI/180)) + $b);
imagettftext($im,$size,-$arc,$x,$y,$red,$font,$word[$j+$j+1-$i]);
}
}
header('Content-Type:image/png');
imagepng($im);
?>
php-gd 且支援 FreeType(imagettftext)。simkai.ttf(楷體)需自行放置於可讀取路徑,或改用其他 TrueType 字體。imagepng($im) 改為 imagepng($im, 'filename.png')。