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

PHP 圖片加浮水印完整實作:支援 PNG/JPG/GIF、九宮格定位、透明度控制與錯誤處理

     編輯:PHP 相關知識

為圖片新增浮水印是版權保護、品牌曝光的常見需求。本文提供支援 **PNG/JPG/GIF** 三格式、九宮格定位、Alpha 透明度控制、完整錯誤碼回傳的生產級函式 `img_water_mark()`,並解析 GD 庫圖片資源建立與合成細節。

核心函式:img_water_mark()

<?php
/**
 * 圖片加浮水印
 * @param string $srcImg 源圖路徑
 * @param string $waterImg 浮水印圖路徑 (建議 PNG 含透明通道)
 * @param string|null $savePath 儲存目錄 (null=源圖目錄)
 * @param string|null $saveName 儲存檔名 (null=源圖檔名)
 * @param int $position 1-9 九宮格 (1=左上, 3=中上, 5=右下預設, 9=右下)
 * @param int $alpha 透明度 0-100 (0=全透明, 100=不透明)
 * @return string|int 成功回傳新檔路徑,失敗回傳負數錯誤碼
 */
function img_water_mark(
    string $srcImg,
    string $waterImg,
    ?string $savePath = null,
    ?string $saveName = null,
    int $position = 5,
    int $alpha = 30
): string|int {
    // 1. 解析源圖資訊
    $srcInfo = @getimagesize($srcImg);
    if (!$srcInfo) return -1; // 源圖不存在或非圖片

    $waterInfo = @getimagesize($waterImg);
    if (!$waterInfo) return -2; // 浮水印不存在或非圖片

    // 2. 建立 GD 圖片資源 (支援三格式)
    $srcRes = image_create_from_ext($srcImg);
    if (!$srcRes) return -3; // 源圖資源建立失敗

    $waterRes = image_create_from_ext($waterImg);
    if (!$waterRes) return -4; // 浮水印資源建立失敗

    // 3. 開啟 Alpha 混合 (關鍵:保持浮水印透明度)
    imagealphablending($srcRes, true);
    imagesavealpha($srcRes, true);
    imagealphablending($waterRes, true);
    imagesavealpha($waterRes, true);

    // 4. 計算九宮格座標
    [$dstX, $dstY] = calculate_position($srcInfo, $waterInfo, $position);

    // 5. 合成 (imagecopymerge 支援透明度)
    // 注意:imagecopymerge 對 PNG Alpha 通道支援有限,純 PNG 疊加建議用 imagecopy
    if ($waterInfo[2] === IMAGETYPE_PNG && $alpha >= 100) {
        imagecopy($srcRes, $waterRes, $dstX, $dstY, 0, 0, $waterInfo[0], $waterInfo[1]);
    } else {
        imagecopymerge($srcRes, $waterRes, $dstX, $dstY, 0, 0, $waterInfo[0], $waterInfo[1], $alpha);
    }

    // 6. 依源圖格式儲存
    $saveFile = ($savePath ?? dirname($srcImg)) . '/' . ($saveName ?? basename($srcImg));
    $result = match ($srcInfo[2]) {
        IMAGETYPE_GIF  => imagegif($srcRes, $saveFile),
        IMAGETYPE_JPEG => imagejpeg($srcRes, $saveFile, 90), // 品質 90
        IMAGETYPE_PNG  => imagepng($srcRes, $saveFile, 6),   // 壓縮 6
        default => false
    };

    // 7. 清理資源
    imagedestroy($srcRes);
    imagedestroy($waterRes);

    return $result ? $saveFile : -5; // 儲存失敗
}

// 輔助:根據副檔名/MIME 建立資源
function image_create_from_ext(string $file): \GdImage|false {
    $info = @getimagesize($file);
    return match ($info[2] ?? 0) {
        IMAGETYPE_GIF  => @imagecreatefromgif($file),
        IMAGETYPE_JPEG => @imagecreatefromjpeg($file),
        IMAGETYPE_PNG  => @imagecreatefrompng($file),
        IMAGETYPE_WEBP => @imagecreatefromwebp($file),
        default => false
    };
}

// 輔助:九宮格座標計算
function calculate_position(array $src, array $water, int $pos): array {
    $srcW = $src[0]; $srcH = $src[1];
    $wW = $water[0]; $wH = $water[1];
    
    $positions = [
        1 => [0, 0],                                    // 左上
        2 => [($srcW - $wW) / 2, 0],                    // 中上
        3 => [$srcW - $wW, 0],                          // 右上
        4 => [0, ($srcH - $wH) / 2],                    // 左中
        5 => [($srcW - $wW) / 2, ($srcH - $wH) / 2],    // 正中
        6 => [$srcW - $wW, ($srcH - $wH) / 2],          // 右中
        7 => [0, $srcH - $wH],                          // 左下
        8 => [($srcW - $wW) / 2, $srcH - $wH],          // 中下
        9 => [$srcW - $wW, $srcH - $wH],                // 右下
    ];
    return $positions[$pos] ?? [0, 0];
}
?>

使用範例

<?php
// 基本使用 (右下角、30% 透明度)
$newFile = img_water_mark('photo.jpg', 'logo.png');
if (is_int($newFile)) {
    echo "錯誤碼: $newFile";
} else {
    echo "成功: $newFile";
}

// 進階:中上位置、完全不透明、自訂輸出
$newFile = img_water_mark(
    'banner.png', 
    'watermark.png', 
    '/var/www/uploads/watermarked', 
    'wm_' . date('YmdHis') . '.png',
    2,   // 中上
    100  // 不透明
);
?>

關鍵技術細節深度解析

技術點說明最佳實踐
Alpha 混合順序先 `imagealphablending($dst, true)` 再 `imagesavealpha($dst, true)`目標圖開啟混合並保存 Alpha,源圖 (浮水印) 同理
imagecopy vs imagecopymerge`copy` 完整複製含 Alpha;`copymerge` 指定透明度但會丟失源圖 Alpha 細節浮水印為 PNG 且需完整透明度用 `copy`;需可調透明度用 `copymerge`
GIF 動畫支援GD 僅處理第一幀,動畫 GIF 加浮水印會變靜態需保持動畫請用 Imagick / FFmpeg 逐幀處理
記憶體管理大圖 (如 4000x3000) 佔用 ~48MB/張處理完立即 `imagedestroy()`;批次處理間 `unset` 變數
JPEG 品質/ PNG 壓縮`imagejpeg($res, $file, 90)`、`imagepng($res, $file, 6)`JPEG 85-90 平衡品質/大小;PNG 6-9 壓縮等級

錯誤碼對照表

代碼含義排查方向
-1源圖不存在/非圖片檢查路徑、檔案權限、MIME 型別
-2浮水印不存在/非圖片同 -1
-3源圖 GD 資源建立失敗GD 未支援該格式、檔案損壞、記憶體不足
-4浮水印 GD 資源建立失敗同 -3
-5儲存失敗目錄不可寫、磁碟滿、格式不支援儲存

進階擴展:文字浮水印

<?php
function img_text_watermark(
    string $srcImg, string $text, int $position = 5, 
    int $fontSize = 20, string $color = 'ffffff', int $alpha = 50
): string|int {
    $srcInfo = @getimagesize($srcImg);
    if (!$srcInfo) return -1;
    $srcRes = image_create_from_ext($srcImg);
    if (!$srcRes) return -3;

    // 計算文字區域 (需 TTF 字體檔)
    $fontFile = __DIR__ . '/fonts/msjh.ttc'; // 微軟正黑體
    $box = imagettfbbox($fontSize, 0, $fontFile, $text);
    $textW = $box[2] - $box[0];
    $textH = $box[1] - $box[7];

    [$x, $y] = calculate_position($srcInfo, [0=>$textW, 1=>$textH], $position);
    
    // 分配顏色 (含 Alpha)
    $r = hexdec(substr($color, 0, 2));
    $g = hexdec(substr($color, 2, 2));
    $b = hexdec(substr($color, 4, 2));
    $textColor = imagecolorallocatealpha($srcRes, $r, $g, $b, 127 - $alpha * 1.27); // 0-100 -> 0-127

    imagettftext($srcRes, $fontSize, 0, $x, $y + $textH, $textColor, $fontFile, $text);
    
    // 儲存邏輯同 img_water_mark...
    return $saveFile;
}
?>

此實作涵蓋圖片/文字浮水印、多格式支援、透明度精準控制、錯誤碼語意化,可直接整合至 CMS、電商、相簿系統的上傳處理管線。

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