為圖片添加水印是保護版權、品牌推廣的常見需求。本文提供一個健壯、可復用的 img_water_mark() 函數,支援主流圖片格式、9 種定位模式、透明度控制,並包含完善的錯誤碼返回機制。
<?php
/**
* 圖片加水印(支援 png/jpg/gif)
*
* @param string $srcImg 原圖路徑
* @param string $waterImg 水印圖路徑
* @param string $savepath 保存目錄(預設同原圖目錄)
* @param string $savename 保存檔名(預設同原圖檔名)
* @param int $position 水印位置 1~9(參見下方說明)
* @param int $alpha 透明度 0~100(0 全透明,100 不透明)
* @return string|int 成功返回新圖路徑,失敗返回負數錯誤碼
*/
function img_water_mark($srcImg, $waterImg, $savepath = null, $savename = null, $position = 5, $alpha = 30) {
// 1. 解析原圖路徑資訊
$info = pathinfo($srcImg);
$name = $info['basename'];
$dir = $info['dirname'];
$ext = $info['extension'];
$savename = $savename ?: $name;
$savepath = $savepath ?: $dir;
$savefile = $savepath . '/' . $savename;
// 2. 取得圖片尺寸與類型
$srcInfo = @getimagesize($srcImg);
$waterInfo = @getimagesize($waterImg);
if (!$srcInfo) return -1; // 原文件不存在
if (!$waterInfo) return -2; // 水印文件不存在
// 3. 建立 GD 圖像資源
$srcObj = image_create_from_ext($srcImg);
$waterObj = image_create_from_ext($waterImg);
if (!$srcObj) return -3; // 原圖資源建立失敗
if (!$waterObj) return -4; // 水印資源建立失敗
// 4. 計算水印座標(9 宮格定位)
$srcW = $srcInfo[0]; $srcH = $srcInfo[1];
$watW = $waterInfo[0]; $watH = $waterInfo[1];
switch ($position) {
case 1: $x = 0; $y = 0; break; // 左上
case 2: $x = $srcW - $watW; $y = 0; break; // 右上
case 3: $x = ($srcW - $watW)/2; $y = ($srcH - $watH)/2; break; // 居中
case 4: $x = 0; $y = $srcH - $watH; break; // 左下
case 5: $x = $srcW - $watW; $y = $srcH - $watH; break; // 右下(預設)
case 6: $x = ($srcW - $watW)/2; $y = 0; break; // 頂部居中
case 7: $x = ($srcW - $watW)/2; $y = $srcH - $watH; break; // 底部居中
case 8: $x = 0; $y = ($srcH - $watH)/2; break; // 左側居中
case 9: $x = $srcW - $watW; $y = ($srcH - $watH)/2; break; // 右側居中
default: $x = $y = 0;
}
// 5. 合併圖片(支援透明度)
imagecopymerge($srcObj, $waterObj, $x, $y, 0, 0, $watW, $watH, $alpha);
// 6. 按原格式輸出
switch ($srcInfo[2]) {
case IMAGETYPE_GIF: imagegif($srcObj, $savefile); break;
case IMAGETYPE_JPEG: imagejpeg($srcObj, $savefile); break;
case IMAGETYPE_PNG: imagepng($srcObj, $savefile); break;
default: return -5; // 不支援格式
}
// 7. 釋放資源
imagedestroy($srcObj);
imagedestroy($waterObj);
return $savefile;
}
/**
* 根據副檔名/MIME 建立 GD 資源
*/
function image_create_from_ext($imgfile) {
$info = @getimagesize($imgfile);
if (!$info) return null;
switch ($info[2]) {
case IMAGETYPE_GIF: return imagecreatefromgif($imgfile);
case IMAGETYPE_JPEG: return imagecreatefromjpeg($imgfile);
case IMAGETYPE_PNG: return imagecreatefrompng($imgfile);
default: return null;
}
}
?>
<?php
// 右下角、透明度 50%、另存為新檔
$result = img_water_mark(
'uploads/photo.jpg',
'assets/watermark.png',
'uploads/watermarked',
'photo_wm.jpg',
5, // 位置:右下
50 // 透明度 50%
);
if (is_int($result) && $result < 0) {
$errors = [
-1 => '原圖不存在', -2 => '水印圖不存在',
-3 => '原圖資源建立失敗', -4 => '水印資源建立失敗', -5 => '儲存失敗'
];
exit('錯誤:' . $errors[$result]);
}
echo '水印已生成:' . $result;
?>
getimagesize() 返回的索引 2(IMAGETYPE_* 常量)判斷格式,避免副檔名欺騙。imagecopymerge() 最後一個參數控制不透明度(0~100),PNG 水印若本身含 Alpha 通道效果更佳。imagedestroy() 防止記憶體洩漏,批量處理時尤為重要。memory_limit 或分塊處理。imagettftext() 繪製 TTF 字體文字,支援中文、旋轉、陰影。glob(),建議加入進度條與錯誤日誌。