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

PHP GD 實作 App Logo 多尺寸自動產生與打包下載類別

     編輯:PHP 綜合知識

前言

App 發布需提供多種尺寸的 Logo(iOS/Android 各平台規範不同)。美工通常只給 1024x1024 主圖,開發者需手動裁切。本文提供一個 Image 類別,支援縮放、裁切、浮水印、多格式輸出,一鍵產生所有規格並打包下載。

核心類別程式碼

<?php
class Image {
    private $source = [];
    private $image;      // GD 資源
    private $ext;        // 副檔名
    private $error = ''; // 錯誤訊息

    public function __construct($source = null) {
        if ($source !== null) $this->source($source);
    }

    // 設定來源(支援檔案路徑或 $_FILES 陣列)
    public function source($source) {
        if (!is_array($source)) {
            $this->source['name'] = $source;
            $this->source['tmp_name'] = $source;
            $ext = strtolower(pathinfo($source, PATHINFO_EXTENSION));
            $types = ['jpg'=>'image/jpeg','jpeg'=>'image/jpeg','gif'=>'image/gif','png'=>'image/png'];
            $this->source['type'] = $types[$ext] ?? null;
        } else {
            $this->source = $source;
        }
        $this->destination = $this->source['name'];
    }

    // 縮放(保持比例,僅給寬或高即可)
    public function resize($width = null, $height = null) {
        if (empty($this->source['tmp_name']) || !file_exists($this->source['tmp_name'])) return;
        list($sw, $sh) = getimagesize($this->source['tmp_name']);
        if ($width === null && $height !== null) $width = ($sw * $height) / $sh;
        if ($height === null && $width !== null) $height = ($sh * $width) / $sw;
        if ($width === null && $height === null) { $width = $sw; $height = $sh; }

        $create = ['image/jpeg'=>'imagecreatefromjpeg','image/gif'=>'imagecreatefromgif','image/png'=>'imagecreatefrompng'];
        $func = $create[$this->source['type']] ?? null;
        if (!$func) return;
        $src = $func($this->source['tmp_name']);

        $this->image = imagecreatetruecolor($width, $height);
        // 保持透明度(PNG/GIF)
        if (in_array($this->source['type'], ['image/gif','image/png'])) {
            imagealphablending($this->image, false);
            imagesavealpha($this->image, true);
        }
        imagecopyresampled($this->image, $src, 0,0,0,0, $width,$height, $sw,$sh);
        imagedestroy($src);
    }

    // 裁切(指定左上座標與寬高)
    public function crop($x, $y, $width, $height) {
        if (empty($this->source['tmp_name']) || !file_exists($this->source['tmp_name'])) return;
        $create = ['image/jpeg'=>'imagecreatefromjpeg','image/gif'=>'imagecreatefromgif','image/png'=>'imagecreatefrompng'];
        $func = $create[$this->source['type']] ?? null;
        if (!$func) return;
        $src = $func($this->source['tmp_name']);
        $this->image = imagecreatetruecolor($width, $height);
        imagecopy($this->image, $src, 0,0, $x,$y, $width,$height);
        imagedestroy($src);
    }

    // 浮水印
    public function watermark($markFile, $opacity = 50, $posX = 'right', $posY = 'bottom') {
        if (empty($this->image) || !file_exists($markFile)) return;
        $markExt = strtolower(pathinfo($markFile, PATHINFO_EXTENSION));
        $mFunc = ['jpg'=>'imagecreatefromjpeg','jpeg'=>'imagecreatefromjpeg','gif'=>'imagecreatefromgif','png'=>'imagecreatefrompng'];
        $mark = $mFunc[$markExt]($markFile);
        list($mw, $mh) = getimagesize($markFile);
        $sw = imagesx($this->image); $sh = imagesy($this->image);

        $x = ($posX === 'left') ? 0 : $sw - $mw;
        $y = ($posY === 'top')  ? 0 : $sh - $mh;
        imagecopymerge($this->image, $mark, $x, $y, 0, 0, $mw, $mh, $opacity);
        imagedestroy($mark);
    }

    // 輸出檔案
    public function create($dest, $quality = 90) {
        if (empty($this->image)) return false;
        $ext = strtolower(pathinfo($dest, PATHINFO_EXTENSION));
        switch ($ext) {
            case 'gif':  imagegif($this->image, $dest); break;
            case 'png':  imagepng($this->image, $dest, round($quality/10)-1); break;
            default:     imagejpeg($this->image, $dest, $quality); break;
        }
        return true;
    }

    // 驗證副檔名
    public function validateExtension() {
        $allowed = ['image/jpeg','image/pjpeg','image/png','image/gif'];
        if (!in_array($this->source['type'] ?? '', $allowed)) {
            $this->error .= 'extension;';
        }
    }

    // 驗證檔案大小(KB)
    public function validateSize($maxKb) {
        if (($this->source['size'] ?? 0) > $maxKb * 1024) {
            $this->error .= 'size;';
        }
    }

    // 取得錯誤
    public function getErrors() {
        $msgs = [];
        if (strpos($this->error, 'extension') !== false) $msgs[] = '不支援的檔案格式';
        if (strpos($this->error, 'size') !== false) $msgs[] = '檔案過大';
        return $msgs;
    }
}
?>

使用範例:批量產生 App Logo

<?php
require 'Image.php';

$src = 'logo_1024.png'; // 美工提供的主圖
$specs = [
    // iOS
    ['name'=>'Icon-20.png',       'w'=>20,  'h'=>20],
    ['name'=>'Icon-20@2x.png',    'w'=>40,  'h'=>40],
    ['name'=>'Icon-20@3x.png',    'w'=>60,  'h'=>60],
    ['name'=>'Icon-29.png',       'w'=>29,  'h'=>29],
    ['name'=>'Icon-29@2x.png',    'w'=>58,  'h'=>58],
    ['name'=>'Icon-29@3x.png',    'w'=>87,  'h'=>87],
    ['name'=>'Icon-40@2x.png',    'w'=>80,  'h'=>80],
    ['name'=>'Icon-40@3x.png',    'w'=>120, 'h'=>120],
    ['name'=>'Icon-60@2x.png',    'w'=>120, 'h'=>120],
    ['name'=>'Icon-60@3x.png',    'w'=>180, 'h'=>180],
    ['name'=>'Icon-76.png',       'w'=>76,  'h'=>76],
    ['name'=>'Icon-76@2x.png',    'w'=>152, 'h'=>152],
    ['name'=>'Icon-83.5@2x.png',  'w'=>167, 'h'=>167],
    ['name'=>'Icon-1024.png',     'w'=>1024,'h'=>1024],
    // Android (mipmap)
    ['name'=>'mipmap-mdpi/ic_launcher.png',    'w'=>48,  'h'=>48],
    ['name'=>'mipmap-hdpi/ic_launcher.png',    'w'=>72,  'h'=>72],
    ['name'=>'mipmap-xhdpi/ic_launcher.png',   'w'=>96,  'h'=>96],
    ['name'=>'mipmap-xxhdpi/ic_launcher.png',  'w'=>144, 'h'=>144],
    ['name'=>'mipmap-xxxhdpi/ic_launcher.png', 'w'=>192, 'h'=>192],
];

$outDir = __DIR__ . '/output_logos/';
if (!is_dir($outDir)) mkdir($outDir, 0755, true);

foreach ($specs as $spec) {
    $img = new Image($src);
    $img->resize($spec['w'], $spec['h']);
    $dest = $outDir . $spec['name'];
    // 確保子目錄存在
    @mkdir(dirname($dest), 0755, true);
    $img->create($dest);
    echo "Generated: {$spec['name']} ({$spec['w']}x{$spec['h']})<br>";
}

// 打包下載
$zip = new ZipArchive();
$zipFile = $outDir . 'app_logos.zip';
if ($zip->open($zipFile, ZipArchive::CREATE | ZipArchive::OVERWRITE)) {
    $files = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($outDir));
    foreach ($files as $file) {
        if ($file->isFile() && $file->getFilename() !== 'app_logos.zip') {
            $zip->addFile($file->getRealPath(), str_replace($outDir, '', $file->getRealPath()));
        }
    }
    $zip->close();
    echo "<a href='app_logos.zip'>下載打包 ZIP</a>";
}
?>

功能擴充建議

  • 支援 圓角遮罩(iOS 圖標需求)。
  • 整合 ImageMagick (Imagick) 獲得更高品質縮放(Lanczos 濾鏡)。
  • 加入 顏色空間轉換(sRGB ↔ P3)。
  • 建立 Web 介面:上傳主圖 → 選擇平台 → 一鍵產生並下載 ZIP。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved