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

PHP 圖片處理封裝類:水印、壓縮、裁剪一體化實現

     編輯:PHP 綜合知識

設計思路

GD 庫操作圖片固定四步:**打開 → 操作 → 輸出 → 銷毀**。封裝類將前三步通用化,暴露具體操作方法(水印/壓縮/裁剪),最後統一輸出/保存/銷毀。

核心類實現

<?php
class ImageProcessor {
    private $image;      // GD 圖片資源
    private $info;       // getimagesize 信息
    private $type;       // 擴展名(無點):jpg/png/gif/webp

    /**
     * 構造函數:打開圖片
     * @param string $src 圖片路徑
     */
    public function __construct(string $src) {
        if (!file_exists($src)) throw new Exception('圖片不存在: ' . $src);
        
        $this->info = getimagesize($src);
        if (!$this->info) throw new Exception('非法圖片文件: ' . $src);
        
        $this->type = image_type_to_extension($this->info[2], false); // jpg/png/gif/webp
        $func = 'imagecreatefrom' . $this->type;
        if (!function_exists($func)) throw new Exception('不支持的圖片類型: ' . $this->type);
        
        $this->image = $func($src);
        if (!$this->image) throw new Exception('圖片資源創建失敗');
    }

    /**
     * 文字水印
     * @param string $font 字體文件路徑
     * @param string $text 水印文字
     * @param int $size 字體大小
     * @param array $color RGBA 顏色 [r,g,b,a] a:0-127
     * @param array $position [x, y] 左上角坐標
     * @param int $angle 傾斜角度
     */
    public function addTextWatermark(
        string $font, string $text, int $size, array $color, array $position, int $angle = 0
    ): self {
        $col = imagecolorallocatealpha($this->image, $color[0], $color[1], $color[2], $color[3]);
        imagettftext($this->image, $size, $angle, $position[0], $position[1], $col, $font, $text);
        return $this; // 支持鏈式調用
    }

    /**
     * 圖片水印
     * @param string $watermarkPath 水印圖片路徑
     * @param array $position [x, y] 貼合位置
     * @param int $opacity 透明度 0-100
     */
    public function addImageWatermark(string $watermarkPath, array $position, int $opacity = 50): self {
        $info = getimagesize($watermarkPath);
        $func = 'imagecreatefrom' . image_type_to_extension($info[2], false);
        $watermark = $func($watermarkPath);
        
        imagecopymerge($this->image, $watermark, $position[0], $position[1], 0, 0, $info[0], $info[1], $opacity);
        imagedestroy($watermark);
        return $this;
    }

    /**
     * 壓縮縮放
     * @param array $maxSize [maxWidth, maxHeight] 最大尺寸,保持比例
     */
    public function resize(array $maxSize): self {
        $srcW = $this->info[0];
        $srcH = $this->info[1];
        $ratio = min($maxSize[0] / $srcW, $maxSize[1] / $srcH);
        
        if ($ratio >= 1) return $this; // 無需放大
        
        $newW = (int)($srcW * $ratio);
        $newH = (int)($srcH * $ratio);
        
        $thumb = imagecreatetruecolor($newW, $newH);
        // 保持透明通道
        if (in_array($this->type, ['png', 'gif', 'webp'])) {
            imagealphablending($thumb, false);
            imagesavealpha($thumb, true);
        }
        imagecopyresampled($thumb, $this->image, 0, 0, 0, 0, $newW, $newH, $srcW, $srcH);
        imagedestroy($this->image);
        $this->image = $thumb;
        $this->info[0] = $newW;
        $this->info[1] = $newH;
        return $this;
    }

    /**
     * 裁剪
     * @param array $size [width, height] 裁剪尺寸
     * @param array $position [x, y] 起始坐標
     */
    public function crop(array $size, array $position): self {
        $crop = imagecreatetruecolor($size[0], $size[1]);
        if (in_array($this->type, ['png', 'gif', 'webp'])) {
            imagealphablending($crop, false);
            imagesavealpha($crop, true);
        }
        imagecopyresampled($crop, $this->image, 0, 0, $position[0], $position[1], $size[0], $size[1], $size[0], $size[1]);
        imagedestroy($this->image);
        $this->image = $crop;
        $this->info[0] = $size[0];
        $this->info[1] = $size[1];
        return $this;
    }

    /**
     * 直接輸出到瀏覽器
     */
    public function output(): void {
        header('Content-Type: ' . $this->info['mime']);
        $func = 'image' . $this->type;
        $func($this->image);
    }

    /**
     * 保存到文件
     * @param string $path 保存路徑(含文件名)
     * @param int $quality 壓縮質量 0-100(僅 jpg/webp 有效)
     */
    public function save(string $path, int $quality = 90): bool {
        $func = 'image' . $this->type;
        $dir = dirname($path);
        if (!is_dir($dir)) mkdir($dir, 0755, true);
        
        $result = match ($this->type) {
            'jpg', 'jpeg', 'webp' => $func($this->image, $path, $quality),
            'png' => $func($this->image, $path, 9), // PNG 壓縮級別 0-9
            default => $func($this->image, $path),
        };
        return $result;
    }

    /**
     * 解構函數:自動銷毀資源
     */
    public function __destruct() {
        if ($this->image) imagedestroy($this->image);
    }
}

使用示例

<?php
require 'ImageProcessor.php';

try {
    // 1. 文字水印 + 壓縮 + 保存
    $img = new ImageProcessor('source.jpg');
    $img->addTextWatermark(
        'fonts/msyh.ttc',           // 字體
        '© MySite 2024',            // 文字
        24,                         // 大小
        [255, 255, 255, 30],        // 白色半透明
        [20, 20]                    // 位置
    )->resize([800, 600])->save('output/watermarked.jpg');

    // 2. 圖片水印 + 裁剪 + 直接輸出
    $img2 = new ImageProcessor('photo.png');
    $img2->addImageWatermark('logo.png', [10, 10], 40)
        ->crop([400, 300], [50, 50])
        ->output();

    // 3. 批量處理
    foreach (glob('uploads/*.jpg') as $file) {
        $out = 'processed/' . basename($file);
        (new ImageProcessor($file))
            ->resize([1200, 900])
            ->addTextWatermark('fonts/msyh.ttc', 'Demo', 20, [0,0,0,50], [10,10])
            ->save($out, 85);
    }
} catch (Exception $e) {
    echo 'Error: ' . $e->getMessage();
}

擴展建議

  • 支持 WebP:PHP 7.0+ 內置 imagecreatefromwebp/imagewebp,類中已兼容
  • 增加濾鏡:imagefilter($this->image, IMG_FILTER_GRAYSCALE) 等
  • 圖片旋轉:imagerotate()
  • 異步處理:大量圖片推送隊列,Worker 消費
  • 切換 Imagick:性能更強、格式更多,API 相似,可作驅動模式切換

常見坑點

問題原因解決
透明背景變黑未開啟 alphablending/savealpha縮放/裁剪前設置 imagealphablending(false); imagesavealpha(true);
內存耗盡大圖處理超過 memory_limit分塊處理、增加 memory_limit、用 Imagick
字體找不到相對路徑錯誤使用絕對路徑 __DIR__ . '/fonts/msyh.ttc'
輸出前有空白PHP 標籤前有換行/BOM文件純 PHP 無關閉標籤,編碼 UTF-8 無 BOM
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved