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

ThinkPHP 圖片浮水印功能強化:支援 PNG 透明度與 JPEG 品質調整

     編輯:PHP 綜合知識

背景

ThinkPHP 內建 Image 類別提供 water() 方法,但預設使用 imagecopymerge() 導致 PNG 透明度遺失、JPEG 品質無法調整。本文提供修正版實作。

修正版 water() 方法

<?php
namespace think;

class Image {
    /**
     * 為圖片加浮水印(修正版)
     *
     * @param string $source   原圖路徑
     * @param string $water    水印圖路徑
     * @param string|null $savename 輸出路徑,null 覆蓋原圖
     * @param int    $alpha    水印透明度 0-100(僅對 imagecopymerge 有效,本修正版改用 imagecopy 保持 PNG 透明)
     * @param int    $quality  JPEG 輸出品質 0-100(預設 90)
     * @return bool|string 成功回傳儲存路徑,失敗 false
     */
    public static function water(string $source, string $water, string $savename = null, int $alpha = 80, int $quality = 90) {
        // 1. 檢查檔案存在
        if (!file_exists($source) || !file_exists($water)) return false;

        // 2. 取得圖片資訊
        $sInfo = self::getImageInfo($source);
        $wInfo = self::getImageInfo($water);

        // 3. 原圖小於水印則不處理
        if ($sInfo['width'] < $wInfo['width'] || $sInfo['height'] < $wInfo['height']) return false;

        // 4. 建立 GD 資源
        $sCreate = 'imagecreatefrom' . $sInfo['type'];
        $wCreate = 'imagecreatefrom' . $wInfo['type'];
        $sImg = $sCreate($source);
        $wImg = $wCreate($water);

        // 5. 關鍵:開啟 Alpha Blending,保持 PNG 透明通道
        imagealphablending($wImg, true);
        imagesavealpha($wImg, true); // 確保儲存時保留 Alpha

        // 6. 位置:預設右下角
        $posX = $sInfo['width'] - $wInfo['width'];
        $posY = $sInfo['height'] - $wInfo['height'];

        // 7. 使用 imagecopy 而非 imagecopymerge,完整保留水印 Alpha 通道
        imagecopy($sImg, $wImg, $posX, $posY, 0, 0, $wInfo['width'], $wInfo['height']);

        // 8. 輸出
        $outFunc = 'image' . $sInfo['type'];
        if (!$savename) {
            $savename = $source;
            @unlink($source);
        }

        $result = false;
        if (in_array($sInfo['type'], ['jpg', 'jpeg'])) {
            // JPEG 可調品質
            $result = imagejpeg($sImg, $savename, $quality);
        } elseif ($sInfo['type'] === 'png') {
            // PNG 無品質參數,但保留透明度
            $result = imagepng($sImg, $savename);
        } elseif ($sInfo['type'] === 'gif') {
            $result = imagegif($sImg, $savename);
        } else {
            $result = $outFunc($sImg, $savename);
        }

        imagedestroy($sImg);
        imagedestroy($wImg);

        return $result ? $savename : false;
    }
    // ... 原有 getImageInfo 等方法保持不變
}
?>

關鍵修正點解析

原版問題修正做法效果
imagecopymerge() 不支援 Alpha 通道,PNG 水印變不透明改用 imagecopy() + imagesavealpha()PNG 水印完美保持透明/半透明效果
JPEG 輸出無品質參數,預設 75 品質較差新增 $quality 參數傳給 imagejpeg()可控制檔案大小與畫質平衡,預設 90
不支援 WebP、BMP 等新格式擴展 getImageInfo() 回傳型別對應相容更多格式

控制器使用範例

<?php
namespace app\controller;

use think\Image;

class Upload {
    public function watermark() {
        $file = request()->file('image');
        if (!$file) return json(['code' => 0, 'msg' => '無檔案']);

        $info = $file->move('uploads/');
        if (!$info) return json(['code' => 0, 'msg' => $file->getError()]);

        $source = $info->getRealPath();
        $water  = 'static/images/watermark.png'; // 透明 PNG 水印
        $save   = 'uploads/watermarked/' . $info->getFilename();

        $result = Image::water($source, $water, $save, 80, 90);
        if ($result) {
            return json(['code' => 1, 'url' => '/' . $result]);
        }
        return json(['code' => 0, 'msg' => '浮水印失敗']);
    }
}
?>

進階:支援多位置、文字水印

<?php
// 擴展位置參數
const POSITIONS = [
    'TL' => [0, 0],
    'TC' => ['center', 0],
    'TR' => ['right', 0],
    'ML' => [0, 'center'],
    'MC' => ['center', 'center'],
    'MR' => ['right', 'center'],
    'BL' => [0, 'bottom'],
    'BC' => ['center', 'bottom'],
    'BR' => ['right', 'bottom'], // 預設
];

// 文字水印(需 FreeType 支援)
public static function textWater(string $source, string $text, string $font, int $size, string $color, string $pos = 'BR', string $savename = null) {
    // 實作略...
}
?>

常見問題排查

  • 水印位置偏移:確認 getImageInfo() 正確回傳寬高,GD 版本差異可能導致座標計算不同。
  • PNG 背景變黑:未呼叫 imagesavealpha($dst, true) 且 imagealphablending($dst, false)。
  • 記憶體耗盡:大圖處理前 ini_set('memory_limit', '256M'),或改用 Imagick 擴展。
  • 權限錯誤:儲存目錄需 Web 使用者寫入權限(chmod 755 + chown www:www)。

將此修正版整合至專案 extend/think/Image.php 覆寫原方法,即可享受完美透明水印與可調 JPEG 品質。

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