使用 GD 庫縮放 GIF 圖片時,最常見的問題是透明背景變為黑色。這是因為 imagecreatetruecolor() 創建的畫布默認黑色,且未正確複製透明色信息。本類封裝了完整的透明色保留邏輯。
class ResizeImage {
private $srcPath, $dstPath;
private $srcImg, $dstImg;
private $srcW, $srcH, $dstW, $dstH;
private $scale = 0.5; // 默認縮放比例 50%
public function __construct($srcPath, $dstPath) {
$this->srcPath = $srcPath;
$this->dstPath = $dstPath;
list($this->srcW, $this->srcH) = getimagesize($srcPath);
}
public function setScale($scale) {
$this->scale = max(0.01, min(10, $scale)); // 限制 1%-1000%
}
public function resizeAndSave() {
// 計算目標尺寸(等比)
$this->dstW = round($this->srcW * $this->scale);
$this->dstH = round($this->srcH * $this->scale);
// 創建源圖資源(僅支持 GIF)
$this->srcImg = imagecreatefromgif($this->srcPath);
if (!$this->srcImg) throw new Exception('非有效 GIF 文件');
// 創建真彩色目標畫布
$this->dstImg = imagecreatetruecolor($this->dstW, $this->dstH);
// === 關鍵:保留透明色 ===
$transparentIndex = imagecolortransparent($this->srcImg);
if ($transparentIndex >= 0 && $transparentIndex < imagecolorstotal($this->srcImg)) {
// 獲取透明色 RGB
$rgb = imagecolorsforindex($this->srcImg, $transparentIndex);
// 在目標畫布分配相同顏色
$newTransparent = imagecolorallocate($this->dstImg, $rgb['red'], $rgb['green'], $rgb['blue']);
// 填充背景為該透明色
imagefill($this->dstImg, 0, 0, $newTransparent);
// 設置目標畫布透明色
imagecolortransparent($this->dstImg, $newTransparent);
}
// 等比縮放繪制
imagecopyresampled(
$this->dstImg, $this->srcImg,
0, 0, 0, 0,
$this->dstW, $this->dstH,
$this->srcW, $this->srcH
);
// 輸出保存
imagegif($this->dstImg, $this->dstPath);
$this->destroy();
}
private function destroy() {
if ($this->srcImg) imagedestroy($this->srcImg);
if ($this->dstImg) imagedestroy($this->dstImg);
}
}
require 'ResizeImage.php';
$resizer = new ResizeImage('source.gif', 'thumb.gif');
$resizer->setScale(0.3); // 縮小到 30%
$resizer->resizeAndSave();
echo '縮略圖已生成:thumb.gif';
| 步驟 | 函數 | 作用 |
|---|---|---|
| 1 | imagecolortransparent() | 獲取源圖透明色索引 |
| 2 | imagecolorsforindex() | 將索引轉為 RGB 數組 |
| 3 | imagecolorallocate() | 在新畫布註冊相同顏色 |
| 4 | imagefill() | 用透明色填充新畫布背景 |
| 5 | imagecolortransparent() | 將新畫布該顏色標記為透明 |
| 6 | imagecopyresampled() | 高質量重採樣縮放 |
若需通用圖片縮放,可根據 getimagesize() 返回的 MIME 類型動態選擇 imagecreatefromgif/png/jpeg 及輸出函數,透明色處理邏輯對 PNG 同樣適用(PNG 使用 Alpha 通道,另需 imagesavealpha($dstImg, true))。