功能特色
- 支援 JPG、PNG、GIF、BMP 四種主流格式
- 智慧檢測圖片類型(不依賴副檔名)
- 兩種模式:裁切填滿(預設)與 等比縮放(保留完整畫面)
- 可指定輸出品質、目標路徑(預設覆蓋原檔)
- 完整錯誤代碼回傳,便於程式邏輯判斷
函數簽名與回傳結構
function thumbImage(
string $file, // 來源圖片路徑
int $thumbWidth, // 目標寬度
int $thumbHeight, // 目標高度
string $savePath = '', // 儲存路徑(空則覆蓋原檔)
bool $isCut = true, // true=裁切填滿 false=等比縮放
int $quality = 100 // JPG 輸出品質 0-100
): array
// 回傳陣列結構
[
'status' => 0, // 0成功 1檔案不存在 2格式不支援 3尺寸過小
'file' => '1.jpg',
'width' => 200,
'height' => 200,
'savePath' => '2.jpg',
'info' => '縮略圖片生成成功'
]
完整函數實作
<?php
function thumbImage($file, $thumbWidth, $thumbHeight, $savePath = '', $isCut = true, $quality = 100) {
$result = ['status' => 0, 'file' => '', 'width' => 0, 'height' => 0, 'savePath' => '', 'info' => ''];
// 1. 檔案存在性檢查
if (!file_exists($file)) {
return ['status' => 1, 'info' => '圖片檔案不存在'];
}
// 2. 讀取檔頭判斷真實類型(避免副檔名偽裝)
$fp = fopen($file, 'rb');
$bytes = fread($fp, 2);
fclose($fp);
$arr = @unpack('c2chars', $bytes);
$typeCode = intval($arr['chars1'] . $arr['chars2']);
$fileType = '';
switch ($typeCode) {
case 255216: $fileType = 'jpg'; break; // FF D8
case 7173: $fileType = 'gif'; break; // 47 49
case 6677: $fileType = 'bmp'; break; // 42 4D
case 13780: $fileType = 'png'; break; // 89 50
default: $fileType = $typeCode;
}
// 處理有符號位元組情況
if ($arr['chars1'] === -1 && $arr['chars2'] === -40) $fileType = 'jpg';
if ($arr['chars1'] === -119 && $arr['chars2'] === 80) $fileType = 'png';
if (!in_array($fileType, ['jpg', 'gif', 'bmp', 'png'])) {
return ['status' => 2, 'info' => "不支援的圖片格式: {$fileType}"];
}
// 3. 建立 GD 圖片資源
switch ($fileType) {
case 'jpg': $im = imagecreatefromjpeg($file); break;
case 'gif': $im = imagecreatefromgif($file); break;
case 'png': $im = imagecreatefrompng($file); break;
case 'bmp': // BMP 需自行實作或轉檔
return ['status' => 2, 'info' => 'BMP 格式暫不支援,請先轉檔'];
}
if (empty($savePath)) $savePath = $file;
$width = imagesx($im);
$height = imagesy($im);
// 4. 來源圖較小時不放大(可透過 $isCut=false 允許放大)
if ($width < $thumbWidth && $height < $thumbHeight && $isCut) {
return ['status' => 3, 'info' => '圖片尺寸小於目標縮略圖尺寸'];
}
$ratio = $width / $height;
$thumbRatio = $thumbWidth / $thumbHeight;
// 5. PHP 5.1.2+ imagepng 品質參數意義改變(0-9 壓縮等級)
if (function_exists('imagepng') && (int)str_replace('.', '', PHP_VERSION) >= 512) {
$quality = 9; // PNG 壓縮等級 9(最小檔案)
}
// 6. 核心縮放邏輯
if ($isCut) {
// --- 裁切模式:填滿目標區域,超出部分裁切 ---
if ($ratio >= $thumbRatio) {
// 來源較寬 -> 以高度為基準縮放,寬度超出部分裁切
$newImg = imagecreatetruecolor($thumbWidth, $thumbHeight);
$srcW = $height * $thumbRatio;
imagecopyresampled($newImg, $im, 0, 0, 0, 0, $thumbWidth, $thumbHeight, $srcW, $height);
} else {
// 來源較高 -> 以寬度為基準縮放,高度超出部分裁切
$newImg = imagecreatetruecolor($thumbWidth, $thumbHeight);
$srcH = $width / $thumbRatio;
imagecopyresampled($newImg, $im, 0, 0, 0, 0, $thumbWidth, $thumbHeight, $width, $srcH);
}
imagejpeg($newImg, $savePath, $quality);
} else {
// --- 等比縮放模式:完整保留畫面,可能留白 ---
if ($ratio >= $thumbRatio) {
// 以寬度為基準
$newH = $thumbWidth / $ratio;
$newImg = imagecreatetruecolor($thumbWidth, $newH);
imagecopyresampled($newImg, $im, 0, 0, 0, 0, $thumbWidth, $newH, $width, $height);
} else {
// 以高度為基準
$newW = $thumbHeight * $ratio;
$newImg = imagecreatetruecolor($newW, $thumbHeight);
imagecopyresampled($newImg, $im, 0, 0, 0, 0, $newW, $thumbHeight, $width, $height);
}
imagejpeg($newImg, $savePath, $quality);
}
imagedestroy($im);
if (isset($newImg)) imagedestroy($newImg);
return [
'status' => 0,
'file' => $file,
'width' => $thumbWidth,
'height' => $thumbHeight,
'savePath' => $savePath,
'info' => '縮略圖片生成成功'
];
}
?>
使用範例
<?php
// 1. 裁切模式產生 200x100 縮略圖,另存新檔
$result = thumbImage('uploads/photo.jpg', 200, 100, 'thumbs/photo_thumb.jpg');
print_r($result);
// 2. 等比縮放模式,最大寬高 300x300,覆蓋原檔
$result = thumbImage('uploads/photo.jpg', 300, 300, '', false, 90);
// 3. 批次處理上傳目錄
foreach (glob('uploads/*.jpg') as $file) {
$out = 'thumbs/' . basename($file);
thumbImage($file, 150, 150, $out, true, 85);
}
?>
進階優化建議
| 優化方向 | 說明 |
| 支援 WebP/HEIC |
使用 imagecreatefromwebp()、imagecreatefromheic()(需 PHP 7.2+ / 8.1+) |
| 記憶體優化 |
大圖分塊處理或使用 Imagick 串流模式避免 memory_limit 耗盡 |
| 銳化處理 |
縮放後套用 imageconvolution() 銳化核矩陣提升清晰度 |
| 非同步佇列 |
上傳後推入 Redis/RabbitMQ,Worker 後台生成縮圖,API 秒回應 |
| 快取策略 |
以「原檔路徑+尺寸+模式」為 Key 快取,避免重複生成 |
常見問題排查
- 輸出黑色/空白:檢查
imagecreatetruecolor() 是否成功,GD 擴展是否啟用
- PNG 透明背景變黑:需啟用
imagealphablending($newImg, false); imagesavealpha($newImg, true);
- GIF 動畫只剩第一幀:GD 不支援多幀 GIF 處理,需用 Imagick 或 ffmpeg
- 權限錯誤:確認目標目錄可寫(
chmod 755 或 PHP-FPM 執行身分擁有權限)