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

PHP 圖片縮略圖生成函數:支援裁切、等比縮放與多格式完整實作

     編輯:PHP 相關知識

功能特色

  • 支援 JPG、PNG、GIF、BMP 四種主流格式
  • 智慧檢測圖片類型(不依賴副檔名)
  • 兩種模式:裁切填滿(預設)與 等比縮放(保留完整畫面)
  • 可指定輸出品質、目標路徑(預設覆蓋原檔)
  • 完整錯誤代碼回傳,便於程式邏輯判斷

函數簽名與回傳結構

function thumbImage(
    string $file,           // 來源圖片路徑
    int $thumbWidth,        // 目標寬度
    int $thumbHeight,       // 目標高度
    string $savePath = '',  // 儲存路徑(空則覆蓋原檔)
    bool $isCut = true,     // true=裁切填滿 false=等比縮放
    int $quality = 100      // JPG 輸出品質 0-100
): array

// 回傳陣列結構
[
    'status'   => 0,        // 0成功 1檔案不存在 2格式不支援 3尺寸過小
    'file'     => '1.jpg',
    'width'    => 200,
    'height'   => 200,
    'savePath' => '2.jpg',
    'info'     => '縮略圖片生成成功'
]

完整函數實作

<?php
function thumbImage($file, $thumbWidth, $thumbHeight, $savePath = '', $isCut = true, $quality = 100) {
    $result = ['status' => 0, 'file' => '', 'width' => 0, 'height' => 0, 'savePath' => '', 'info' => ''];

    // 1. 檔案存在性檢查
    if (!file_exists($file)) {
        return ['status' => 1, 'info' => '圖片檔案不存在'];
    }

    // 2. 讀取檔頭判斷真實類型(避免副檔名偽裝)
    $fp = fopen($file, 'rb');
    $bytes = fread($fp, 2);
    fclose($fp);
    $arr = @unpack('c2chars', $bytes);
    $typeCode = intval($arr['chars1'] . $arr['chars2']);

    $fileType = '';
    switch ($typeCode) {
        case 255216: $fileType = 'jpg'; break;   // FF D8
        case 7173:   $fileType = 'gif'; break;   // 47 49
        case 6677:   $fileType = 'bmp'; break;   // 42 4D
        case 13780:  $fileType = 'png'; break;   // 89 50
        default:     $fileType = $typeCode;
    }
    // 處理有符號位元組情況
    if ($arr['chars1'] === -1 && $arr['chars2'] === -40) $fileType = 'jpg';
    if ($arr['chars1'] === -119 && $arr['chars2'] === 80) $fileType = 'png';

    if (!in_array($fileType, ['jpg', 'gif', 'bmp', 'png'])) {
        return ['status' => 2, 'info' => "不支援的圖片格式: {$fileType}"];
    }

    // 3. 建立 GD 圖片資源
    switch ($fileType) {
        case 'jpg':  $im = imagecreatefromjpeg($file); break;
        case 'gif':  $im = imagecreatefromgif($file);  break;
        case 'png':  $im = imagecreatefrompng($file);  break;
        case 'bmp':  // BMP 需自行實作或轉檔
            return ['status' => 2, 'info' => 'BMP 格式暫不支援,請先轉檔'];
    }

    if (empty($savePath)) $savePath = $file;

    $width  = imagesx($im);
    $height = imagesy($im);

    // 4. 來源圖較小時不放大(可透過 $isCut=false 允許放大)
    if ($width < $thumbWidth && $height < $thumbHeight && $isCut) {
        return ['status' => 3, 'info' => '圖片尺寸小於目標縮略圖尺寸'];
    }

    $ratio      = $width / $height;
    $thumbRatio = $thumbWidth / $thumbHeight;

    // 5. PHP 5.1.2+ imagepng 品質參數意義改變(0-9 壓縮等級)
    if (function_exists('imagepng') && (int)str_replace('.', '', PHP_VERSION) >= 512) {
        $quality = 9; // PNG 壓縮等級 9(最小檔案)
    }

    // 6. 核心縮放邏輯
    if ($isCut) {
        // --- 裁切模式:填滿目標區域,超出部分裁切 ---
        if ($ratio >= $thumbRatio) {
            // 來源較寬 -> 以高度為基準縮放,寬度超出部分裁切
            $newImg = imagecreatetruecolor($thumbWidth, $thumbHeight);
            $srcW = $height * $thumbRatio;
            imagecopyresampled($newImg, $im, 0, 0, 0, 0, $thumbWidth, $thumbHeight, $srcW, $height);
        } else {
            // 來源較高 -> 以寬度為基準縮放,高度超出部分裁切
            $newImg = imagecreatetruecolor($thumbWidth, $thumbHeight);
            $srcH = $width / $thumbRatio;
            imagecopyresampled($newImg, $im, 0, 0, 0, 0, $thumbWidth, $thumbHeight, $width, $srcH);
        }
        imagejpeg($newImg, $savePath, $quality);
    } else {
        // --- 等比縮放模式:完整保留畫面,可能留白 ---
        if ($ratio >= $thumbRatio) {
            // 以寬度為基準
            $newH = $thumbWidth / $ratio;
            $newImg = imagecreatetruecolor($thumbWidth, $newH);
            imagecopyresampled($newImg, $im, 0, 0, 0, 0, $thumbWidth, $newH, $width, $height);
        } else {
            // 以高度為基準
            $newW = $thumbHeight * $ratio;
            $newImg = imagecreatetruecolor($newW, $thumbHeight);
            imagecopyresampled($newImg, $im, 0, 0, 0, 0, $newW, $thumbHeight, $width, $height);
        }
        imagejpeg($newImg, $savePath, $quality);
    }

    imagedestroy($im);
    if (isset($newImg)) imagedestroy($newImg);

    return [
        'status'   => 0,
        'file'     => $file,
        'width'    => $thumbWidth,
        'height'   => $thumbHeight,
        'savePath' => $savePath,
        'info'     => '縮略圖片生成成功'
    ];
}
?>

使用範例

<?php
// 1. 裁切模式產生 200x100 縮略圖,另存新檔
$result = thumbImage('uploads/photo.jpg', 200, 100, 'thumbs/photo_thumb.jpg');
print_r($result);

// 2. 等比縮放模式,最大寬高 300x300,覆蓋原檔
$result = thumbImage('uploads/photo.jpg', 300, 300, '', false, 90);

// 3. 批次處理上傳目錄
foreach (glob('uploads/*.jpg') as $file) {
    $out = 'thumbs/' . basename($file);
    thumbImage($file, 150, 150, $out, true, 85);
}
?>

進階優化建議

優化方向說明
支援 WebP/HEIC 使用 imagecreatefromwebp()、imagecreatefromheic()(需 PHP 7.2+ / 8.1+)
記憶體優化 大圖分塊處理或使用 Imagick 串流模式避免 memory_limit 耗盡
銳化處理 縮放後套用 imageconvolution() 銳化核矩陣提升清晰度
非同步佇列 上傳後推入 Redis/RabbitMQ,Worker 後台生成縮圖,API 秒回應
快取策略 以「原檔路徑+尺寸+模式」為 Key 快取,避免重複生成

常見問題排查

  • 輸出黑色/空白:檢查 imagecreatetruecolor() 是否成功,GD 擴展是否啟用
  • PNG 透明背景變黑:需啟用 imagealphablending($newImg, false); imagesavealpha($newImg, true);
  • GIF 動畫只剩第一幀:GD 不支援多幀 GIF 處理,需用 Imagick 或 ffmpeg
  • 權限錯誤:確認目標目錄可寫(chmod 755 或 PHP-FPM 執行身分擁有權限)
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved