<?php
/**
* 產生縮圖
*
* @param string $sourcePath 來源圖片路徑
* @param string $destPath 輸出路徑(留空覆蓋原檔)
* @param int $maxWidth 最大寬度
* @param int $maxHeight 最大高度
* @param int $quality 輸出品質 1-100 (JPEG/WebP)
* @param bool $upscale 是否允許放大(預設 false)
* @return bool|array 成功回傳 ['width'=>, 'height'=>, 'path'=>],失敗回傳 false
*/
function createThumbnail(
string $sourcePath,
string $destPath = '',
int $maxWidth = 800,
int $maxHeight = 600,
int $quality = 85,
bool $upscale = false
) {
// 1. 驗證來源檔案
if (!file_exists($sourcePath) || !is_readable($sourcePath)) {
trigger_error("來源檔案不存在或不可讀: $sourcePath", E_USER_WARNING);
return false;
}
// 2. 取得圖片資訊
$imageInfo = @getimagesize($sourcePath);
if (!$imageInfo) {
trigger_error("無法識別圖片格式: $sourcePath", E_USER_WARNING);
return false;
}
[$srcWidth, $srcHeight, $mimeType] = $imageInfo;
// 3. 計算目標尺寸(等比例)
$ratio = min($maxWidth / $srcWidth, $maxHeight / $srcHeight);
if (!$upscale && $ratio >= 1) {
// 無需縮放,直接複製或回傳原資訊
if ($destPath && $destPath !== $sourcePath) {
copy($sourcePath, $destPath);
}
return ['width' => $srcWidth, 'height' => $srcHeight, 'path' => $destPath ?: $sourcePath];
}
$dstWidth = (int)round($srcWidth * $ratio);
$dstHeight = (int)round($srcHeight * $ratio);
// 4. 建立來源圖片資源
$createFunc = match ($mimeType) {
IMAGETYPE_JPEG => 'imagecreatefromjpeg',
IMAGETYPE_PNG => 'imagecreatefrompng',
IMAGETYPE_GIF => 'imagecreatefromgif',
IMAGETYPE_WEBP => 'imagecreatefromwebp',
default => null,
};
if (!$createFunc || !function_exists($createFunc)) {
trigger_error("不支援的圖片格式或 GD 未編譯支援: $mimeType", E_USER_WARNING);
return false;
}
$srcImage = $createFunc($sourcePath);
if (!$srcImage) {
trigger_error("建立圖片資源失敗: $sourcePath", E_USER_WARNING);
return false;
}
// 5. 建立目標真彩色畫布
$dstImage = imagecreatetruecolor($dstWidth, $dstHeight);
// 6. 處理透明度(PNG/GIF/WebP)
if (in_array($mimeType, [IMAGETYPE_PNG, IMAGETYPE_GIF, IMAGETYPE_WEBP], true)) {
imagealphablending($dstImage, false);
imagesavealpha($dstImage, true);
$transparent = imagecolorallocatealpha($dstImage, 255, 255, 255, 127);
imagefilledrectangle($dstImage, 0, 0, $dstWidth, $dstHeight, $transparent);
}
// 7. 高品質重採樣
if (function_exists('imagecopyresampled')) {
imagecopyresampled($dstImage, $srcImage, 0, 0, 0, 0, $dstWidth, $dstHeight, $srcWidth, $srcHeight);
} else {
imagecopyresized($dstImage, $srcImage, 0, 0, 0, 0, $dstWidth, $dstHeight, $srcWidth, $srcHeight);
}
// 8. 確定輸出路徑與格式
$outputPath = $destPath ?: $sourcePath;
$outputMime = $mimeType;
// 若輸出副檔名不同,依副檔名決定格式
if ($destPath) {
$ext = strtolower(pathinfo($destPath, PATHINFO_EXTENSION));
$outputMime = match ($ext) {
'jpg', 'jpeg' => IMAGETYPE_JPEG,
'png' => IMAGETYPE_PNG,
'gif' => IMAGETYPE_GIF,
'webp' => IMAGETYPE_WEBP,
default => $mimeType,
};
}
// 9. 輸出圖片
$success = false;
switch ($outputMime) {
case IMAGETYPE_JPEG:
$success = imagejpeg($dstImage, $outputPath, $quality);
break;
case IMAGETYPE_PNG:
// PNG 品質 0-9 (壓縮等級),轉換 100->0, 0->9
$pngQuality = (int)round((100 - $quality) / 100 * 9);
$success = imagepng($dstImage, $outputPath, $pngQuality);
break;
case IMAGETYPE_GIF:
$success = imagegif($dstImage, $outputPath);
break;
case IMAGETYPE_WEBP:
$success = imagewebp($dstImage, $outputPath, $quality);
break;
}
// 10. 清理資源
imagedestroy($srcImage);
imagedestroy($dstImage);
// 11. 設定檔案權限(可選)
if ($success && $destPath) {
@chmod($outputPath, 0644);
}
return $success
? ['width' => $dstWidth, 'height' => $dstHeight, 'path' => $outputPath]
: false;
}
<?php
require 'thumbnail.php';
// 基本用法:縮圖至 800x600 內,品質 85
$result = createThumbnail('uploads/photo.jpg', 'thumbs/photo.jpg');
if ($result) {
echo "成功: {$result['width']}x{$result['height']} -> {$result['path']}";
} else {
echo "失敗";
}
// 進階:指定尺寸、品質、允許放大
createThumbnail(
'uploads/original.png',
'thumbs/small.webp', // 轉檔為 WebP
300, 300,
90,
true // 允許放大小圖
);
// 批量處理目錄
$files = glob('uploads/*.{jpg,jpeg,png,gif,webp}', GLOB_BRACE);
foreach ($files as $file) {
$name = basename($file);
createThumbnail($file, "thumbs/$name", 400, 300, 80);
}
// 原文問題程式碼
private function createSmallImg($fileName) {
list($width,$height,$type,$attr) = getimagesize($fileName);
$imgOld = imagecreatefromjpeg($fileName); // 僅支援 JPEG
$imgObj = imagecreatetruecolor($width-100, $height-100); // 固定減 100px,非等比例
// ...
unlink($fileName); // 危險:直接刪除原檔!
imagejpeg($imgObj, $fileName, 100); // 覆蓋原檔,無品質選擇
}
主要缺陷:
unlink() 在輸出前刪除原檔,失敗時資料永久遺失imagick 擴充套件(多執行緒、記憶體效率更好)