unlink<?php
/**
* 通用圖片縮放
*
* @param string $file 來源圖片路徑
* @param int $width 目標寬度 (0=依比例)
* @param int $height 目標高度 (0=依比例)
* @param bool $proportional 是否等比例縮放
* @param string $output 'file'=覆蓋原檔 | 'browser'=直接輸出 | 'return'=回傳 GD 資源 | 路徑字串=另存新檔
* @param bool $deleteOriginal 縮放成功後是否刪除原檔
* @param bool $useLinuxCmd 刪除時是否用 exec('rm') (需權限)
* @param int $jpegQuality JPEG 輸出品質 (1-100)
* @return bool|resource 成功 true / 資源 / 失敗 false
*/
function smartResizeImage(
string $file,
int $width = 0,
int $height = 0,
bool $proportional = true,
string|bool $output = 'file',
bool $deleteOriginal = false,
bool $useLinuxCmd = false,
int $jpegQuality = 85
): bool|resource {
// 1. 參數驗證
if ($width <= 0 && $height <= 0) return false;
if (!file_exists($file) || !is_readable($file)) return false;
// 2. 取得原圖資訊
$info = @getimagesize($file);
if ($info === false) return false;
[$srcW, $srcH, $type] = $info;
// 3. 計算目標尺寸
if ($proportional) {
if ($width == 0) $factor = $height / $srcH;
elseif ($height == 0) $factor = $width / $srcW;
else $factor = min($width / $srcW, $height / $srcH);
$dstW = (int)round($srcW * $factor);
$dstH = (int)round($srcH * $factor);
} else {
$dstW = $width > 0 ? $width : $srcW;
$dstH = $height > 0 ? $height : $srcH;
}
// 4. 建立來源資源
$src = match ($type) {
IMAGETYPE_GIF => @imagecreatefromgif($file),
IMAGETYPE_JPEG => @imagecreatefromjpeg($file),
IMAGETYPE_PNG => @imagecreatefrompng($file),
IMAGETYPE_WEBP => @imagecreatefromwebp($file), // PHP 8.1+
default => null,
};
if (!$src) return false;
// 5. 建立真彩色目標畫布
$dst = imagecreatetruecolor($dstW, $dstH);
// 6. 透明背景處理 (關鍵!)
if ($type === IMAGETYPE_GIF || $type === IMAGETYPE_PNG) {
// 關閉混合模式,啟用 Alpha 通道儲存
imagealphablending($dst, false);
imagesavealpha($dst, true);
// 建立全透明色並填滿
$transparent = imagecolorallocatealpha($dst, 0, 0, 0, 127);
imagefill($dst, 0, 0, $transparent);
// GIF 可能有調色盤透明色,額外處理
if ($type === IMAGETYPE_GIF) {
$trnIdx = imagecolortransparent($src);
if ($trnIdx >= 0) {
$trnColor = imagecolorsforindex($src, $trnIdx);
$newTrnIdx = imagecolorallocatealpha(
$dst,
$trnColor['red'],
$trnColor['green'],
$trnColor['blue'],
127
);
imagefill($dst, 0, 0, $newTrnIdx);
imagecolortransparent($dst, $newTrnIdx);
}
}
}
// 7. 高品質重採樣縮放
imagecopyresampled($dst, $src, 0, 0, 0, 0, $dstW, $dstH, $srcW, $srcH);
// 8. 輸出處理
$result = false;
$outPath = null;
if ($output === 'browser') {
header('Content-Type: ' . image_type_to_mime_type($type));
$outPath = null;
} elseif ($output === 'return') {
return $dst; // 呼叫端負責 imagedestroy
} elseif ($output === 'file' || $output === true) {
$outPath = $file; // 覆蓋原檔
} else {
$outPath = $output; // 自訂路徑
}
if ($outPath !== null) {
$result = match ($type) {
IMAGETYPE_GIF => imagegif($dst, $outPath),
IMAGETYPE_JPEG => imagejpeg($dst, $outPath, $jpegQuality),
IMAGETYPE_PNG => imagepng($dst, $outPath),
IMAGETYPE_WEBP => imagewebp($dst, $outPath, $jpegQuality), // PHP 8.1+
default => false,
};
} else {
// browser 模式
$result = match ($type) {
IMAGETYPE_GIF => imagegif($dst),
IMAGETYPE_JPEG => imagejpeg($dst, null, $jpegQuality),
IMAGETYPE_PNG => imagepng($dst),
IMAGETYPE_WEBP => imagewebp($dst, null, $jpegQuality),
default => false,
};
}
// 9. 清理資源
imagedestroy($src);
if ($output !== 'return') imagedestroy($dst);
// 10. 刪除原檔
if ($result && $deleteOriginal && $outPath === $file) {
if ($useLinuxCmd) {
@exec('rm ' . escapeshellarg($file));
} else {
@unlink($file);
}
}
return $result;
}
<?php
// 1. 等比縮放寬度 800px,覆蓋原檔,JPEG 品質 90
smartResizeImage('photo.jpg', 800, 0, true, 'file', false, false, 90);
// 2. 固定 300x300 正方形(裁切需另寫),另存新檔
smartResizeImage('logo.png', 300, 300, false, 'thumb_logo.png');
// 3. 直接輸出到瀏覽器(適用圖片代理端點)
smartResizeImage('avatar.gif', 150, 150, true, 'browser');
// 4. 取得 GD 資源進一步處理(加水印、合成等)
$res = smartResizeImage('input.png', 400, 0, true, 'return');
if ($res) {
// ... 進一步操作 ...
imagedestroy($res);
}
// 5. 批次處理目錄
foreach (glob('uploads/*.{jpg,png,gif}', GLOB_BRACE) as $f) {
smartResizeImage($f, 1200, 1200, true, 'file', false, false, 85);
}
| 格式 | 透明機制 | 關鍵函式 |
|---|---|---|
| PNG | Alpha 通道 (0-127) | imagealphablending(false), imagesavealpha(true), imagecolorallocatealpha(..., 127) |
| GIF | 調色盤單一透明索引 | imagecolortransparent(), imagecolorsforindex(), 同 PNG Alpha 步驟 |
| WebP | 支援有損/無損 Alpha | 同 PNG,imagewebp() 參數 quality 控制 |
imagealphablending(false) + imagesavealpha(true)。imagick 擴充或 gifsicle 指令工具。imagecreatetruecolor 佔用大量記憶體,調大 memory_limit 或分塊處理。<?php
function resizeWithImagick(string $src, string $dst, int $w, int $h, bool $prop = true): bool
{
try {
$im = new Imagick($src);
if ($prop) {
$im->thumbnailImage($w, $h, true); // 等比
} else {
$im->resizeImage($w, $h, Imagick::FILTER_LANCZOS, 1);
}
// 保留 ICC Profile、EXIF、透明度
$im->setImageCompressionQuality(85);
$im->writeImage($dst);
return true;
} catch (ImagickException $e) {
error_log($e->getMessage());
return false;
}
}
GD 版 smartResizeImage 功能完整、零依賴、適合中小專案。關鍵在於**正確處理 Alpha 通道**(PNG/WebP)與**調色盤透明索引**(GIF)。大型、高併發、需動畫/色彩管理專案,請直接上 **ImageMagick (imagick擴充)** 或 **libvips (php-vips)**,效能與功能更強。