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

PHP 圖片縮放函式:支援 PNG 透明背景、GIF 動畫首幀、JPEG 品質控制的通用實作

     編輯:PHP 相關知識

功能特性

  • 支援 **JPEG / PNG / GIF / WebP** (PHP 8.1+)
  • **等比例縮放**或**固定尺寸**(可選)
  • **PNG/GIF 透明背景完美保留**
  • **JPEG 品質參數可調**
  • 可**覆蓋原檔**或**輸出新檔/瀏覽器/回傳資源**
  • 可選 **Linux 指令刪除原檔** 或 PHP unlink

完整函式程式碼

<?php
/**
 * 通用圖片縮放
 *
 * @param string $file           來源圖片路徑
 * @param int    $width          目標寬度 (0=依比例)
 * @param int    $height         目標高度 (0=依比例)
 * @param bool   $proportional   是否等比例縮放
 * @param string $output         'file'=覆蓋原檔 | 'browser'=直接輸出 | 'return'=回傳 GD 資源 | 路徑字串=另存新檔
 * @param bool   $deleteOriginal 縮放成功後是否刪除原檔
 * @param bool   $useLinuxCmd    刪除時是否用 exec('rm') (需權限)
 * @param int    $jpegQuality    JPEG 輸出品質 (1-100)
 * @return bool|resource         成功 true / 資源 / 失敗 false
 */
function smartResizeImage(
    string $file,
    int $width = 0,
    int $height = 0,
    bool $proportional = true,
    string|bool $output = 'file',
    bool $deleteOriginal = false,
    bool $useLinuxCmd = false,
    int $jpegQuality = 85
): bool|resource {
    
    // 1. 參數驗證
    if ($width <= 0 && $height <= 0) return false;
    if (!file_exists($file) || !is_readable($file)) return false;
    
    // 2. 取得原圖資訊
    $info = @getimagesize($file);
    if ($info === false) return false;
    [$srcW, $srcH, $type] = $info;
    
    // 3. 計算目標尺寸
    if ($proportional) {
        if ($width == 0)       $factor = $height / $srcH;
        elseif ($height == 0)  $factor = $width / $srcW;
        else                   $factor = min($width / $srcW, $height / $srcH);
        $dstW = (int)round($srcW * $factor);
        $dstH = (int)round($srcH * $factor);
    } else {
        $dstW = $width  > 0 ? $width  : $srcW;
        $dstH = $height > 0 ? $height : $srcH;
    }
    
    // 4. 建立來源資源
    $src = match ($type) {
        IMAGETYPE_GIF  => @imagecreatefromgif($file),
        IMAGETYPE_JPEG => @imagecreatefromjpeg($file),
        IMAGETYPE_PNG  => @imagecreatefrompng($file),
        IMAGETYPE_WEBP => @imagecreatefromwebp($file), // PHP 8.1+
        default        => null,
    };
    if (!$src) return false;
    
    // 5. 建立真彩色目標畫布
    $dst = imagecreatetruecolor($dstW, $dstH);
    
    // 6. 透明背景處理 (關鍵!)
    if ($type === IMAGETYPE_GIF || $type === IMAGETYPE_PNG) {
        // 關閉混合模式,啟用 Alpha 通道儲存
        imagealphablending($dst, false);
        imagesavealpha($dst, true);
        
        // 建立全透明色並填滿
        $transparent = imagecolorallocatealpha($dst, 0, 0, 0, 127);
        imagefill($dst, 0, 0, $transparent);
        
        // GIF 可能有調色盤透明色,額外處理
        if ($type === IMAGETYPE_GIF) {
            $trnIdx = imagecolortransparent($src);
            if ($trnIdx >= 0) {
                $trnColor = imagecolorsforindex($src, $trnIdx);
                $newTrnIdx = imagecolorallocatealpha(
                    $dst,
                    $trnColor['red'],
                    $trnColor['green'],
                    $trnColor['blue'],
                    127
                );
                imagefill($dst, 0, 0, $newTrnIdx);
                imagecolortransparent($dst, $newTrnIdx);
            }
        }
    }
    
    // 7. 高品質重採樣縮放
    imagecopyresampled($dst, $src, 0, 0, 0, 0, $dstW, $dstH, $srcW, $srcH);
    
    // 8. 輸出處理
    $result = false;
    $outPath = null;
    
    if ($output === 'browser') {
        header('Content-Type: ' . image_type_to_mime_type($type));
        $outPath = null;
    } elseif ($output === 'return') {
        return $dst; // 呼叫端負責 imagedestroy
    } elseif ($output === 'file' || $output === true) {
        $outPath = $file; // 覆蓋原檔
    } else {
        $outPath = $output; // 自訂路徑
    }
    
    if ($outPath !== null) {
        $result = match ($type) {
            IMAGETYPE_GIF  => imagegif($dst, $outPath),
            IMAGETYPE_JPEG => imagejpeg($dst, $outPath, $jpegQuality),
            IMAGETYPE_PNG  => imagepng($dst, $outPath),
            IMAGETYPE_WEBP => imagewebp($dst, $outPath, $jpegQuality), // PHP 8.1+
            default        => false,
        };
    } else {
        // browser 模式
        $result = match ($type) {
            IMAGETYPE_GIF  => imagegif($dst),
            IMAGETYPE_JPEG => imagejpeg($dst, null, $jpegQuality),
            IMAGETYPE_PNG  => imagepng($dst),
            IMAGETYPE_WEBP => imagewebp($dst, null, $jpegQuality),
            default        => false,
        };
    }
    
    // 9. 清理資源
    imagedestroy($src);
    if ($output !== 'return') imagedestroy($dst);
    
    // 10. 刪除原檔
    if ($result && $deleteOriginal && $outPath === $file) {
        if ($useLinuxCmd) {
            @exec('rm ' . escapeshellarg($file));
        } else {
            @unlink($file);
        }
    }
    
    return $result;
}

使用範例

<?php
// 1. 等比縮放寬度 800px,覆蓋原檔,JPEG 品質 90
smartResizeImage('photo.jpg', 800, 0, true, 'file', false, false, 90);

// 2. 固定 300x300 正方形(裁切需另寫),另存新檔
smartResizeImage('logo.png', 300, 300, false, 'thumb_logo.png');

// 3. 直接輸出到瀏覽器(適用圖片代理端點)
smartResizeImage('avatar.gif', 150, 150, true, 'browser');

// 4. 取得 GD 資源進一步處理(加水印、合成等)
$res = smartResizeImage('input.png', 400, 0, true, 'return');
if ($res) {
    // ... 進一步操作 ...
    imagedestroy($res);
}

// 5. 批次處理目錄
foreach (glob('uploads/*.{jpg,png,gif}', GLOB_BRACE) as $f) {
    smartResizeImage($f, 1200, 1200, true, 'file', false, false, 85);
}

透明背景處理關鍵點總表

格式透明機制關鍵函式
PNGAlpha 通道 (0-127)imagealphablending(false), imagesavealpha(true), imagecolorallocatealpha(..., 127)
GIF調色盤單一透明索引imagecolortransparent(), imagecolorsforindex(), 同 PNG Alpha 步驟
WebP支援有損/無損 Alpha同 PNG,imagewebp() 參數 quality 控制

常見坑與解決

  • 縮放後變黑底:漏掉 imagealphablending(false) + imagesavealpha(true)。
  • GIF 動畫只剩第一幀:GD 不支援多幀處理,需用 imagick 擴充或 gifsicle 指令工具。
  • 記憶體不足:大圖片 imagecreatetruecolor 佔用大量記憶體,調大 memory_limit 或分塊處理。
  • JPEG 伽瑪/色彩空間偏移:GD 不支援 ICC Profile,專業印刷請用 ImageMagick。

進階:ImageMagick (imagick) 版本(生產環境推薦)

<?php
function resizeWithImagick(string $src, string $dst, int $w, int $h, bool $prop = true): bool
{
    try {
        $im = new Imagick($src);
        if ($prop) {
            $im->thumbnailImage($w, $h, true); // 等比
        } else {
            $im->resizeImage($w, $h, Imagick::FILTER_LANCZOS, 1);
        }
        // 保留 ICC Profile、EXIF、透明度
        $im->setImageCompressionQuality(85);
        $im->writeImage($dst);
        return true;
    } catch (ImagickException $e) {
        error_log($e->getMessage());
        return false;
    }
}

總結

GD 版 smartResizeImage 功能完整、零依賴、適合中小專案。關鍵在於**正確處理 Alpha 通道**(PNG/WebP)與**調色盤透明索引**(GIF)。大型、高併發、需動畫/色彩管理專案,請直接上 **ImageMagick (imagick擴充)** 或 **libvips (php-vips)**,效能與功能更強。

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