圖片水印是內容保護、品牌曝光的常用手段。PHP GD 擴展提供豐富的圖像處理函數,本文展示三種代碼風格實現文字/圖片水印:過程式 (適合簡單腳本)、物件導向 (適合複用擴展)、綜合函數 (支援多種位置、格式、類型),並解析關鍵函數用法、透明度控制、記憶體管理。
| 函數 | 用途 |
|---|---|
getimagesize() | 獲取圖片寬高、MIME、類型常數 |
image_type_to_extension() | 類型常數 → 副檔名 (如 IMAGETYPE_JPEG → '.jpg') |
imagecreatefromjpeg/png/gif/webp() | 從檔案/字串建立圖像資源 |
imagecreatetruecolor() | 建立真彩色畫布 (支援透明度) |
imagecolorallocatealpha() | 分配帶 Alpha 通道顏色 (0 不透明 ~ 127 完全透明) |
imagestring() | 繪製固定字體字串 (字體 1-5) |
imagettftext() | 繪製 TrueType 字體文字 (支援中文、旋轉、大小) |
imagecopy() | 複製圖像區塊 (水印圖片疊加) |
imagecopymerge() | 帶透明度合併複製 |
imagejpeg/png/gif/webp() | 輸出圖像到瀏覽器或檔案 |
imagedestroy() | 釋放圖像資源記憶體 |
優缺點
type}";
$this->image = $loadFunc($src);
}
// 文字水印
public function addTextWatermark(int $fontSize, int $x, int $y, array $rgba, string $text): self {
$color = imagecolorallocatealpha($this->image, $rgba[0], $rgba[1], $rgba[2], $rgba[3]);
imagestring($this->image, $fontSize, $x, $y, $text, $color);
return $this; // 鏈式調用
}
// TTF 文字水印 (支援中文、旋轉)
public function addTTFWatermark(string $fontFile, int $size, float $angle, int $x, int $y, array $rgba, string $text): self {
$color = imagecolorallocatealpha($this->image, $rgba[0], $rgba[1], $rgba[2], $rgba[3]);
imagettftext($this->image, $size, $angle, $x, $y, $color, $fontFile, $text);
return $this;
}
// 圖片水印
public function addImageWatermark(string $markSrc, int $x, int $y, int $opacity = 100): self {
$markInfo = getimagesize($markSrc);
$markType = image_type_to_extension($markInfo[2], false);
$loadFunc = "imagecreatefrom{$markType}";
$mark = $loadFunc($markSrc);
// 處理透明度
if ($opacity < 100) {
imagefilter($mark, IMG_FILTER_COLORIZE, 0, 0, 0, (100 - $opacity) * 1.27);
}
imagecopy($this->image, $mark, $x, $y, 0, 0, $markInfo[0], $markInfo[1]);
imagedestroy($mark);
return $this;
}
// 輸出到瀏覽器
public function output(): void {
header('Content-Type: ' . $this->info['mime']);
$outputFunc = "image{$this->type}";
$outputFunc($this->image);
}
// 儲存到檔案
public function save(string $dest): bool {
$saveFunc = "image{$this->type}";
return $saveFunc($this->image, $dest);
}
// 解構釋放
public function __destruct() {
if (is_resource($this->image)) imagedestroy($this->image);
}
}
// 使用範例
$wm = new ImageWatermarker('photo.jpg');
$wm->addTextWatermark(20, 20, 30, [255,255,255,60], 'Copyright 2024')
->addImageWatermark('logo.png', 100, 100, 50)
->output();
imagefilter() 陰影、浮雕、灰階等效果rotate()、resize() 等前置處理WatermarkPosition 策略類 (左上、右下、平鋪、對角線等) [5, 5], // 左上
2 => [($srcW - $markW) / 2, 5], // 上中
3 => [$srcW - $markW - 5, 5], // 右上
4 => [5, ($srcH - $markH) / 2], // 左中
5 => [($srcW - $markW) / 2, ($srcH - $markH) / 2], // 中心
6 => [$srcW - $markW - 5, ($srcH - $markH) / 2], // 右中
7 => [5, $srcH - $markH - 5], // 左下
8 => [($srcW - $markW) / 2, $srcH - $markH - 5], // 下中
9 => [$srcW - $markW - 5, $srcH - $markH - 5], // 右下
];
[$x, $y] = $positions[$markPos];
// 4. 建立真彩色畫布並複製源圖 (保持透明度)
$dst = imagecreatetruecolor($srcW, $srcH);
imagealphablending($dst, true);
imagesavealpha($dst, true);
imagecopy($dst, $srcIm, 0, 0, 0, 0, $srcW, $srcH);
// 5. 疊加水印
if ($markType === 'img') {
imagecopy($dst, $markIm, $x, $y, 0, 0, $markW, $markH);
imagedestroy($markIm);
} elseif ($markType === 'text') {
$rgb = explode(',', $textColor);
$color = imagecolorallocate($dst, $rgb[0], $rgb[1], $rgb[2]);
imagettftext($dst, 16, 0, $x, $y, $color, $fontFile, $markText);
}
// 6. 覆蓋輸出 (保持原格式)
$saveFunc = "image" . image_type_to_extension($srcInfo[2], false);
$saveFunc($dst, $imgSrc);
// 7. 清理
imagedestroy($dst);
imagedestroy($srcIm);
}
// 使用範例
setWaterMark('photo.jpg', '', '© MySite', '255,0,0', 9, 'msyh.ttf', 'text'); // 右下紅字
setWaterMark('photo.jpg', 'logo.png', '', '', 5, '', 'img'); // 中心圖片水印
// 方法一:imagecopymerge (簡單但不支援 Alpha 通道疊加) imagecopymerge($dst, $mark, $x, $y, 0, 0, $w, $h, $opacity); // 方法二:預處理水印圖片 Alpha (推薦) $markAlpha = imagecreatetruecolor($w, $h); imagealphablending($markAlpha, false); imagesavealpha($markAlpha, true); $transparent = imagecolorallocatealpha($markAlpha, 0, 0, 0, 127); imagefill($markAlpha, 0, 0, $transparent); imagecopy($markAlpha, $mark, 0, 0, 0, 0, $w, $h); // 然後 imagecopy($dst, $markAlpha, ...)
imagecreate* 佔用 ~ 寬×高×4 位元組 (真彩色)imagedestroy()memory_limit_wm.jpg,保留無水印原圖備用imagewebp() PHP 5.5+),體積減少 30%+從簡單腳本到企業級服務,水印功能的演進核心在於「職責分離、資源隔離、異步解耦」。選擇適合當前階段的實現風格,預留擴展接口,才能應對業務增長帶來的複雜度。