直接用 imagecopyresampled() 縮放 PNG 會導致透明通道丟失(變黑背景)。本文提供保持 Alpha 通道完整的標準 GD 代碼模式,解釋關鍵函數原理與常見坑點。
imagecreatetruecolor() 創建的畫布默認不透明(黑色背景)imagesavealpha()<?php
/**
* 等比縮放 PNG 保持透明度
* @param string $srcPath 源文件路徑
* @param string $dstPath 目標文件路徑
* @param int $maxWidth 最大寬度
* @param int $maxHeight 最大高度
* @return bool
*/
function resizePngKeepAlpha($srcPath, $dstPath, $maxWidth = 800, $maxHeight = 600) {
// 1. 載入源圖
$srcImg = imagecreatefrompng($srcPath);
if (!$srcImg) return false;
$srcW = imagesx($srcImg);
$srcH = imagesy($srcImg);
// 2. 計算目標尺寸 (等比縮放)
$ratio = min($maxWidth / $srcW, $maxHeight / $srcH);
if ($ratio >= 1) {
// 無需縮放,直接複製
return copy($srcPath, $dstPath);
}
$dstW = (int)round($srcW * $ratio);
$dstH = (int)round($srcH * $ratio);
// 3. 創建真彩色目標畫布
$dstImg = imagecreatetruecolor($dstW, $dstH);
if (!$dstImg) return false;
// 4. 關鍵步驟:分配全透明色並填充
$transparent = imagecolorallocatealpha($dstImg, 0, 0, 0, 127); // 127 = 完全透明
imagefill($dstImg, 0, 0, $transparent);
// 5. 關鍵步驟:啟用 Alpha 混合模式
imagealphablending($dstImg, true);
// 6. 縮放複製 (支持透明混合)
imagecopyresampled($dstImg, $srcImg, 0, 0, 0, 0, $dstW, $dstH, $srcW, $srcH);
// 7. 關鍵步驟:保存完整 Alpha 通道信息
imagesavealpha($dstImg, true);
// 8. 輸出
$result = imagepng($dstImg, $dstPath);
// 9. 清理內存
imagedestroy($srcImg);
imagedestroy($dstImg);
return $result;
}
// 使用
resizePngKeepAlpha('source.png', 'thumb.png', 300, 200);
| 函數 | 作用 | 關鍵參數 |
|---|---|---|
imagecolorallocatealpha() | 分配帶 Alpha 的顏色 | $alpha: 0(不透明) ~ 127(全透明) |
imagefill() | 填充畫布背景 | 用透明色填充整個畫布 |
imagealphablending() | 設置混合模式 | true=混合模式(默認), false=覆蓋模式 |
imagesavealpha() | 輸出時保存 Alpha | true=保存完整通道, false=混合後輸出 |
imagecopyresampled() | 重採樣縮放 | 高質量縮放,支持透明混合 |
// 錯誤 1: 忽略 imagefill + imagesavealpha
$dst = imagecreatetruecolor($w, $h);
imagecopyresampled($dst, $src, ...);
imagepng($dst); // 背景變黑
// 錯誤 2: 用 imagecolortransparent (僅支持單一透明色,不支持半透明漸變)
$transparent = imagecolorallocate($dst, 255, 0, 255); // 品紅
imagecolortransparent($dst, $transparent); // 僅這顏色透明
// 錯誤 3: 開啟 alphablending 但未 imagesavealpha
imagealphablending($dst, true);
imagecopyresampled(...);
imagepng($dst); // 輸出時 Alpha 丟失
function smartResize($src, $dst, $maxW, $maxH) {
// 檢查目標是否存在且更新
if (file_exists($dst) && filemtime($dst) >= filemtime($src)) {
return $dst; // 直接返回緩存
}
// 確保目標目錄存在
$dir = dirname($dst);
if (!is_dir($dir)) mkdir($dir, 0755, true);
if (resizePngKeepAlpha($src, $dst, $maxW, $maxH)) {
return $dst;
}
return $src; // 失敗回退原圖
}
Image::make($src)->resize(300, 200, function($c) {$c->aspectRatio();})->save($dst); 自動處理透明度$im->resizeImage(300, 200, Imagick::FILTER_LANCZOS, 1); 性能更強、格式支持更全掌握 GD 透明度處理細節,能在無法安裝擴展的環境下正確輸出 PNG 縮圖。