圖片等比縮放是上傳/展示系統的基礎功能。本文提供一個生產級 imgResize() 函數,支援「指定最大寬高、自動計算比例、JPEG/PNG/GIF 格式保留、輸出質量可控、輸出到文件或瀏覽器」,附完整錯誤處理與記憶體優化。
/**
* 等比例縮放圖片
* @param string $srcPath 源圖絕對路徑
* @param int $maxWidth 最大寬度
* @param int $maxHeight 最大高度
* @param string|null $destPath 目標路徑,null 直接輸出瀏覽器
* @param int $quality JPEG質量 0-100
* @return bool|string 成功返回目標路徑或 true(直接輸出),失敗 false
*/
function imgResize($srcPath, $maxWidth, $maxHeight, $destPath = null, $quality = 85) {
// 1. 檢查源文件
if (!file_exists($srcPath) || !is_readable($srcPath)) {
trigger_error("源文件不存在或不可讀: $srcPath", E_USER_WARNING);
return false;
}
// 2. 獲取圖片信息
$info = @getimagesize($srcPath);
if (!$info) {
trigger_error("無法識別圖片格式: $srcPath", E_USER_WARNING);
return false;
}
[$srcWidth, $srcHeight, $type] = $info;
$mime = $info['mime'];
// 3. 計算目標尺寸(等比縮放)
$ratio = min($maxWidth / $srcWidth, $maxHeight / $srcHeight);
if ($ratio >= 1) { // 無需縮放
$dstWidth = $srcWidth;
$dstHeight = $srcHeight;
} else {
$dstWidth = (int)round($srcWidth * $ratio);
$dstHeight = (int)round($srcHeight * $ratio);
}
// 4. 創建源圖資源
$createFunc = "imagecreatefrom" . image_type_to_extension($type, false);
if (!function_exists($createFunc)) {
trigger_error("不支援的圖片類型: $mime", E_USER_WARNING);
return false;
}
$srcImg = $createFunc($srcPath);
if (!$srcImg) return false;
// 5. 創建目標畫布(真彩色)
$dstImg = imagecreatetruecolor($dstWidth, $dstHeight);
// 6. 處理透明度(PNG/GIF)
if ($type === IMAGETYPE_PNG || $type === IMAGETYPE_GIF) {
imagealphablending($dstImg, false);
imagesavealpha($dstImg, true);
$transparent = imagecolorallocatealpha($dstImg, 255, 255, 255, 127);
imagefill($dstImg, 0, 0, $transparent);
}
// 7. 重採樣縮放(高質量)
if (!imagecopyresampled($dstImg, $srcImg, 0, 0, 0, 0, $dstWidth, $dstHeight, $srcWidth, $srcHeight)) {
imagedestroy($srcImg); imagedestroy($dstImg);
return false;
}
// 8. 輸出
$outputFunc = "image" . ($type === IMAGETYPE_JPEG ? 'jpeg' : ($type === IMAGETYPE_PNG ? 'png' : 'gif'));
$result = true;
if ($destPath) {
// 確保目標目錄存在
$dir = dirname($destPath);
if (!is_dir($dir) && !mkdir($dir, 0755, true)) {
$result = false;
} else {
$result = $outputFunc($dstImg, $destPath, $quality);
}
} else {
// 直接輸出瀏覽器
header("Content-Type: $mime");
$result = $outputFunc($dstImg, null, $quality);
}
// 9. 清理資源
imagedestroy($srcImg);
imagedestroy($dstImg);
return $result ? ($destPath ?? true) : false;
}
// 1. 生成縮略圖保存到文件
imgResize('/data/uploads/photo.jpg', 640, 480, '/data/thumbs/photo_thumb.jpg', 80);
// 2. 直接輸出到瀏覽器(用於
)
// thumb.php
$file = $_GET['file'] ?? '';
$allowed = ['/data/uploads/', '/data/thumbs/'];
if ($file && str_starts_with($file, $allowed)) {
imgResize($file, 300, 200); // 直接輸出
} else {
http_response_code(404);
}
// 3. 批量處理上傳圖片
foreach ($_FILES['photos']['tmp_name'] as $i => $tmp) {
if ($tmp) {
$ext = pathinfo($_FILES['photos']['name'][$i], PATHINFO_EXTENSION);
$name = uniqid('img_') . ".$ext";
$dest = "/data/uploads/$name";
move_uploaded_file($tmp, $dest);
imgResize($dest, 1200, 1200, $dest, 85); // 原圖壓縮覆蓋
imgResize($dest, 300, 300, "/data/thumbs/$name", 80); // 生成縮略圖
}
}
| 技術點 | 實現細節 | 作用 |
|---|---|---|
| 等比計算 | min(maxW/srcW, maxH/srcH) | 保證長邊不超限,短邊自適應,不變形 |
| imagecreatetruecolor | 真彩色畫布(24位) | 避免調色板模式導致色彩失真 |
| imagecopyresampled | 雙線性插值重採樣 | 比 imagecopyresized 質量高得多 |
| 透明度保留 | imagealphablending + imagesavealpha | PNG/GIF 透明背景不變黑 |
| 質量參數 | 僅 JPEG 有效 (0-100) | 平衡體積與清晰度,80-85 通常最佳 |
| 記憶體管理 | 及時 imagedestroy | 防止大量圖片處理時內存洩漏 |
ini_set('memory_limit', '256M'),或分塊處理(需 ImageMagick) Intervention/Image 庫imagewebp(),現代瀏覽器體積減 30%+| 場景 | 推薦 | 理由 |
|---|---|---|
| 常規縮略圖、質量要求一般 | GD | PHP 內建、無額外依賴、部署簡單 |
| 大圖、高質量、保留 EXIF、WebP、色彩管理 | ImageMagick (imagick 擴展) | 功能強、性能好、支援格式多、多線程 |
| 極高併發、雲原生 | 對象存儲圖片處理(OSS/CDN) | 卸載應用服務器、無狀態、無限擴展 |
掌握這個 imgResize(),即可覆蓋 95% 的圖片縮放需求。建議封裝為 ImageService,統一異常處理、日誌記錄、格式轉換、存儲適配,構建可維護的圖片處理核心模組。