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

PHP GD 庫生成自適應縮略圖:按比例與固定尺寸雙模式實現

     編輯:PHP 綜合知識

需求場景

電商商品圖、用戶頭像、文章配圖等場景常需生成多種尺寸縮略圖。既要支援「按原圖百分比縮放」,也要支援「指定最大寬高、等比縮放不變形」,且優先級明確。

核心函數設計

<?php
/**
 * 生成縮略圖
 *
 * @param string $srcPath   原圖路徑
 * @param string $dstPath   目標儲存路徑
 * @param int    $percent   百分比模式:1-100,優先級最高
 * @param int    $maxWidth  最大寬度(像素)
 * @param int    $maxHeight 最大高度(像素)
 * @param int    $quality   JPEG 輸出品質 0-100
 * @return bool 成功返回 true,失敗拋出異常
 */
function makeThumbnail(
    string $srcPath,
    string $dstPath,
    int $percent = 0,
    int $maxWidth = 0,
    int $maxHeight = 0,
    int $quality = 85
): bool {
    // 1. 讀取原圖資訊
    if (!is_file($srcPath) || !is_readable($srcPath)) {
        throw new InvalidArgumentException("原圖不存在或不可讀: {$srcPath}");
    }
    $info = getimagesize($srcPath);
    if ($info === false) {
        throw new RuntimeException("無法識別圖片格式: {$srcPath}");
    }
    [$srcW, $srcH, $type] = $info;

    // 2. 根據類型建立 GD 資源
    $createFrom = match ($type) {
        IMAGETYPE_GIF  => 'imagecreatefromgif',
        IMAGETYPE_JPEG => 'imagecreatefromjpeg',
        IMAGETYPE_PNG  => 'imagecreatefrompng',
        IMAGETYPE_WEBP => 'imagecreatefromwebp',
        default        => throw new RuntimeException("不支援的圖片類型: {$type}"),
    };
    $srcImg = $createFrom($srcPath);
    if (!$srcImg) {
        throw new RuntimeException("GD 建立圖片資源失敗: {$srcPath}");
    }

    // 3. 計算目標尺寸
    if ($percent > 0 && $percent <= 100) {
        // 百分比模式優先
        $dstW = max(1, (int)round($srcW * $percent / 100));
        $dstH = max(1, (int)round($srcH * $percent / 100));
    } elseif ($maxWidth > 0 || $maxHeight > 0) {
        // 等比縮放至限制框內
        $ratioW = $maxWidth > 0 ? $maxWidth / $srcW : INF;
        $ratioH = $maxHeight > 0 ? $maxHeight / $srcH : INF;
        $ratio = min($ratioW, $ratioH, 1); // 不放大,僅縮小
        $dstW = max(1, (int)round($srcW * $ratio));
        $dstH = max(1, (int)round($srcH * $ratio));
    } else {
        throw new InvalidArgumentException('必須指定 percent 或 maxWidth/maxHeight 至少一項');
    }

    // 4. 建立真彩色畫布並重採樣
    $dstImg = imagecreatetruecolor($dstW, $dstH);
    
    // 保持 PNG/GIF/WEBP 透明度
    if (in_array($type, [IMAGETYPE_PNG, IMAGETYPE_GIF, IMAGETYPE_WEBP], true)) {
        imagealphablending($dstImg, false);
        imagesavealpha($dstImg, true);
        $transparent = imagecolorallocatealpha($dstImg, 255, 255, 255, 127);
        imagefill($dstImg, 0, 0, $transparent);
    }

    // 使用 imagecopyresampled 而非 imagecopyresized,品質更高
    imagecopyresampled($dstImg, $srcImg, 0, 0, 0, 0, $dstW, $dstH, $srcW, $srcH);

    // 5. 輸出儲存
    $saveFunc = match ($type) {
        IMAGETYPE_GIF  => fn() => imagegif($dstImg, $dstPath),
        IMAGETYPE_JPEG => fn() => imagejpeg($dstImg, $dstPath, $quality),
        IMAGETYPE_PNG  => fn() => imagepng($dstImg, $dstPath, 9), // PNG 壓縮級別 0-9
        IMAGETYPE_WEBP => fn() => imagewebp($dstImg, $dstPath, $quality),
        default        => throw new RuntimeException("不支援的輸出類型"),
    };
    $result = $saveFunc();

    // 6. 釋放資源
    imagedestroy($srcImg);
    imagedestroy($dstImg);

    return $result;
}
?>

使用範例

<?php
require_once 'thumbnail.php';

try {
    // 1. 生成原圖 15% 縮略圖
    makeThumbnail('uploads/photo.jpg', 'thumbs/photo_15pct.jpg', 15);
    
    // 2. 生成寬不超過 200px、高不超過 120px 的等比縮略圖
    makeThumbnail('uploads/photo.jpg', 'thumbs/photo_200x120.jpg', 0, 200, 120);
    
    // 3. 同時指定百分比與尺寸,百分比優先
    makeThumbnail('uploads/photo.jpg', 'thumbs/photo_mixed.jpg', 15, 200, 120);
    
    // 4. PNG 保持透明背景
    makeThumbnail('uploads/logo.png', 'thumbs/logo_thumb.png', 0, 100, 100);
    
    echo "所有縮略圖生成成功!\n";
} catch (Throwable $e) {
    error_log("縮略圖生成失敗: " . $e->getMessage());
    echo "錯誤: " . $e->getMessage() . "\n";
}
?>

進階優化建議

  • ImageMagick 替代 GD:大圖、高併發、複雜格式(HEIC、AVIF、TIFF)建議用 imagick 擴展,效能與品質更優。
  • 快取機制:以「原圖路徑+參數哈希」為 Key 快取縮略圖,避免重複生成。
  • 異步處理:上傳時放入隊列,由 Worker 異步生成各尺寸,提升響應速度。
  • WebP/AVIF 輸出:現代瀏覽器支援 WebP,體積比 JPEG 小 25-35%,可雙輸出並用 <picture> 標籤回退。
  • 記憶體限制:處理超大圖(>5000px)時需調大 memory_limit,或分塊處理。

常見坑點提醒

  1. php.ini 必須啟用 extension=gd 並編譯支援 JPEG/PNG/FreeType。
  2. imagecopyresized 為最近鄰插值,鋸齒嚴重,務必用 imagecopyresampled(雙線性插值)。
  3. PNG 輸出第三參數為壓縮級別(0-9),非品質;JPEG/WebP 才是品質(0-100)。
  4. 輸出目錄需可寫權限,且路徑建議用絕對路徑避免當前工作目錄混淆。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved