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

PHP imagecopy 與 imagecopymerge 圖片水印實作全解析

     編輯:PHP 相關知識

GD 水印兩大核心函式

函式用途透明度支援
imagecopy()直接複製像素區塊不支援(PNG 需手動處理 Alpha)
imagecopymerge()複製並依 pct 參數混合支援 0-100 透明度

現代 PHP 版本中 imagecopy() 已能正確處理 PNG Alpha 通道(需配合 imagealphablending()、imagesavealpha()),imagecopymerge() 較適用於簡單不透明水印疊加。

啟用 GD 庫(Windows)

; php.ini
extension=php_gd2.dll
; 移除前面分號並重啟 Apache/IIS

基礎範例:右下角加入半透明 Logo

<?php
header('Content-Type: image/jpeg');

$dstFile = 'images/flower_1.jpg';
$srcFile = 'images/logo.gif'; // 水印圖
$alpha = 30; // 透明度 0-100

$dst = imagecreatefromjpeg($dstFile);
$src = imagecreatefromgif($srcFile);

$dstInfo = getimagesize($dstFile);
$srcInfo = getimagesize($srcFile);

// 右下角座標
$x = $dstInfo[0] - $srcInfo[0];
$y = $dstInfo[1] - $srcInfo[1];

imagecopymerge($dst, $src, $x, $y, 0, 0, $srcInfo[0], $srcInfo[1], $alpha);

imagejpeg($dst);
imagedestroy($dst);
imagedestroy($src);
?>

進階封裝:可複用水印類 ImageTool

<?php
class ImageTool {
    /** 取得圖片資訊 */
    public static function imageInfo(string $path): ?array {
        if (!file_exists($path)) return null;
        $info = getimagesize($path);
        if (!$info) return null;
        return [
            'width' => $info[0],
            'height' => $info[1],
            'ext' => substr($info['mime'], strpos($info['mime'], '/') + 1), // jpeg, png, gif
        ];
    }

    /**
     * 加水印
     * @param string $dst 目標圖片
     * @param string $water 水印圖片
     * @param string|null $save 輸出路徑(null 覆寫原檔)
     * @param int $pos 位置 0=左上 1=右上 2=右下(預設) 3=左下
     * @param int $alpha 透明度 0-100
     */
    public static function water(string $dst, string $water, ?string $save = null, int $pos = 2, int $alpha = 50): bool {
        $dInfo = self::imageInfo($dst);
        $wInfo = self::imageInfo($water);
        if (!$dInfo || !$wInfo) return false;
        if ($wInfo['width'] > $dInfo['width'] || $wInfo['height'] > $dInfo['height']) return false;

        $dFunc = 'imagecreatefrom' . $dInfo['ext'];
        $wFunc = 'imagecreatefrom' . $wInfo['ext'];
        if (!function_exists($dFunc) || !function_exists($wFunc)) return false;

        $dIm = $dFunc($dst);
        $wIm = $wFunc($water);

        // 計算座標
        switch ($pos) {
            case 0: $px = 0; $py = 0; break; // 左上
            case 1: $px = $dInfo['width'] - $wInfo['width']; $py = 0; break; // 右上
            case 3: $px = 0; $py = $dInfo['height'] - $wInfo['height']; break; // 左下
            default: $px = $dInfo['width'] - $wInfo['width']; $py = $dInfo['height'] - $wInfo['height']; // 右下
        }

        imagecopymerge($dIm, $wIm, $px, $py, 0, 0, $wInfo['width'], $wInfo['height'], $alpha);

        $save = $save ?? $dst;
        if ($save === $dst) @unlink($dst);
        $outFunc = 'image' . $dInfo['ext'];
        $outFunc($dIm, $save);

        imagedestroy($dIm);
        imagedestroy($wIm);
        return true;
    }

    /**
     * 等比縮圖並白底置中
     */
    public static function thumb(string $dst, ?string $save = null, int $width = 200, int $height = 200): bool {
        $dInfo = self::imageInfo($dst);
        if (!$dInfo) return false;

        $scale = min($width / $dInfo['width'], $height / $dInfo['height']);
        $dFunc = 'imagecreatefrom' . $dInfo['ext'];
        $dIm = $dFunc($dst);

        $tIm = imagecreatetruecolor($width, $height);
        $white = imagecolorallocate($tIm, 255, 255, 255);
        imagefill($tIm, 0, 0, $white);

        $newW = (int)($dInfo['width'] * $scale);
        $newH = (int)($dInfo['height'] * $scale);
        $padX = (int)(($width - $newW) / 2);
        $padY = (int)(($height - $newH) / 2);

        imagecopyresampled($tIm, $dIm, $padX, $padY, 0, 0, $newW, $newH, $dInfo['width'], $dInfo['height']);

        $save = $save ?? $dst;
        if ($save === $dst) @unlink($dst);
        $outFunc = 'image' . $dInfo['ext'];
        $outFunc($tIm, $save);

        imagedestroy($dIm);
        imagedestroy($tIm);
        return true;
    }
}

// 使用範例
ImageTool::water('photo.jpg', 'logo.png', 'photo_wm.jpg', 2, 40);
ImageTool::thumb('photo_wm.jpg', 'photo_thumb.jpg', 300, 200);
?>

PNG 透明水印最佳實踐

若水印為帶 Alpha 通道的 PNG,建議改用 imagecopy() 並開啟混色模式:

$dst = imagecreatefromjpeg('photo.jpg');
$wm = imagecreatefrompng('watermark.png');

imagealphablending($dst, true); // 開啟混色
imagesavealpha($dst, true);     // 保留 Alpha

$x = imagesx($dst) - imagesx($wm);
$y = imagesy($dst) - imagesy($wm);
imagecopy($dst, $wm, $x, $y, 0, 0, imagesx($wm), imagesy($wm));

imagejpeg($dst, 'out.jpg', 90);

效能與安全提醒

  • 大圖處理:調大 memory_limit,處理完立即 imagedestroy()。
  • 輸入驗證:嚴格檢查檔案路徑,防止目錄遍歷攻擊。
  • 並發考量:高流量下建議將圖片處理移至背景隊列(如 RabbitMQ + Worker)。
  • 現代替代:Intervention\Image 提供鏈式語法:Image::make($img)->insert($wm, 'bottom-right', 10, 10)->save($out)。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved