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

PHP GD 庫實現中文文字水印完整程式碼

     編輯:PHP 相關知識

PHP GD 繪製中文文字水印:從基礎到實用封裝

利用 PHP GD 擴充庫的 imagettftext() 函式可繪製 TrueType 字型文字,配合中文字型檔 (如微軟雅黑、思源黑體) 即可實現中文水印。本文提供完整函式封裝、字型處理、透明度控制、平鋪水印與批量處理範例。

一、核心水印函式

<?php
/**
 * 給圖片添加中文文字水印
 * @param string $srcImage      來源圖片路徑
 * @param string $dstImage      輸出圖片路徑 (空字串則直接輸出瀏覽器)
 * @param string $text          水印文字 (UTF-8)
 * @param int    $fontSize      字體大小 (pt)
 * @param int    $angle         旋轉角度 (度,順時針)
 * @param int    $x             X 座標 (左上角為原點)
 * @param int    $y             Y 座標
 * @param string $fontFile      TTF 字型檔絕對路徑
 * @param array  $color         RGB 顏色 [r,g,b] 0-255
 * @param int    $alpha         透明度 0-127 (0不透明, 127全透明)
 * @return bool 成功返回 true
 */
function addTextWatermark(
    string $srcImage,
    string $dstImage,
    string $text,
    int $fontSize = 20,
    int $angle = 0,
    int $x = 10,
    int $y = 30,
    string $fontFile = '',
    array $color = [255, 255, 255],
    int $alpha = 30
): bool {
    // 預設字型搜尋路徑
    if (!$fontFile) {
        $fontPaths = [
            '/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf',           // Linux 常見
            '/System/Library/Fonts/PingFang.ttc',                       // macOS
            'C:/Windows/Fonts/msyh.ttc',                                // Windows 微軟雅黑
            __DIR__ . '/fonts/msyh.ttf',                                // 專案內置
        ];
        foreach ($fontPaths as $path) {
            if (file_exists($path)) { $fontFile = $path; break; }
        }
    }
    if (!$fontFile || !file_exists($fontFile)) {
        trigger_error("找不到可用中文字型檔,請指定 \$fontFile 參數", E_USER_WARNING);
        return false;
    }

    // 載入圖片 (自動偵測類型)
    $srcInfo = @getimagesize($srcImage);
    if (!$srcInfo) return false;
    $mime = $srcInfo['mime'];
    $createFunc = [
        'image/jpeg' => 'imagecreatefromjpeg',
        'image/png'  => 'imagecreatefrompng',
        'image/gif'  => 'imagecreatefromgif',
        'image/webp' => 'imagecreatefromwebp',
    ];
    if (!isset($createFunc[$mime])) return false;
    $im = $createFunc[$mime]($srcImage);
    if (!$im) return false;

    // 開啟 Alpha 混合
    imagealphablending($im, true);
    imagesavealpha($im, true);

    // 分配顏色 (含透明度)
    $textColor = imagecolorallocatealpha($im, $color[0], $color[1], $color[2], $alpha);

    // 繪製文字
    // imagettftext($image, $size, $angle, $x, $y, $color, $fontfile, $text)
    // 注意:$y 為基線位置,非文字頂部
    $bbox = imagettfbbox($fontSize, $angle, $fontFile, $text);
    $textWidth = $bbox[2] - $bbox[0];
    $textHeight = $bbox[1] - $bbox[7];
    
    // 如果座標為負數,表示從右下角偏移
    if ($x < 0) $x = imagesx($im) + $x - $textWidth - 10;
    if ($y < 0) $y = imagesy($im) + $y + $textHeight + 10;

    imagettftext($im, $fontSize, $angle, $x, $y, $textColor, $fontFile, $text);

    // 輸出
    $outputFunc = [
        'image/jpeg' => function($im, $path) { return imagejpeg($im, $path, 90); },
        'image/png'  => function($im, $path) { return imagepng($im, $path, 8); },
        'image/gif'  => function($im, $path) { return imagegif($im, $path); },
        'image/webp' => function($im, $path) { return imagewebp($im, $path, 85); },
    ];
    
    $success = false;
    if ($dstImage === '') {
        // 直接輸出瀏覽器
        header('Content-Type: ' . $mime);
        $success = $outputFunc[$mime]($im, null);
    } else {
        $success = $outputFunc[$mime]($im, $dstImage);
    }

    imagedestroy($im);
    return $success;
}
?>

二、使用範例

1. 基本單一水印

<?php
// 參數
$src = 'photo.jpg';
$dst = 'photo_watermarked.jpg';
$text = '© 2024 MySite.com - 版權所有';

// 執行 (右下角,白色半透明)
addTextWatermark($src, $dst, $text, 24, 0, -10, -10, '', [255,255,255], 40);

echo "水印添加完成: $dst";
?>

2. 批量處理目錄圖片

<?php
function batchWatermark(string $dir, string $text, array $options = []) {
    $opts = array_merge([
        'extensions' => ['jpg','jpeg','png','webp'],
        'outputDir'  => '', // 空則覆蓋原檔,建議指定輸出目錄
        'fontSize'   => 20,
        'color'      => [255,255,255],
        'alpha'      => 40,
        'position'   => 'bottom-right', // top-left, top-right, bottom-left, bottom-right, center, tile
    ], $options);

    $outDir = $opts['outputDir'] ?: $dir;
    if ($outDir !== $dir && !is_dir($outDir)) mkdir($outDir, 0755, true);

    $files = new RecursiveIteratorIterator(
        new RecursiveDirectoryIterator($dir, RecursiveDirectoryIterator::SKIP_DOTS)
    );
    foreach ($files as $file) {
        if (!$file->isFile()) continue;
        $ext = strtolower($file->getExtension());
        if (!in_array($ext, $opts['extensions'])) continue;

        $src = $file->getPathname();
        $dst = $outDir . DIRECTORY_SEPARATOR . $file->getBasename();
        
        // 計算座標
        list($x, $y) = calculatePosition($src, $opts['position'], $opts['fontSize'], strlen($text)*0.6);
        
        addTextWatermark($src, $dst, $text, $opts['fontSize'], 0, $x, $y, '', $opts['color'], $opts['alpha']);
        echo "Processed: $dst\n";
    }
}

function calculatePosition(string $image, string $pos, int $fontSize, int $textWidth): array {
    $size = getimagesize($image);
    $w = $size[0]; $h = $size[1];
    $margin = 15;
    switch ($pos) {
        case 'top-left':      return [$margin, $fontSize + $margin];
        case 'top-right':     return [$w - $textWidth - $margin, $fontSize + $margin];
        case 'bottom-left':   return [$margin, $h - $margin];
        case 'bottom-right':  return [$w - $textWidth - $margin, $h - $margin];
        case 'center':        return [($w - $textWidth)/2, $h/2 + $fontSize/2];
        case 'tile':          return ['tile' => true]; // 特殊標記
        default:              return [$margin, $fontSize + $margin];
    }
}
?>

三、進階:平鋪水印

<?php
function addTiledWatermark(string $src, string $dst, string $text, array $options = []) {
    $opts = array_merge([
        'fontSize' => 16,
        'color'    => [200,200,200],
        'alpha'    => 60,
        'angle'    => -30,
        'spacingX' => 200,
        'spacingY' => 100,
    ], $options);

    $im = imagecreatefromjpeg($src); // 簡化:假設 JPEG
    $w = imagesx($im); $h = imagesy($im);
    
    $fontFile = $options['fontFile'] ?? '';
    // ... 字型搜尋邏輯同上 ...
    
    $color = imagecolorallocatealpha($im, $opts['color'][0], $opts['color'][1], $opts['color'][2], $opts['alpha']);
    
    for ($y = -$h; $y < $h * 2; $y += $opts['spacingY']) {
        for ($x = -$w; $x < $w * 2; $x += $opts['spacingX']) {
            imagettftext($im, $opts['fontSize'], $opts['angle'], $x, $y, $color, $fontFile, $text);
        }
    }
    
    imagejpeg($im, $dst, 90);
    imagedestroy($im);
}
?>

四、常見問題與解決

問題解決方案
中文顯示方框/亂碼字型檔不支援中文。必須使用包含中文字形的 TTF/OTF (如 msyh.ttc, simhei.ttf, SourceHanSansCN-Regular.otf)。
文字位置不正確imagettftext 的 $y 是基線。使用 imagettfbbox() 計算實際高度調整。
透明度無效確保呼叫 imagealphablending($im, true) 和 imagesavealpha($im, true),且使用 imagecolorallocatealpha。
字型檔找不到Linux 伺服器常無中文字型。下載 Noto Sans CJK 或 Source Han Sans 放入專案 /fonts/ 目錄並指定路徑。
記憶體耗盡大圖 (如 4000x3000) 處理需大量記憶體。調整 memory_limit 或分塊處理。

五、現代替代:ImageMagick (Imagick 擴充)

<?php
// Imagick 版水印 (功能更強、效能更好、支援更多格式)
$im = new Imagick('photo.jpg');
$draw = new ImagickDraw();
$draw->setFont('msyh.ttc');
$draw->setFontSize(24);
$draw->setFillColor('rgba(255,255,255,0.3)');
$draw->setTextAlignment(Imagick::ALIGN_RIGHT);
$draw->annotation($im->getImageWidth() - 10, $im->getImageHeight() - 10, '© MySite.com');
$im->drawImage($draw);
$im->writeImage('photo_wm.jpg');
$im->destroy();
?>
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved