DedeCMS (織夢) 內置的 `image.class.php` 是一個經典的 GD 庫封裝,支援縮略圖生成、圖片/文字水印、多格式處理、動畫 GIF 檢測等功能。本文深度剖析其核心邏輯、參數流轉、關鍵算法與擴展點,為二次開發、遷移重構提供參考。
class image {
// 配置屬性(由構造函數注入)
public $thumbstatus; // 縮略圖模式:1=強制覆蓋原圖, 2=生成單獨文件
public $watermarkstatus; // 水印位置 1-9 (九宮格)
public $watermarktype; // 1=圖片水印, 2=文字水印
public $watermarktext; // 文字水印配置 [text, font, size, color, angle, shadow...]
public $watermarktrans; // 透明度 0-100
public $watermarkquality; // JPEG 輸出質量
// 運行時屬性
public $targetfile; // 目標文件路徑
public $attachinfo; // getimagesize() 返回數組
public $imagecreatefromfunc; // 對應格式的創建函數名
public $imagefunc; // 對應格式的輸出函數名
public $animatedgif; // 是否為動畫 GIF
}
public function thumb_gd(int $thumbwidth, int $thumbheight, int $preview = 0) {
// 前置檢查:開啟縮略、GD 函數存在、非動畫 GIF、原圖超過目標尺寸
if (!$this->thumbstatus || !$this->imagecreatefromfunc || $this->animatedgif) return;
if ($this->attachinfo[0] < $thumbwidth && $this->attachinfo[1] < $thumbheight) return;
// 計算目標尺寸(等比縮放,長邊優先)
$x_ratio = $thumbwidth / $imagewidth;
$y_ratio = $thumbheight / $imageheight;
if ($x_ratio * $imageheight < $thumbheight) {
$thumb['height'] = ceil($x_ratio * $imageheight);
$thumb['width'] = $thumbwidth;
} else {
$thumb['width'] = ceil($y_ratio * $imagewidth);
$thumb['height'] = $thumbheight;
}
// 目標文件名
$targetfile = $preview ? './watermark_tmp.jpg'
: ($this->thumbstatus == 1 ? $this->targetfile.'.thumb.jpg' : $this->targetfile);
// 核心 GD 操作
$src = $this->imagecreatefromfunc($this->targetfile);
$dst = imagecreatetruecolor($thumb['width'], $thumb['height']);
imagecopyresampled($dst, $src, 0,0, 0,0, $thumb['width'], $thumb['height'], $imagewidth, $imageheight);
// 輸出(JPEG 強制質量 100,其他格式默認)
if ($this->attachinfo['mime'] == 'image/jpeg') {
imagejpeg($dst, $targetfile, 100);
} else {
$this->imagefunc($dst, $targetfile);
}
}
// $wmwidth = 圖片寬 - 水印寬; $wmheight = 圖片高 - 水印高
switch ($this->watermarkstatus) {
case 1: $x=5; $y=5; break; // 左上
case 2: $x=($wmwidth)/2; $y=5; break; // 上中
case 3: $x=$wmwidth-5; $y=5; break; // 右上
case 4: $x=5; $y=($wmheight)/2; break; // 左中
case 5: $x=($wmwidth)/2; $y=($wmheight)/2; break; // 正中心
case 6: $x=$wmwidth-5; $y=($wmheight)/2; break; // 右中
case 7: $x=5; $y=$wmheight-5; break; // 左下
case 8: $x=($wmwidth)/2; $y=$wmheight-5; break; // 下中
case 9: $x=$wmwidth-5; $y=$wmheight-5; break; // 右下 (默認最常用)
}
| 類型 | 核心函數 | 關鍵參數 | 特點 |
|---|---|---|---|
| 圖片水印 PNG (type=1) | `imagecopy()` | 支持 Alpha 透明通道、需 `imagealphablending` | 效果最好、文件較大 |
| 圖片水印 GIF (type=0) | `imagecopymerge()` | `$this->watermarktrans` 透明度 0-100 | 無 Alpha 通道、透明度模擬 |
| 文字水印 (type=2) | `imagettftext()` | 字體路徑、大小、顏色、角度、陰影 | 無需外部文件、動態生成 |
// 字體邊界框計算
$box = imagettfbbox($size, $angle, $fontpath, $text);
$logowidth = max($box[2],$box[4]) - min($box[0],$box[6]);
$logoheight = max($box[1],$box[3]) - min($box[5],$box[7]);
$ax = min($box[0],$box[6]) * -1; // 基線偏移修正
$ay = min($box[5],$box[7]) * -1;
// 陰影繪製
if ($shadowx || $shadowy) {
$shadowColor = imagecolorallocate($dst, ...$shadowRgb);
imagettftext($dst, $size, $angle, $x+$ax+$shadowx, $y+$ay+$shadowy, $shadowColor, $fontpath, $text);
}
// 主文字
$color = imagecolorallocate($dst, ...$textRgb);
imagettftext($dst, $size, $angle, $x+$ax, $y+$ay, $color, $fontpath, $text);
// 生成縮略圖(可選預覽模式)
public function thumb(int $w, int $h, int $preview = 0) {
$this->thumb_gd($w, $h, $preview);
// 縮略後若需水印,重新獲取圖片信息
if ($this->thumbstatus == 2 && $this->watermarkstatus) {
$this->image($this->targetfile, $this->attach);
$this->attach['size'] = filesize($this->targetfile);
}
}
// 添加水印
public function watermark(int $preview = 0) {
// 尺寸檢查:圖片小於最小水印尺寸則跳過
if ($this->watermarkminwidth && $this->attachinfo[0] <= $this->watermarkminwidth) return;
if ($this->watermarkminheight && $this->attachinfo[1] <= $this->watermarkminheight) return;
$this->watermark_gd($preview);
}
| 痛點 | GD 限制 | 現代方案 |
|---|---|---|
| 大圖內存溢出 | `imagecreatetruecolor` 需連續內存,2000w+ 像素易 OOM | Imagick 流式處理、分塊處理 |
| 格式支持有限 | 不支持 WebP、AVIF、HEIC、TIFF 多頁 | ImageMagick 原生支持 200+ 格式 |
| 文字渲染差 | `imagettftext` 無哈勁、無 RTL、行間距控制弱 | Imagick `annotateImage` / `drawText` 支持完整排版 |
| 動畫處理 | 僅能檢測、無法保持幀生成縮略/水印 | Imagick `coalesceImages` 逐幀處理後重組 |
| 色彩管理 | 無 ICC 配置文件支持、CMYK 處理極差 | 完整色彩空間轉換、Soft Proofing |
use Intervention\Image\ImageManager;
use Intervention\Image\Drivers\Gd\Driver; // 或 Imagick\Driver
$manager = new ImageManager(new Driver());
// 縮略
$img = $manager->read($sourcePath);
$img->scaleDown(width: 800, height: 600);
$img->save($thumbPath, quality: 85);
// 水印(圖片/文字統一 API)
$watermark = $manager->read('logo.png')->opacity(0.5);
$img->place($watermark, 'bottom-right', 20, 20);
$img->save($outputPath);
// 文字水印
$img->text('版權所有', 200, 50, function($font) {
$font->file('fonts/msyh.ttf');
$font->size(24);
$font->color('#ffffff');
$font->align('right');
})->save($outputPath);
DedeCMS 的 `image.class.php` 體現了 PHP 早期 GD 封裝的典型模式:功能完整、參數靈活、但缺乏現代錯誤處理、內存管理與格式支持。維護老項目時建議保留兼容層,新業務直接引入 Intervention Image + Imagick 驅動,享受現代化 API 與強大功能。