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

PHP 圖片處理實戰:從載入、操作到儲存的完整流程

     編輯:PHP 綜合知識

前言:動態圖片處理的核心場景

驗證碼生成、統計圖表繪製、使用者上傳頭像裁切、產品圖加浮水印、縮圖自動生成——這些 Web 開發高頻需求,核心都是**對現有圖片資源進行讀取、操作、輸出**。PHP GD 庫提供了完整的圖片處理函數族群,本文將系統梳理從「載入現有圖片」到「輸出儲存」的標準化流程與最佳實踐。

核心流程三部曲

  1. 載入:根據格式呼叫對應函數建立圖片資源。
  2. 操作:繪圖、縮放、裁切、旋轉、加文字/水印等。
  3. 輸出/儲存:輸出到瀏覽器或寫入檔案,並釋放資源。

載入現有圖片:格式對應函數

格式載入函數輸出函數MIME 類型
JPEGimagecreatefromjpeg()imagejpeg()image/jpeg
PNGimagecreatefrompng()imagepng()image/png
GIFimagecreatefromgif()imagegif()image/gif
WBMPimagecreatefromwbmp()imagewbmp()image/vnd.wap.wbmp
WebPimagecreatefromwebp() (PHP 5.5+)imagewebp()image/webp

所有載入函數成功回傳 圖片資源識別符,失敗回傳 false 並觸發 E_WARNING。

萬用載入器:自動偵測格式並載入

利用 getimagesize() 取得圖片資訊,動態選擇載入函數:

<?php
function loadImage($filename) {
    if (!file_exists($filename)) {
        throw new Exception("檔案不存在:$filename");
    }
    
    $info = getimagesize($filename);
    if ($info === false) {
        throw new Exception("無效圖片檔案:$filename");
    }
    
    // $info[2] 對應 IMAGETYPE_* 常數
    $type = $info[2];
    $mime = $info['mime'];
    
    $loadFunc = [
        IMAGETYPE_GIF  => 'imagecreatefromgif',
        IMAGETYPE_JPEG => 'imagecreatefromjpeg',
        IMAGETYPE_PNG  => 'imagecreatefrompng',
        IMAGETYPE_WEBP => 'imagecreatefromwebp',
        IMAGETYPE_BMP  => 'imagecreatefrombmp', // PHP 7.2+
    ];
    
    if (!isset($loadFunc[$type])) {
        throw new Exception("不支援的圖片格式:$mime");
    }
    
    $func = $loadFunc[$type];
    $resource = $func($filename);
    
    if ($resource === false) {
        throw new Exception("圖片載入失敗:$filename");
    }
    
    return [
        'resource' => $resource,
        'width'    => $info[0],
        'height'   => $info[1],
        'type'     => $type,
        'mime'     => $mime,
    ];
}

// 使用範例
try {
    $img = loadImage('photo.jpg');
    // $img['resource'] 即為圖片資源
    // $img['width'], $img['height'] 可直接使用
} catch (Exception $e) {
    echo "錯誤:" . $e->getMessage();
}
?>

getimagesize() 回傳值完整解析

<?php
$info = getimagesize('image/brophp.jpg');
/*
$info[0] => 寬度 (像素)
$info[1] => 高度 (像素)
$info[2] => 類型常數 (1=GIF, 2=JPG, 3=PNG, 4=SWF, ...)
$info[3] => 字串 "width=xxx height=yyy" 可直接用於 <img> 標籤
$info['bits']     => 色彩位深
$info['channels'] => 通道數 (3=RGB, 4=RGBA)
$info['mime']     => MIME 類型
*/
list($width, $height, $type, $attr) = $info;
echo "<img src='image/brophp.jpg' $attr>";
// 輸出:<img src='image/brophp.jpg' width=800 height=600>
?>

通用儲存函數:保持原格式輸出

實務上常見需求:開啟何種格式,儲存何種格式。以下模式完美解決:

<?php
function saveImage($resource, $filename, $type = null, $quality = 90) {
    // 若未指定類型,從副檔名推斷
    if ($type === null) {
        $ext = strtolower(pathinfo($filename, PATHINFO_EXTENSION));
        $typeMap = [
            'jpg'  => IMAGETYPE_JPEG,
            'jpeg' => IMAGETYPE_JPEG,
            'png'  => IMAGETYPE_PNG,
            'gif'  => IMAGETYPE_GIF,
            'webp' => IMAGETYPE_WEBP,
            'bmp'  => IMAGETYPE_BMP,
        ];
        $type = $typeMap[$ext] ?? IMAGETYPE_JPEG;
    }
    
    $saveFunc = [
        IMAGETYPE_JPEG => function($res, $file) use ($quality) {
            return imagejpeg($res, $file, $quality);
        },
        IMAGETYPE_PNG  => function($res, $file) use ($quality) {
            // PNG 品質 0-9 (壓縮等級),需轉換
            $pngQuality = min(9, max(0, (100 - $quality) / 10));
            return imagepng($res, $file, (int)$pngQuality);
        },
        IMAGETYPE_GIF  => function($res, $file) {
            return imagegif($res, $file);
        },
        IMAGETYPE_WEBP => function($res, $file) use ($quality) {
            return imagewebp($res, $file, $quality);
        },
    ];
    
    if (!isset($saveFunc[$type])) {
        throw new Exception("不支援的儲存格式類型:$type");
    }
    
    return $saveFunc[$type]($resource, $filename);
}

// 實戰範例:開啟任意格式 → 加文字水印 → 存回原格式
function addWatermark($srcFile, $text, $dstFile = null) {
    $img = loadImage($srcFile);
    $res = $img['resource'];
    $w = $img['width'];
    $h = $img['height'];
    
    // 分配紅色
    $color = imagecolorallocate($res, 255, 0, 0);
    // 字體大小 5 (內建)
    $font = 5;
    $tw = imagefontwidth($font) * strlen($text);
    $th = imagefontheight($font);
    // 置中座標
    $x = ($w - $tw) / 2;
    $y = ($h - $th) / 2;
    
    imagestring($res, $font, $x, $y, $text, $color);
    
    // 儲存
    $target = $dstFile ?? $srcFile;
    saveImage($res, $target, $img['type']);
    
    imagedestroy($res);
    return true;
}

// 批次處理
addWatermark("brophp.gif", "GIF");
addWatermark("brophp.jpg", "JPEG");
addWatermark("brophp.png", "PNG");
?>

進階操作:縮放、裁切、旋轉、翻轉

1. 等比例縮放 (生成縮圖)

<?php
function resizeImage($srcFile, $maxWidth, $maxHeight, $dstFile) {
    $img = loadImage($srcFile);
    $srcW = $img['width'];
    $srcH = $img['height'];
    
    // 計算縮放比例
    $ratio = min($maxWidth / $srcW, $maxHeight / $srcH);
    if ($ratio >= 1) { // 無需縮小
        copy($srcFile, $dstFile);
        return;
    }
    
    $dstW = (int)($srcW * $ratio);
    $dstH = (int)($srcH * $ratio);
    
    // 建立真彩色目標畫布
    $dst = imagecreatetruecolor($dstW, $dstH);
    
    // 保持透明度 (PNG/GIF)
    if ($img['type'] == IMAGETYPE_PNG || $img['type'] == IMAGETYPE_GIF) {
        imagealphablending($dst, false);
        imagesavealpha($dst, true);
        $transparent = imagecolorallocatealpha($dst, 255, 255, 255, 127);
        imagefilledrectangle($dst, 0, 0, $dstW, $dstH, $transparent);
    }
    
    // 重採樣縮放 (高品質)
    imagecopyresampled($dst, $img['resource'], 0, 0, 0, 0, $dstW, $dstH, $srcW, $srcH);
    
    saveImage($dst, $dstFile, $img['type']);
    imagedestroy($dst);
    imagedestroy($img['resource']);
}
?>

2. 裁切 (Crop)

<?php
function cropImage($srcFile, $x, $y, $width, $height, $dstFile) {
    $img = loadImage($srcFile);
    $dst = imagecreatetruecolor($width, $height);
    
    // 透明度處理同縮放
    if (in_array($img['type'], [IMAGETYPE_PNG, IMAGETYPE_GIF])) {
        imagealphablending($dst, false);
        imagesavealpha($dst, true);
    }
    
    imagecopy($dst, $img['resource'], 0, 0, $x, $y, $width, $height);
    saveImage($dst, $dstFile, $img['type']);
    imagedestroy($dst);
    imagedestroy($img['resource']);
}
?>

3. 旋轉與翻轉

<?php
function rotateImage($srcFile, $angle, $dstFile) {
    $img = loadImage($srcFile);
    // imagerotate 會自動擴展畫布,背景色需指定
    $bgColor = imagecolorallocatealpha($img['resource'], 255, 255, 255, 127);
    $rotated = imagerotate($img['resource'], $angle, $bgColor);
    // 保持透明
    if (in_array($img['type'], [IMAGETYPE_PNG, IMAGETYPE_GIF])) {
        imagealphablending($rotated, false);
        imagesavealpha($rotated, true);
    }
    saveImage($rotated, $dstFile, $img['type']);
    imagedestroy($rotated);
    imagedestroy($img['resource']);
}

function flipImage($srcFile, $mode, $dstFile) {
    // $mode: 'horizontal' (水平鏡像) 或 'vertical' (垂直翻轉)
    $img = loadImage($srcFile);
    $w = $img['width'];
    $h = $img['height'];
    $dst = imagecreatetruecolor($w, $h);
    
    if ($mode === 'horizontal') {
        // 從右往左複製每一列
        for ($x = 0; $x < $w; $x++) {
            imagecopy($dst, $img['resource'], $x, 0, $w - 1 - $x, 0, 1, $h);
        }
    } else {
        // 從下往上複製每一行
        for ($y = 0; $y < $h; $y++) {
            imagecopy($dst, $img['resource'], 0, $y, 0, $h - 1 - $y, $w, 1);
        }
    }
    
    saveImage($dst, $dstFile, $img['type']);
    imagedestroy($dst);
    imagedestroy($img['resource']);
}
?>

資源管理鐵律

  • 每個 imagecreatefrom* 都必須配對 imagedestroy(),否則記憶體洩漏嚴重。
  • 大量批次處理時,建議分批執行或使用 CLI 模式避免超時。
  • 錯誤處理:使用 @ 抑制警告,搭配 error_get_last() 捕捉。

常見問題排查表

現象可能原因解決方案
輸出圖片空白/破損未送出正確 Header / 輸出前有空白字元確保 header() 在任何輸出前;檢查檔案結尾無 ?> 後空白
PNG/GIF 透明背景變黑未啟用 Alpha blending / savealpha目標畫布設定 imagealphablending(false); imagesavealpha(true);
中文文字顯示方塊字體不支援中文 / 編碼非 UTF-8使用支援中文的 .ttf/.ttc 字體;確保腳本 UTF-8 編碼
JPEG 品質差/檔案過大品質參數設定不當imagejpeg($res, $file, 85) 85-90 為平衡點
記憶體耗盡處理超大圖片 / 未釋放資源增加 memory_limit;及時 imagedestroy();分塊處理

總結

PHP GD 圖片處理的核心在於:**正確載入 → 靈活操作 → 精準輸出 → 必須釋放**。掌握 getimagesize() 動態偵測格式、建立通用載入/儲存封裝函數、妥善處理透明度與記憶體管理,即能構建健壯、可擴充的圖片處理服務。無論是簡單的水印加文字、縮圖生成,還是複雜的圖片合成、濾鏡效果,皆遵循此一核心流程。

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