首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 相關知識

PHP 完美支援 PNG 透明背景的縮略圖生成類

     編輯:PHP 相關知識

針對 GD2 生成 PNG 縮略圖時「透明變黑、格式強制轉 JPG」的經典痛點,本文提供改良版類,完整保留 Alpha 通道,支援 PNG/GIF/JPG 統一處理,代碼結構現代化(命名空間、類型聲明、異常處理)。

核心改進點

  1. 輸出格式跟隨源圖:PNG 輸出 PNG、GIF 輸出 GIF、JPG 輸出 JPG,不再強制轉 JPG。
  2. 透明度完整保留:imagecreatetruecolor + imagefill(..., imagecolorallocatealpha(..., 127)) + imagesavealpha(true) 三步驟建立全透明畫布。
  3. 現代化代碼風格:private 封裝、__construct 初始化、異常拋出、類型提示。

類完整代碼

<?php
/**
 * PNG 透明友好的縮略圖生成器
 * @author 十年後的盧哥哥
 * @date 2014-11-13 (重構優化版)
 */
class ResizeImage {
    private string $srcPath;
    private string $dstPath;
    private int $targetW;
    private int $targetH;
    private bool $cut;
    private string $type;
    private $imgRes; // GD resource
    private int $srcW, $srcH;

    public function __construct(string $srcPath, int $width, int $height, bool $isCut, string $savePath) {
        $this->srcPath = $srcPath;
        $this->targetW = $width;
        $this->targetH = $height;
        $this->cut = $isCut;
        $this->dstPath = $savePath;

        $this->type = strtolower(pathinfo($srcPath, PATHINFO_EXTENSION));
        $this->initImage();
        $this->srcW = imagesx($this->imgRes);
        $this->srcH = imagesy($this->imgRes);
        $this->process();
        imagedestroy($this->imgRes);
    }

    private function initImage(): void {
        switch ($this->type) {
            case 'jpg': case 'jpeg': $this->imgRes = imagecreatefromjpeg($this->srcPath); break;
            case 'png': $this->imgRes = imagecreatefrompng($this->srcPath); break;
            case 'gif': $this->imgRes = imagecreatefromgif($this->srcPath); break;
            default: throw new \InvalidArgumentException("Unsupported image type: {$this->type}");
        }
        if (!$this->imgRes) throw new \RuntimeException("Failed to load image: {$this->srcPath}");
    }

    private function process(): void {
        $srcRatio = $this->srcW / $this->srcH;
        $dstRatio = $this->targetW / $this->targetH;

        if ($this->cut) {
            // 裁剪模式:目標尺寸固定
            $canvas = $this->createTransparentCanvas($this->targetW, $this->targetH);
            if ($srcRatio >= $dstRatio) {
                // 寬度富餘,按高度縮放,左右裁剪
                $cropW = $this->srcH * $dstRatio;
                $srcX = ($this->srcW - $cropW) / 2;
                imagecopyresampled($canvas, $this->imgRes, 0, 0, $srcX, 0, $this->targetW, $this->targetH, $cropW, $this->srcH);
            } else {
                // 高度富餘,按寬度縮放,上下裁剪
                $cropH = $this->srcW / $dstRatio;
                $srcY = ($this->srcH - $cropH) / 2;
                imagecopyresampled($canvas, $this->imgRes, 0, 0, 0, $srcY, $this->targetW, $this->targetH, $this->srcW, $cropH);
            }
        } else {
            // 等比縮放:畫布尺寸自適應
            if ($srcRatio >= $dstRatio) {
                $newW = $this->targetW;
                $newH = $this->targetW / $srcRatio;
            } else {
                $newH = $this->targetH;
                $newW = $this->targetH * $srcRatio;
            }
            $canvas = $this->createTransparentCanvas($newW, $newH);
            imagecopyresampled($canvas, $this->imgRes, 0, 0, 0, 0, $newW, $newH, $this->srcW, $this->srcH);
        }

        $this->saveOutput($canvas);
        imagedestroy($canvas);
    }

    /** 建立支援透明的真彩色畫布 */
    private function createTransparentCanvas(int $w, int $h) {
        $canvas = imagecreatetruecolor($w, $h);
        if ($this->type === 'png' || $this->type === 'gif') {
            // 關鍵三步:關閉混色、分配全透明色、填充、啟用 Alpha 保存
            imagealphablending($canvas, false);
            $transparent = imagecolorallocatealpha($canvas, 0, 0, 0, 127);
            imagefill($canvas, 0, 0, $transparent);
            imagesavealpha($canvas, true);
        }
        return $canvas;
    }

    private function saveOutput($canvas): void {
        switch ($this->type) {
            case 'png':
                imagepng($canvas, $this->dstPath, 6); // 壓縮等級 6
                break;
            case 'gif':
                imagegif($canvas, $this->dstPath);
                break;
            default: // jpg/jpeg
                imagejpeg($canvas, $this->dstPath, 90);
        }
    }
}
?>

使用範例

<?php
require 'ResizeImage.php';

// JPG 等比縮放
new ResizeImage("img/photo.jpg", 320, 240, false, "img/photo_320x240.jpg");

// PNG 裁剪模式,保留透明背景
new ResizeImage("img/logo.png", 200, 200, true, "img/logo_200x200.png");
?>

常見問題排查

現象原因解決
PNG 變黑底未關閉 alpha blending、未 imagesavealpha參考 createTransparentCanvas() 實現
GIF 動畫只剩第一幀GD 不支援多幀處理改用 Imagick 或 ffmpeg
記憶體耗盡大圖解碼佔用巨大內存分塊處理、增加 memory_limit、或用 Imagick 流式處理
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved