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

PHP 圖片水印實例函式大全:文字、圖片、上傳整合、多格式支援

     編輯:PHP 相關知識

核心 GD 函式速查

函式用途
imagecreatefromjpeg/gif/png/webp/bmp載入不同格式圖片
getimagesize()取得寬高、MIME
imagecopymerge()疊加並混合透明度 (0-100)
imagecopy()直接複製像素(配合 Alpha 通道)
imagejpeg/gif/png/webp/bmp()輸出/儲存

通用水印函式 img_water_mark()

<?php
/**
 * 圖片加水印(支援 PNG/JPG/GIF)
 *
 * @param string $srcImg  來源圖片路徑
 * @param string $waterImg 水印圖片路徑
 * @param string|null $savePath 存放資料夾(null=同目錄)
 * @param string|null $saveName 存檔名稱(null=同檔名)
 * @param int $position 1=左上 2=右上 3=置中 4=左下 5=右下
 * @param int $alpha 透明度 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) {
    $srcInfo = @getimagesize($srcImg);
    if (!$srcInfo) return -1; // 來源不存在

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

    $srcIm = loadImage($srcImg, $srcInfo[2]);
    if (!$srcIm) return -3;
    $waterIm = loadImage($waterImg, $waterInfo[2]);
    if (!$waterIm) return -4;

    // 計算座標
    $positions = [
        1 => [0, 0],
        2 => [$srcInfo[0]-$waterInfo[0], 0],
        3 => [($srcInfo[0]-$waterInfo[0])/2, ($srcInfo[1]-$waterInfo[1])/2],
        4 => [0, $srcInfo[1]-$waterInfo[1]],
        5 => [$srcInfo[0]-$waterInfo[0], $srcInfo[1]-$waterInfo[1]],
    ];
    [$x, $y] = $positions[$position] ?? $positions[5];

    imagecopymerge($srcIm, $waterIm, $x, $y, 0, 0, $waterInfo[0], $waterInfo[1], $alpha);

    // 輸出路徑
    $savePath = $savePath ?? dirname($srcImg);
    $saveName = $saveName ?? basename($srcImg);
    $saveFile = rtrim($savePath, '/') . '/' . $saveName;

    $outFunc = ['imagegif','imagejpeg','imagepng'][$srcInfo[2] - 1] ?? null;
    if (!$outFunc || !$outFunc($srcIm, $saveFile)) return -5;

    imagedestroy($srcIm);
    imagedestroy($waterIm);
    return $saveFile;
}

function loadImage(string $file, int $type) {
    $map = [1=>'imagecreatefromgif', 2=>'imagecreatefromjpeg', 3=>'imagecreatefrompng'];
    return ($map[$type] ?? false) ? $map[$type]($file) : false;
}

// 使用範例
$result = img_water_mark('1.jpg', 'walter.gif', null, '2.jpg', 5, 80);
if (is_string($result)) echo "<img src='$result'>";

完整上傳+水印整合範例

<?php
// 設定
$maxSize = 2_000_000;
$upDir = 'uploadimg/';
$watermark = 1; // 1=開啟
$waterType = 2; // 1=文字 2=圖片
$waterPos = 1;  // 1=左下 2=右下 3=左上 4=右上 5=置中
$waterStr = 'https://example.com';
$waterImg = 'xplore.gif';

if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_FILES['upfile'])) {
    $file = $_FILES['upfile'];
    $allowed = ['image/jpeg','image/pjpeg','image/png','image/gif','image/bmp','image/x-png'];
    if (!in_array($file['type'], $allowed)) die('類型不允許');
    if ($file['size'] > $maxSize) die('檔案過大');

    if (!is_dir($upDir)) mkdir($upDir, 0755, true);
    $ext = pathinfo($file['name'], PATHINFO_EXTENSION);
    $dest = $upDir . time() . ".$ext";

    if (!move_uploaded_file($file['tmp_name'], $dest)) die('移動失敗');

    if ($watermark) {
        $info = getimagesize($dest);
        $im = loadImage($dest, $info[2]);
        $canvas = imagecreatetruecolor($info[0], $info[1]);
        $white = imagecolorallocate($canvas, 255, 255, 255);
        imagefill($canvas, 0, 0, $white);
        imagecopy($canvas, $im, 0, 0, 0, 0, $info[0], $info[1]);

        if ($waterType === 1) {
            $black = imagecolorallocate($canvas, 0, 0, 0);
            imagestring($canvas, 2, 3, $info[1]-15, $waterStr, $black);
        } elseif ($waterType === 2) {
            $wm = imagecreatefromgif($waterImg);
            $wx = $info[0] - imagesx($wm);
            $wy = $info[1] - imagesy($wm);
            imagecopy($canvas, $wm, $wx, $wy, 0, 0, imagesx($wm), imagesy($wm));
            imagedestroy($wm);
        }

        $outFunc = ['imagegif','imagejpeg','imagepng'][$info[2]-1];
        $outFunc($canvas, $dest);
        imagedestroy($canvas);
        imagedestroy($im);
    }

    echo "<p>上傳成功:<img src='$dest'></p>";
}
?>
<form method="post" enctype="multipart/form-data">
    <input type="file" name="upfile" required>
    <button type="submit">上傳加水印</button>
</form>

PNG 透明水印進階版(保留 Alpha)

function pngWatermark(string $src, string $dst, string $wm, int $pos = 2): bool {
    $srcIm = imagecreatefromjpeg($src); // 假設背景為 JPG
    $wmIm = imagecreatefrompng($wm);    // 水印為透明 PNG

    imagealphablending($srcIm, true);
    imagesavealpha($srcIm, true);

    $sw = imagesx($srcIm); $sh = imagesy($srcIm);
    $ww = imagesx($wmIm); $wh = imagesy($wmIm);

    $positions = [
        0 => [0, 0],
        1 => [$sw-$ww, 0],
        2 => [$sw-$ww, $sh-$wh],
        3 => [0, $sh-$wh],
    ];
    [$x, $y] = $positions[$pos] ?? $positions[2];

    imagecopy($srcIm, $wmIm, $x, $y, 0, 0, $ww, $wh);
    imagejpeg($srcIm, $dst, 90);
    imagedestroy($srcIm); imagedestroy($wmIm);
    return true;
}

常見問題與解決

問題原因解決
水印位置偏移座標計算錯誤確認 $x, $y 為目標畫布左上角座標,水印右下角不超過邊界
透明水印變黑底未開啟 Alpha 混色在目標畫布呼叫 imagealphablending($im, true); imagesavealpha($im, true);
文字水印中文亂碼字體不支援/編碼錯誤使用支援中文的 TTF,原始碼存 UTF-8,直接傳入 UTF-8 字串
大圖記憶體不足GD 需解壓整張圖到記憶體調大 memory_limit、分批處理、或改用 Imagick 串流處理

現代化建議

新專案請使用 Intervention/Image:

composer require intervention/image

// 文字水印
Image::make('photo.jpg')
    ->text('版權所有', 10, 10, function($font) {
        $font->file('fonts/NotoSansTC-Regular.otf');
        $font->size(24);
        $font->color('#ff0000');
        $font->align('center');
        $font->valign('bottom');
    })
    ->save('watermarked.jpg');

// 圖片水印
Image::make('photo.jpg')
    ->insert('logo.png', 'bottom-right', 10, 10)
    ->save('watermarked.jpg');
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved