首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 相關知識

DedeCMS 圖片處理類深度解析:縮略圖、水印、GIF 動畫支持與 GD 底層實現

     編輯:PHP 相關知識

DedeCMS 圖片處理類深度解析:縮略圖、水印、GIF 動畫支持與 GD 底層實現

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
}

構造函數關鍵邏輯

  1. 接收 11 個參數(文件路徑、縮略配置、水印配置等),全部賦值給屬性。
  2. `getimagesize()` 獲取圖片信息(寬、高、MIME、類型常量)。
  3. 根據 MIME 類型映射 GD 函數:
    `image/jpeg` → `imagecreatefromjpeg` / `imagejpeg`
    `image/gif` → `imagecreatefromgif` / `imagegif`
    `image/png` → `imagecreatefrompng` / `imagepng`
  4. 動畫 GIF 檢測:讀取文件內容搜索 `NETSCAPE2.0` 標識,若存在標記 `$this->animatedgif = 1`,後續跳過縮略/水印處理(避免破壞動畫幀)。

二、 縮略圖生成算法 (`thumb_gd`)

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);
    }
}

關鍵點

  • 等比縮放邏輯:以「長邊先達到限制」為準,避免拉伸變形。
  • imagecreatetruecolor + imagecopyresampled:真彩色畫布 + 雙線性插值,質量優於 `imagecopyresized`。
  • 動畫 GIF 保護:`$this->animatedgif` 為真時直接返回,保留原幀數據。
  • 輸出文件命名:`thumbstatus=1` 產生 `.thumb.jpg` 後綴文件,`=2` 覆蓋原文件(風險較大)。

三、 水印系統 (`watermark_gd`)

1. 九宮格位置計算


// $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; // 右下 (默認最常用)
}

2. 三種水印模式實現

類型核心函數關鍵參數特點
圖片水印 PNG (type=1)`imagecopy()`支持 Alpha 透明通道、需 `imagealphablending`效果最好、文件較大
圖片水印 GIF (type=0)`imagecopymerge()``$this->watermarktrans` 透明度 0-100無 Alpha 通道、透明度模擬
文字水印 (type=2)`imagettftext()`字體路徑、大小、顏色、角度、陰影無需外部文件、動態生成

3. 文字水印細節


// 字體邊界框計算
$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);

4. 圖片水印透明度處理

  • PNG 水印:`imagealphablending($logo, true); imagecopy($dst, $logo, ...)` 直接利用 Alpha 通道。
  • GIF 水印:`imagecopymerge($dst, $logo, $x, $y, 0,0, $lw, $lh, $trans)` 模擬透明度(無真 Alpha)。
  • 輸出時 JPEG 指定 `$this->watermarkquality`(默認 75-90),PNG/GIF 無損。

四、 公共入口方法

// 生成縮略圖(可選預覽模式)
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 到 ImageMagick/Intervention Image

痛點GD 限制現代方案
大圖內存溢出`imagecreatetruecolor` 需連續內存,2000w+ 像素易 OOMImagick 流式處理、分塊處理
格式支持有限不支持 WebP、AVIF、HEIC、TIFF 多頁ImageMagick 原生支持 200+ 格式
文字渲染差`imagettftext` 無哈勁、無 RTL、行間距控制弱Imagick `annotateImage` / `drawText` 支持完整排版
動畫處理僅能檢測、無法保持幀生成縮略/水印Imagick `coalesceImages` 逐幀處理後重組
色彩管理無 ICC 配置文件支持、CMYK 處理極差完整色彩空間轉換、Soft Proofing

遷移代碼片段(Intervention Image v3)

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);

六、 安全加固清單

  1. 文件類型驗證:上傳後必須 `getimagesize()` 驗證 MIME,禁止依賴擴展名/Content-Type。
  2. 路徑遍歷防護:`$targetfile` 需 `realpath()` 確保在允許目錄內,拒絕 `../`。
  3. 資源限制:`ini_set('memory_limit', '256M'); set_time_limit(60);` 防止惡意大圖拖垮進程。
  4. 錯誤抑制移除:去除 `@` 運算符,捕獲 `GdException` (PHP 8.1+) 記錄日志。
  5. 輸出清理:`imagedestroy($src); imagedestroy($dst);` 及時釋放 GD 內存資源。

DedeCMS 的 `image.class.php` 體現了 PHP 早期 GD 封裝的典型模式:功能完整、參數靈活、但缺乏現代錯誤處理、內存管理與格式支持。維護老項目時建議保留兼容層,新業務直接引入 Intervention Image + Imagick 驅動,享受現代化 API 與強大功能。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved