本文封裝一個健壯的 createSmallImg() 函數,支持 JPEG/PNG/GIF 格式、指定最大寬/高單邊限制、保持原圖比例、輸出質量控制、錯誤處理,可直接用於項目中。
<?php
/**
* 創建等比例縮略圖
* @param string $dir 圖片目錄絕對路徑 (結尾帶 /)
* @param string $sourceImg 源文件名 (如 photo.jpg)
* @param string $suffix 縮略圖文件名後綴 (默認 _s)
* @param int $maxWidth 最大寬度 (像素),與 maxHeight 二擇一
* @param int $maxHeight 最大高度 (像素),與 maxWidth 二擇一
* @return string|false 成功返回縮略圖相對路徑,失敗返回 false
*/
function createSmallImg($dir, $sourceImg, $suffix = '_s', $maxWidth = 0, $maxHeight = 0) {
// 1. 參數校驗
if (($maxWidth <= 0 && $maxHeight <= 0) || ($maxWidth > 0 && $maxHeight > 0)) {
trigger_error('必須且只能指定 maxWidth 或 maxHeight 其中一項', E_USER_WARNING);
return false;
}
$sourcePath = $dir . $sourceImg;
if (!is_file($sourcePath) || !is_readable($sourcePath)) {
trigger_error("源文件不存在或不可讀: $sourcePath", E_USER_WARNING);
return false;
}
// 2. 解析文件信息
$info = pathinfo($sourceImg);
$filename = $info['filename']; // PHP 5.2+ 無 filename 鍵,兼容寫法見下
if (!isset($filename)) {
$filename = substr($sourceImg, 0, strrpos($sourceImg, '.'));
}
$ext = strtolower($info['extension'] ?? '');
$allowed = ['jpg', 'jpeg', 'png', 'gif'];
if (!in_array($ext, $allowed)) {
trigger_error("不支持的圖片格式: $ext", E_USER_WARNING);
return false;
}
// 統一 jpeg 副檔名
$extOut = ($ext === 'jpeg') ? 'jpg' : $ext;
// 3. 創建源圖資源
$createFunc = "imagecreatefrom$extOut";
if ($extOut === 'jpg') $createFunc = 'imagecreatefromjpeg';
if (!function_exists($createFunc)) {
trigger_error("GD 庫未編譯 $extOut 支持", E_USER_WARNING);
return false;
}
$srcImg = @$createFunc($sourcePath);
if (!$srcImg) {
trigger_error("源圖資源創建失敗 (可能文件損壞): $sourcePath", E_USER_WARNING);
return false;
}
$srcW = imagesx($srcImg);
$srcH = imagesy($srcImg);
// 4. 計算目標尺寸
if ($maxHeight > 0 && $srcH >= $maxHeight) {
$dstH = $maxHeight;
$dstW = (int)round($srcW * $dstH / $srcH);
} elseif ($maxWidth > 0 && $srcW >= $maxWidth) {
$dstW = $maxWidth;
$dstH = (int)round($srcH * $dstW / $srcW);
} else {
// 原圖已小於限制,無需縮放,直接複製或返回原路徑
imagedestroy($srcImg);
return $sourceImg; // 或按需複製文件
}
// 5. 創建目標真彩色畫布
$dstImg = imagecreatetruecolor($dstW, $dstH);
// PNG/GIF 透明度保持
if ($extOut === 'png' || $extOut === 'gif') {
imagealphablending($dstImg, false);
imagesavealpha($dstImg, true);
$transparent = imagecolorallocatealpha($dstImg, 255, 255, 255, 127);
imagefilledrectangle($dstImg, 0, 0, $dstW, $dstH, $transparent);
}
// 6. 高質量重採樣縮放
if (!imagecopyresampled($dstImg, $srcImg, 0, 0, 0, 0, $dstW, $dstH, $srcW, $srcH)) {
imagedestroy($srcImg);
imagedestroy($dstImg);
trigger_error('圖片重採樣失敗', E_USER_WARNING);
return false;
}
// 7. 輸出保存
$destName = $filename . $suffix . '.' . $extOut;
$destPath = $dir . $destName;
$saveFunc = "image$extOut";
if ($extOut === 'jpg') $saveFunc = 'imagejpeg';
$result = false;
if ($extOut === 'jpg') {
$result = @$saveFunc($dstImg, $destPath, 90); // 質量 90%
} else {
$result = @$saveFunc($dstImg, $destPath);
}
// 8. 清理資源
imagedestroy($srcImg);
imagedestroy($dstImg);
if (!$result) {
trigger_error("縮略圖保存失敗: $destPath", E_USER_WARNING);
return false;
}
return $destName; // 返回文件名,便於構建 URL
}
// --- 使用示例 ---
// 目錄結構: /var/www/html/uploads/photo.jpg
$uploadDir = '/var/www/html/uploads/';
// 生成寬度不超過 300px 的縮略圖
$thumb = createSmallImg($uploadDir, 'photo.jpg', '_thumb', 300, 0);
if ($thumb) {
echo "成功:
";
} else {
echo "失敗,查看 error_log";
}
?>
| 現象 | 原因 | 解決 |
|---|---|---|
| 生成的圖片是黑色/空白 | 未處理 PNG/GIF 透明通道 | 添加 `imagealphablending(false); imagesavealpha(true);` 及透明色填充 |
| 報錯 Call to undefined function imagecreatefromjpeg() | PHP 編譯時未加 `--with-jpeg-dir` | 重新編譯 PHP 或安裝 `php-gd` 擴展包 (yum/dnf/apt) |
| 內存耗盡 Fatal error | 超大圖片 (如 5000x5000) 解碼佔用巨大內存 | 預先檢查 `getimagesize()` 尺寸,拒絕超限圖片;或用 Imagick 流式處理 |
| 輸出文件 0 字節 | 目錄不可寫、磁盤滿、GD 輸出失敗 | 檢查 `is_writable($dir)`、磁盤空間、error_log |