吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 943|回复: 25
上一主题 下一主题
收起左侧

[其他原创] 文字转图标增强帮 - 文字转PNG和 ICO(安全免费)

[复制链接]
跳转到指定楼层
楼主
午夜飘雪 发表于 2025-12-1 16:13 回帖奖励
本帖最后由 午夜飘雪 于 2025-12-2 13:49 编辑

文字转图标增强帮 - 文字转PNG和 ICO(安全免费)
  
看坛友 发图标转换工具  我拿来略作修改 分享给大家
感谢@dada02兄弟分享的代码 感谢感谢
略作修改 增加了几个功能
1.字体选择做了分类, 选择更清晰
2.加载本机字体库(已删除)
3.手动上传字体(临时使用)刷新就没了
4.增加调整字体大小功能,和拉伸功能二选一
5.增加九宫格方位调整
6.调整页面左右分栏, 左侧是功能区  ,右侧是预览区
7.先写这些吧  有想到再改吧

2025年12月2日  更新 新代码跳转21楼
https://www.52pojie.cn/forum.php?mod=redirect&goto=findpost&ptid=2076927&pid=54383907

1. 坛友@gong084  的提议 修改文本框
2.因Windows权限问题 取消加载本地字库
3.调整文字大小与拉伸功能联动,亦可单独拉伸
4.修复@xiaoshan208  提出svg笔画缺失问题 对svg重新校正
5.增加 专门校正SVG文字的垂直偏移±30px
6.添加 文字居中对齐(换行后仍居中)可单独开关
7.目前仍有bug  目前发现①字体选择对svg无效 有空再修
新版本下载 文字转图标v20251202.rar (12.99 KB, 下载次数: 12)






成品在这里
文字转图标增强版.rar (12.72 KB, 下载次数: 166)


下边是代码  需要的拿走,不谢




[HTML] 纯文本查看 复制代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>图标生成器 - 文字转PNG/ICO/SVG</title>
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
        }
        
        body {
            background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
            color: #333;
            min-height: 100vh;
            padding: 10px;
        }
        
        .container {
            max-width: 1200px;
            margin: 0 auto;
            background-color: white;
            border-radius: 15px;
            box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1);
            overflow: hidden;
        }
        
        header {
            background: linear-gradient(90deg, #4b6cb7 0%, #182848 100%);
            color: white;
            padding: 25px 30px;
            text-align: center;
        }
        
        header h1 {
            font-size: 2.2rem;
            margin-bottom: 10px;
        }
        
        header p {
            opacity: 0.9;
            font-size: 1.1rem;
        }
        
        .app-content {
            display: flex;
            flex-wrap: wrap;
            padding: 20px;
            min-height: calc(100vh - 180px);
        }
        
        .controls {
            flex: 1;
            min-width: 300px;
            padding: 20px;
            border-right: 1px solid #eee;
            overflow-y: auto;
            max-height: calc(100vh - 180px);
        }
        
        .preview {
            flex: 1;
            min-width: 300px;
            padding: 20px;
            display: flex;
            flex-direction: column;
            align-items: center;
            justify-content: center;
            gap: 20px;
        }
        
        .control-group {
            margin-bottom: 25px;
            padding: 15px;
            background: #f8f9fa;
            border-radius: 10px;
            box-shadow: 0 2px 5px rgba(0,0,0,0.05);
        }
        
        .control-group h3 {
            margin-bottom: 15px;
            color: #4b6cb7;
            border-bottom: 1px solid #eaeaea;
            padding-bottom: 8px;
        }
        
        .form-group {
            margin-bottom: 15px;
        }
        
        label {
            display: block;
            margin-bottom: 5px;
            font-weight: 500;
        }
        
        input, select, button {
            width: 100%;
            padding: 10px 15px;
            border: 1px solid #ddd;
            border-radius: 5px;
            font-size: 1rem;
        }
        
        button {
            background: linear-gradient(90deg, #4b6cb7 0%, #182848 100%);
            color: white;
            border: none;
            cursor: pointer;
            font-weight: 600;
            transition: all 0.3s ease;
            margin-top: 10px;
        }
        
        button:hover {
            transform: translateY(-2px);
            box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1);
        }
        
        #loadSystemFonts {
            background: linear-gradient(90deg, #27ae60 0%, #219653 100%);
        }
        #loadSystemFonts:hover {
            box-shadow: 0 5px 15px rgba(39, 174, 96, 0.2);
        }
        #uploadFontBtn {
            background: linear-gradient(90deg, #e67e22 0%, #d35400 100%);
        }
        #uploadFontBtn:hover {
            box-shadow: 0 5px 15px rgba(230, 126, 34, 0.2);
        }
        
        .color-input {
            display: flex;
            align-items: center;
        }
        
        .color-input input {
            flex: 1;
        }
        
        .color-preview {
            width: 30px;
            height: 30px;
            border-radius: 5px;
            margin-left: 10px;
            border: 1px solid #ddd;
        }
        
        .shape-options, .size-options {
            display: flex;
            flex-wrap: wrap;
            gap: 10px;
        }
        
        .position-options {
            display: grid;
            grid-template-columns: repeat(3, 1fr);
            gap: 8px;
            width: 100%;
        }
        
        .shape-option, .size-option {
            flex: 1;
            min-width: 80px;
            text-align: center;
            padding: 10px;
            border: 2px solid #ddd;
            border-radius: 5px;
            cursor: pointer;
            transition: all 0.2s;
        }
        
        .position-option {
            padding: 12px 5px;
            font-size: 0.9rem;
            border: 2px solid #ddd;
            border-radius: 5px;
            cursor: pointer;
            transition: all 0.2s;
            text-align: center;
            background: #f8f9fa;
        }
        
        .shape-option:hover, .size-option:hover, .position-option:hover {
            border-color: #4b6cb7;
        }
        
        .shape-option.active, .size-option.active, .position-option.active {
            border-color: #4b6cb7;
            background-color: rgba(75, 108, 183, 0.1);
        }
        
        .checkbox-group {
            display: flex;
            align-items: center;
            margin-bottom: 10px;
        }
        
        .checkbox-group input {
            width: auto;
            margin-right: 10px;
        }
        
        #transparentBgGroup {
            padding: 8px;
            background: rgba(75, 108, 183, 0.05);
            border-radius: 5px;
            margin-top: 5px;
        }
                
        .char-count {
            font-size: 0.8rem;
            color: #666;
            margin-top: 5px;
        }
        
        .max-chars {
            color: #e74c3c;
        }
        
        .stretch-controls, .font-size-controls {
            display: flex;
            gap: 15px;
            margin-top: 10px;
        }
        
        .stretch-control, .font-size-control {
            flex: 1;
            text-align: center;
        }
        
        .stretch-control label, .font-size-control label {
            font-size: 0.9rem;
            margin-bottom: 5px;
        }
        
        .font-size-note {
            font-size: 0.8rem;
            color: #e67e22;
            margin-top: 5px;
            padding: 5px;
            background: rgba(230, 126, 34, 0.05);
            border-radius: 4px;
        }
        
        .stretch-control input, .font-size-control input {
            width: 100%;
        }
        
        .stretch-value, .font-size-value {
            font-size: 0.8rem;
            color: #666;
            margin-top: 5px;
        }
        
        .preview-area {
            width: 256px;
            height: 256px;
            border: 1px solid #ddd;
            border-radius: 10px;
            display: flex;
            align-items: center;
            justify-content: center;
            overflow: hidden;
            background: 
                linear-gradient(45deg, #f0f0f0 25%, transparent 25%), 
                linear-gradient(-45deg, #f0f0f0 25%, transparent 25%), 
                linear-gradient(45deg, transparent 75%, #f0f0f0 75%), 
                linear-gradient(-45deg, transparent 75%, #f0f0f0 75%);
            background-size: 20px 20px;
            background-position: 0 0, 0 10px, 10px -10px, -10px 0px;
            box-shadow: 0 5px 15px rgba(0, 0, 0, 0.05);
            position: relative;
        }
        
        canvas {
            max-width: 100%;
            max-height: 100%;
        }
        
        .download-options {
            display: flex;
            gap: 10px;
            width: 100%;
            max-width: 400px;
        }
        
        .download-options button {
            flex: 1;
        }
        
        .size-preview {
            display: flex;
            flex-wrap: wrap;
            gap: 10px;
            justify-content: center;
            width: 100%;
            max-width: 400px;
        }
        
        .size-preview-item {
            display: flex;
            flex-direction: column;
            align-items: center;
            margin-bottom: 10px;
        }
        
        .size-preview-canvas {
            border: 1px solid #ddd;
            margin-bottom: 5px;
            background: 
                linear-gradient(45deg, #f0f0f0 25%, transparent 25%), 
                linear-gradient(-45deg, #f0f0f0 25%, transparent 25%), 
                linear-gradient(45deg, transparent 75%, #f0f0f0 75%), 
                linear-gradient(-45deg, transparent 75%, #f0f0f0 75%);
            background-size: 8px 8px;
            background-position: 0 0, 0 4px, 4px -4px, -4px 0px;
        }
        
        footer {
            text-align: center;
            padding: 20px;
            color: #666;
            font-size: 0.9rem;
            border-top: 1px solid #eee;
            height: 80px;
        }
        
        .font-loading {
            display: inline-block;
            margin-left: 10px;
            animation: spin 1s linear infinite;
        }
        
        @keyframes spin {
            0% { transform: rotate(0deg); }
            100% { transform: rotate(360deg); }
        }
        
        .font-group {
            margin: 5px 0;
            padding: 8px;
            background: #e9ecef;
            border-radius: 4px;
            font-weight: 600;
            color: #2d3436;
        }
        
        .font-upload-area {
            margin: 15px 0;
            padding: 15px;
            border: 2px dashed #e67e22;
            border-radius: 5px;
            text-align: center;
            transition: all 0.3s;
        }
        .font-upload-area:hover {
            background: rgba(230, 126, 34, 0.05);
        }
        #fontFileInput {
            display: none;
        }
        .upload-hint {
            font-size: 0.85rem;
            color: #666;
            margin-top: 8px;
        }
        .upload-success {
            margin-top: 10px;
            padding: 8px;
            background: rgba(46, 204, 113, 0.1);
            color: #27ae60;
            border-radius: 4px;
            font-size: 0.9rem;
            display: none;
        }

        /* 进度条样式(优化动画) */
        .progress-modal {
            position: fixed;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            background: rgba(0, 0, 0, 0.5);
            display: flex;
            flex-direction: column;
            align-items: center;
            justify-content: center;
            z-index: 1000;
            opacity: 0;
            visibility: hidden;
            transition: all 0.3s ease;
        }
        .progress-modal.active {
            opacity: 1;
            visibility: visible;
        }
        .progress-container {
            background: white;
            padding: 30px;
            border-radius: 10px;
            width: 90%;
            max-width: 500px;
            box-shadow: 0 10px 30px rgba(0, 0, 0, 0.2);
        }
        .progress-title {
            font-size: 1.2rem;
            font-weight: 600;
            color: #333;
            margin-bottom: 15px;
            text-align: center;
        }
        .progress-bar-container {
            width: 100%;
            height: 12px;
            background: #f1f1f1;
            border-radius: 6px;
            overflow: hidden;
            margin-bottom: 15px;
            position: relative;
        }
        .progress-bar {
            height: 100%;
            background: linear-gradient(90deg, #4b6cb7 0%, #182848 100%);
            width: 0%;
            border-radius: 6px;
            position: absolute;
            left: 0;
            top: 0;
            transition: width 2s ease-out; /* 改为2秒平滑动画 */
        }
        .progress-text {
            font-size: 0.9rem;
            color: #666;
            text-align: center;
        }
        .progress-success {
            color: #27ae60;
            font-weight: 600;
            display: none;
        }

        /* 响应式适配 */
        @media (max-width: 768px) {
            .app-content {
                flex-direction: column;
                min-height: auto;
            }
            
            .controls {
                border-right: none;
                border-bottom: 1px solid #eee;
                max-height: none;
            }
            
            .preview {
                min-height: 500px;
                justify-content: flex-start;
                padding-top: 30px;
            }
            
            .stretch-controls, .font-size-controls {
                flex-direction: column;
            }
            
            .download-options {
                flex-direction: column;
                max-width: 100%;
            }
            
            .progress-container {
                padding: 20px;
            }
            
            .position-options {
                grid-template-columns: repeat(3, 1fr);
            }
        }
    </style>
</head>
<body>
    <div class="container">
        <header>
            <h1>图标生成器 - 文字转PNG/ICO/SVG (增强版)</h1>
        </header>
        
        <div class="app-content">
            <div class="controls">
                <div class="control-group">
                    <h3>文字设置</h3>
                    <div class="form-group">
                        <label for="textInput">输入文字或Emoji表情符号(≤6个)</label>
                        <input type="text" id="textInput" value="图" maxlength="6">
                        <div class="char-count">当前字符数: <span id="charCount">1</span>/6</div>
                    </div>
                    
                    <div class="form-group">
                        <label for="fontSelect">选择字体(内置+本机+上传)</label>
                        <select id="fontSelect" size="8" style="height: 200px; overflow-y: auto;">
                            <!-- 字体选项通过JS动态填充 -->
                        </select>
                    </div>
                    
                    <!-- 本机字体加载区域 -->
                    <div class="form-group">
                        <button id="loadSystemFonts">
                            加载本机已安装字体库
                            <span id="systemFontLoading" class="font-loading" style="display: none;">&#10227;</span>
                        </button>
                        <p style="font-size: 0.8rem; color: #666; margin-top: 5px;">
                            &#128204; 支持Chrome/Edge/Opera最新版 | 仅本地读取不上传 | 加载后永久可用
                        </p>
                    </div>
                    
                    <!-- 手动上传字体区域 -->
                    <div class="font-upload-area">
                        <label for="fontFileInput" style="cursor: pointer; font-weight: 600; color: #e67e22;">
                            点击选择本地字体文件(TTF/OTF)
                        </label>
                        <input type="file" id="fontFileInput" accept=".ttf,.otf,.ttc" multiple>
                        <p class="upload-hint">
                            支持格式:TTF/OTF/TTC | 可批量上传 | 仅临时使用(刷新后失效)
                        </p>
                        <div id="uploadSuccessMsg" class="upload-success">
                            &#9989; 字体上传成功!已添加到字体列表末尾
                        </div>
                    </div>
                    
                    <div class="stretch-controls">
                        <div class="stretch-control">
                            <label for="colorInput">文字颜色(点击选择)</label>
                            <div class="color-input">
                                <input type="color" id="colorInput" value="#ea1026">
                                <div class="color-preview" id="colorPreview"></div>
                            </div>
                        </div>
                        
                        <div class="stretch-control">
                            <label for="bgColorInput">背景颜色</label>
                            <div class="color-input">
                                <input type="color" id="bgColorInput" value="#ffffff">
                                <div class="color-preview" id="bgColorPreview"></div>
                            </div>
                        </div>
                    </div>
                                        
                                        <!-- 透明背景选项 -->
                    <div class="checkbox-group" id="transparentBgGroup">
                        <input type="checkbox" id="transparentBg" checked>
                        <label for="transparentBg">启用透明背景(取消则显示上方背景色)</label>
                    </div>
                    
                    <div class="checkbox-group">
                        <input type="checkbox" id="autoWrap" checked>
                        <label for="autoWrap">自动换行显示多个文字</label>
                    </div>
                    
                    <div class="checkbox-group">
                        <input type="checkbox" id="autoStretch" checked>
                        <label for="autoStretch">自动拉伸文字以适应图标</label>
                    </div>
                    
                    <!-- 新增:字体大小调整 -->
                    <div class="font-size-controls">
                        <div class="font-size-control">
                            <label for="fontSizeSlider">字体大小</label>
                            <input type="range" id="fontSizeSlider" min="10" max="200" value="80">
                            <div class="font-size-value" id="fontSizeValue">80%</div>
                            <div class="font-size-note">&#128161; 提示:需先关闭"自动拉伸"才能手动调整字体大小</div>
                        </div>
                    </div>
                    
                    <div class="stretch-controls">
                        <div class="stretch-control">
                            <label for="horizontalStretch">水平拉伸</label>
                            <input type="range" id="horizontalStretch" min="50" max="500" value="141">
                            <div class="stretch-value" id="horizontalValue">141%</div>
                        </div>
                        
                        <div class="stretch-control">
                            <label for="verticalStretch">垂直拉伸</label>
                            <input type="range" id="verticalStretch" min="50" max="500" value="126">
                            <div class="stretch-value" id="verticalValue">126%</div>
                        </div>
                    </div>
                    
                    <div class="stretch-controls">
                        <div class="stretch-control">
                            <label for="horizontalOffset">横向偏移</label>
                            <input type="range" id="horizontalOffset" min="-50" max="50" value="-5">
                            <div class="stretch-value" id="horizontalOffsetValue">-5px</div>
                        </div>
                        
                        <div class="stretch-control">
                            <label for="verticalOffset">垂直偏移</label>
                            <input type="range" id="verticalOffset" min="-50" max="50" value="2">
                            <div class="stretch-value" id="verticalOffsetValue">2px</div>
                        </div>
                    </div>
                    
                    <!-- 新增:9方位位置选择 -->
                    <div class="form-group" style="margin-top: 20px;">
                        <label>文字位置(九宫格)</label>
                        <div class="position-options">
                            <div class="position-option" data-position="top-left">左上</div>
                            <div class="position-option" data-position="top-center">中上</div>
                            <div class="position-option" data-position="top-right">右上</div>
                            <div class="position-option" data-position="center-left">左中</div>
                            <div class="position-option active" data-position="center-center">居中</div>
                            <div class="position-option" data-position="center-right">右中</div>
                            <div class="position-option" data-position="bottom-left">左下</div>
                            <div class="position-option" data-position="bottom-center">中下</div>
                            <div class="position-option" data-position="bottom-right">右下</div>
                        </div>
                    </div>
                
                    <h3>图标形状</h3>
                    <div class="shape-options">
                        <div class="shape-option" data-shape="square">方形</div>
                        <div class="shape-option" data-shape="circle">圆形</div>
                        <div class="shape-option active" data-shape="rounded">圆角方形</div>
                    </div>
                </div>
                
                <button id="generateBtn" style="display:none;">生成图标</button>
            </div>
            
            <div class="preview">
                <div class="preview-area">
                    <canvas id="previewCanvas" width="256" height="256"></canvas>
                </div>
                <div class="control-group">
                    <h3>图标尺寸</h3>
                    <div class="size-options">
                        <div class="size-option" data-size="16">16×16</div>
                        <div class="size-option" data-size="32">32×32</div>
                        <div class="size-option" data-size="48">48×48</div>
                        <div class="size-option" data-size="64">64×64</div>
                        <div class="size-option" data-size="128">128×128</div>
                        <div class="size-option active" data-size="256">256×256</div>
                    </div>
                </div>
                
                <div class="download-options">
                    <button id="downloadPngBtn">下载PNG</button>
                    <button id="downloadIcoBtn">下载ICO</button>
                    <button id="downloadSvgBtn">下载SVG</button>
                </div>
                
                <div class="size-preview">
                    <!-- 尺寸预览区域通过JS动态生成 -->
                </div>
            </div>
        </div>
        
        <footer>
            <p>图标生成器 &#169; 2025 - 支持PNG、ICO和SVG格式输出 | 增强版:进度条+字体大小+9方位调整</p>
        </footer>
    </div>

    <!-- 下载进度条弹窗 -->
    <div class="progress-modal" id="downloadProgressModal">
        <div class="progress-container">
            <div class="progress-title" id="progressTitle">正在准备下载...</div>
            <div class="progress-bar-container">
                <div class="progress-bar" id="progressBar"></div>
            </div>
            <div class="progress-text">
                <span id="progressPercent">0%</span> | 
                <span id="progressStep">初始化...</span>
                <span id="progressSuccess" class="progress-success">下载准备完成!</span>
            </div>
        </div>
    </div>

    <script>
        document.addEventListener('DOMContentLoaded', function() {
            // 获取DOM元素
            const textInput = document.getElementById('textInput');
            const charCount = document.getElementById('charCount');
            const autoWrap = document.getElementById('autoWrap');
            const fontSelect = document.getElementById('fontSelect');
            const loadSystemFontsBtn = document.getElementById('loadSystemFonts');
            const systemFontLoading = document.getElementById('systemFontLoading');
            const fontFileInput = document.getElementById('fontFileInput');
            const uploadSuccessMsg = document.getElementById('uploadSuccessMsg');
            const colorInput = document.getElementById('colorInput');
            const colorPreview = document.getElementById('colorPreview');
            const bgColorInput = document.getElementById('bgColorInput');
            const bgColorPreview = document.getElementById('bgColorPreview');
            const transparentBg = document.getElementById('transparentBg');
            const autoStretch = document.getElementById('autoStretch');
            const fontSizeSlider = document.getElementById('fontSizeSlider'); // 新增
            const fontSizeValue = document.getElementById('fontSizeValue'); // 新增
            const horizontalStretch = document.getElementById('horizontalStretch');
            const verticalStretch = document.getElementById('verticalStretch');
            const horizontalOffset = document.getElementById('horizontalOffset');
            const verticalOffset = document.getElementById('verticalOffset');
            const horizontalValue = document.getElementById('horizontalValue');
            const verticalValue = document.getElementById('verticalValue');
            const horizontalOffsetValue = document.getElementById('horizontalOffsetValue');
            const verticalOffsetValue = document.getElementById('verticalOffsetValue');
            const shapeOptions = document.querySelectorAll('.shape-option');
            const sizeOptions = document.querySelectorAll('.size-option');
            const positionOptions = document.querySelectorAll('.position-option'); // 新增
            const generateBtn = document.getElementById('generateBtn');
            const downloadPngBtn = document.getElementById('downloadPngBtn');
            const downloadIcoBtn = document.getElementById('downloadIcoBtn');
            const downloadSvgBtn = document.getElementById('downloadSvgBtn');
            const previewCanvas = document.getElementById('previewCanvas');
            const sizePreview = document.querySelector('.size-preview');
            // 进度条相关元素
            const progressModal = document.getElementById('downloadProgressModal');
            const progressTitle = document.getElementById('progressTitle');
            const progressBar = document.getElementById('progressBar');
            const progressPercent = document.getElementById('progressPercent');
            const progressStep = document.getElementById('progressStep');
            const progressSuccess = document.getElementById('progressSuccess');
            
            // 初始化变量
            let selectedShape = 'rounded';
            let selectedSize = 256;
            let selectedPosition = 'center-center'; // 新增
            let ctx = previewCanvas.getContext('2d');
            let systemFontsLoaded = false;
            let uploadedFonts = new Map();
            let fontCounter = 1;
            let progressInterval = null;
            let progressPercentInterval = null;
            let downloadTimeout = null; // 新增:控制下载延迟
            
            // 内置字体库(分类整理)
            const builtInFonts = [
                { group: '常用中文字体', fonts: [
                    { family: 'Microsoft YaHei', name: '微软雅黑' },
                    { family: '微软雅黑 Light', name: '微软雅黑 Light' },
                    { family: 'SimSun', name: '宋体' },
                    { family: '新宋体', name: '新宋体' },
                    { family: 'FangSong', name: '仿宋' },
                    { family: 'KaiTi', name: '楷体' },
                    { family: 'LiSu', name: '隶书' },
                    { family: 'YouYuan', name: '幼圆' },
                    { family: '黑体', name: '黑体' },
                    { family: '等线', name: '等线' },
                    { family: '等线 Light', name: '等线 Light' }
                ]},
                { group: '思源字体', fonts: [
                    { family: "'Noto Sans SC', sans-serif", name: '思源黑体 (Noto Sans SC)' },
                    { family: "'Noto Serif SC', serif", name: '思源宋体 (Noto Serif SC)' }
                ]},
                { group: '华文系列', fonts: [
                    { family: '华文中宋', name: '华文中宋' },
                    { family: '华文仿宋', name: '华文仿宋' },
                    { family: '华文宋体', name: '华文宋体' },
                    { family: '华文彩云', name: '华文彩云' },
                    { family: '华文新魏', name: '华文新魏' },
                    { family: '华文楷体', name: '华文楷体' },
                    { family: '华文琥珀', name: '华文琥珀' },
                    { family: '华文细黑', name: '华文细黑' },
                    { family: '华文行楷', name: '华文行楷' },
                    { family: '华文隶书', name: '华文隶书' }
                ]},
                { group: '方正系列', fonts: [
                    { family: '方正姚体', name: '方正姚体' },
                    { family: '方正舒体', name: '方正舒体' }
                ]},
                { group: '英文字体', fonts: [
                    { family: 'Arial', name: 'Arial' },
                    { family: 'Verdana', name: 'Verdana' },
                    { family: 'Helvetica', name: 'Helvetica' },
                    { family: 'Georgia', name: 'Georgia' },
                    { family: 'Times New Roman', name: 'Times New Roman' },
                    { family: 'Courier New', name: 'Courier New' },
                    { family: 'Impact', name: 'Impact' },
                    { family: 'Comic Sans MS', name: 'Comic Sans MS' }
                ]}
            ];
            
            // 初始化字体选择框
            function initFontSelect() {
                fontSelect.innerHTML = '';
                
                // 添加内置字体(分组显示)
                builtInFonts.forEach(group => {
                    const groupOption = document.createElement('option');
                    groupOption.disabled = true;
                    groupOption.innerHTML = `&#128193; ${group.group}`;
                    groupOption.className = 'font-group';
                    fontSelect.appendChild(groupOption);
                    
                    group.fonts.forEach(font => {
                        const option = document.createElement('option');
                        option.value = font.family;
                        option.textContent = `  ${font.name}`;
                        if (font.family === 'SimSun') {
                            option.selected = true;
                        }
                        fontSelect.appendChild(option);
                    });
                });
                
                // 添加分隔线(本机字体区域)
                const systemDivider = document.createElement('option');
                systemDivider.disabled = true;
                systemDivider.textContent = '────────── 本机已安装字体(点击上方按钮加载) ──────────';
                fontSelect.appendChild(systemDivider);
                
                // 添加分隔线(上传字体区域)
                const uploadDivider = document.createElement('option');
                uploadDivider.disabled = true;
                uploadDivider.textContent = '────────── 本地上传字体(临时使用) ──────────';
                fontSelect.appendChild(uploadDivider);
            }
            
            // 初始化字体选择框
            initFontSelect();
            
            // 进度条初始化(优化动画)
            function initProgressBar(format, fileName) {
                // 清除之前的定时器
                if (progressInterval) clearInterval(progressInterval);
                if (progressPercentInterval) clearInterval(progressPercentInterval);
                if (downloadTimeout) clearTimeout(downloadTimeout);
                
                // 重置进度条状态
                progressModal.classList.add('active');
                progressTitle.textContent = `正在准备下载 ${format} 文件:${fileName}`;
                progressBar.style.width = '0%';
                progressPercent.textContent = '0%';
                progressSuccess.style.display = 'none';
                progressStep.textContent = '初始化...';
                
                // 进度步骤提示
                const steps = [
                    '初始化下载参数...',
                    '正在渲染图标内容...',
                    '正在优化图像质量...',
                    '正在处理文件数据...',
                    '正在生成下载链接...',
                    '最后检查文件完整性...'
                ];
                
                // 分步更新进度条
                let stepIndex = 0;
                let currentProgress = 0;
                
                // 每300ms更新一次进度
                progressInterval = setInterval(() => {
                    currentProgress += 2; // 每次增加2%
                    if (currentProgress > 100) currentProgress = 100;
                    
                    progressBar.style.width = `${currentProgress}%`;
                    progressPercent.textContent = `${currentProgress}%`;
                    
                    // 更新步骤提示
                    const stepPosition = Math.floor(currentProgress / (100 / steps.length));
                    if (stepPosition < steps.length) {
                        progressStep.textContent = steps[stepPosition];
                    } else {
                        progressStep.textContent = '准备完成...';
                    }
                    
                    // 进度完成后停止
                    if (currentProgress >= 100) {
                        clearInterval(progressInterval);
                        progressInterval = null;
                    }
                }, 30);
            }
            
            // 关闭进度条弹窗(增加延迟)
            function closeProgressBar() {
                progressStep.textContent = '文件生成完成!';
                progressSuccess.style.display = 'inline-block';
                
                // 保持进度条显示2秒后关闭
                setTimeout(() => {
                    progressModal.classList.remove('active');
                    
                    // 重置进度条状态
                    setTimeout(() => {
                        progressSuccess.style.display = 'none';
                        progressBar.style.width = '0%';
                        progressPercent.textContent = '0%';
                    }, 300);
                }, 800); // 显示完成状态800ms
            }
            
            // 错误状态进度条
            function errorProgressBar(format, errorMsg) {
                if (progressInterval) clearInterval(progressInterval);
                if (progressPercentInterval) clearInterval(progressPercentInterval);
                
                progressModal.classList.add('active');
                progressTitle.textContent = `下载 ${format} 文件失败`;
                progressBar.style.width = '0%';
                progressPercent.textContent = '0%';
                progressStep.textContent = `&#10060; ${errorMsg}`;
                progressStep.style.color = '#e74c3c';
                progressSuccess.style.display = 'none';
                
                setTimeout(() => {
                    progressModal.classList.remove('active');
                    setTimeout(() => {
                        progressStep.style.color = '';
                    }, 300);
                }, 3000);
            }
            
            // 获取自定义下载文件名
            function getCustomFileName(format) {
                let content = textInput.value.trim() || '图标';
                const invalidChars = /[\\/:*?"<>|]/g;
                content = content.replace(invalidChars, '-');
                if (content.length > 10) {
                    content = content.substring(0, 10) + '...';
                }
                return `${content}-${selectedSize}.${format}`;
            }
            
            // 下载PNG(优化进度条显示)
            downloadPngBtn.addEventListener('click', async function() {
                try {
                    const format = 'png';
                    const fileName = getCustomFileName(format);
                    initProgressBar('PNG', fileName);
                    
                    // 生成文件
                    const canvas = createCanvas(selectedSize);
                    drawIcon(canvas, selectedSize);
                    
                    const link = document.createElement('a');
                    link.download = fileName;
                    link.href = canvas.toDataURL(`image/${format}`);
                    
                    // 等待进度条动画完成后触发下载
                    setTimeout(() => {
                        link.click();
                        closeProgressBar();
                    }, 1200); // 等待1.2秒让进度条动画完成
                    
                } catch (error) {
                    console.error('PNG下载失败:', error);
                    errorProgressBar('PNG', '文件生成失败,请重试');
                }
            });
            
            // 下载ICO(优化进度条显示)
            downloadIcoBtn.addEventListener('click', async function() {
                try {
                    const format = 'ico';
                    const downloadSize = parseInt(selectedSize);
                    const fileName = getCustomFileName(format);
                    initProgressBar('ICO', fileName);
                    
                    // 生成文件
                    const canvas = document.createElement('canvas');
                    canvas.width = downloadSize;
                    canvas.height = downloadSize;
                    const ctx = canvas.getContext('2d');
                    ctx.clearRect(0, 0, downloadSize, downloadSize);
                    drawIcon(canvas, downloadSize);
                    
                    const pngData = canvas.toDataURL('image/png').split(',')[1];
                    const pngBuffer = Uint8Array.from(atob(pngData), c => c.charCodeAt(0));
                    
                    const icoHeader = new Uint8Array([0, 0, 1, 0, 1, 0]);
                    const icoDir = new Uint8Array(16);
                    icoDir[0] = downloadSize > 255 ? 0 : downloadSize;
                    icoDir[1] = downloadSize > 255 ? 0 : downloadSize;
                    icoDir[2] = 0;
                    icoDir[3] = 0;
                    icoDir[4] = 1; icoDir[5] = 0;
                    icoDir[6] = 32; icoDir[7] = 0;
                    const size = pngBuffer.length;
                    icoDir[8] = size & 0xFF;
                    icoDir[9] = (size >> 8) & 0xFF;
                    icoDir[10] = (size >> 16) & 0xFF;
                    icoDir[11] = (size >> 24) & 0xFF;
                    const offset = icoHeader.length + icoDir.length;
                    icoDir[12] = offset & 0xFF;
                    icoDir[13] = (offset >> 8) & 0xFF;
                    icoDir[14] = (offset >> 16) & 0xFF;
                    icoDir[15] = (offset >> 24) & 0xFF;
                    
                    const icoData = new Uint8Array(icoHeader.length + icoDir.length + pngBuffer.length);
                    icoData.set(icoHeader);
                    icoData.set(icoDir, icoHeader.length);
                    icoData.set(pngBuffer, icoHeader.length + icoDir.length);
                    
                    const blob = new Blob([icoData], { type: 'image/x-icon' });
                    const link = document.createElement('a');
                    link.href = URL.createObjectURL(blob);
                    link.download = fileName;
                    link.style.display = 'none';
                    document.body.appendChild(link);
                    
                    // 等待进度条动画完成后触发下载
                    setTimeout(() => {
                        link.click();
                        setTimeout(() => {
                            document.body.removeChild(link);
                            URL.revokeObjectURL(link.href);
                            closeProgressBar();
                        }, 100);
                    }, 1200); // 等待1.2秒
                    
                } catch (error) {
                    console.error('ICO下载失败:', error);
                    errorProgressBar('ICO', '文件生成失败,请重试');
                }
            });
            
            // 下载SVG(优化进度条显示)
            downloadSvgBtn.addEventListener('click', async function() {
                try {
                    const format = 'svg';
                    const fileName = getCustomFileName(format);
                    initProgressBar('SVG', fileName);
                    
                    // 生成文件
                    const svgString = generateSvgString(selectedSize);
                    const blob = new Blob([svgString], { type: 'image/svg+xml' });
                    const url = URL.createObjectURL(blob);
                    const link = document.createElement('a');
                    link.href = url;
                    link.download = fileName;
                    
                    // 等待进度条动画完成后触发下载
                    setTimeout(() => {
                        link.click();
                        URL.revokeObjectURL(url);
                        closeProgressBar();
                    }, 1200); // 等待1.2秒
                    
                } catch (error) {
                    console.error('SVG下载失败:', error);
                    errorProgressBar('SVG', '文件生成失败,请重试');
                }
            });
            
            // 字体上传功能
            fontFileInput.addEventListener('change', async function(e) {
                const files = e.target.files;
                if (!files || files.length === 0) return;
                
                let successCount = 0;
                const validExtensions = ['ttf', 'otf', 'ttc'];
                
                for (const file of files) {
                    const fileName = file.name;
                    const fileExt = fileName.split('.').pop().toLowerCase();
                    
                    if (!validExtensions.includes(fileExt)) {
                        alert(`&#10060; 文件 "${fileName}" 格式不支持\n仅支持TTF/OTF/TTC格式`);
                        continue;
                    }
                    
                    try {
                        const fontUniqueName = `UploadedFont_${fontCounter++}_${fileName.replace(/\.[^/.]+$/, "")}`;
                        const fontUrl = URL.createObjectURL(file);
                        const fontFace = new FontFace(fontUniqueName, `url(${fontUrl})`);
                        
                        await fontFace.load();
                        document.fonts.add(fontFace);
                        uploadedFonts.set(fontUniqueName, {
                            face: fontFace,
                            url: fontUrl,
                            fileName: fileName
                        });
                        
                        const option = document.createElement('option');
                        option.value = fontUniqueName;
                        option.textContent = `  &#128228; ${fileName}`;
                        const uploadDivider = Array.from(fontSelect.options).find(
                            opt => opt.textContent.includes('本地上传字体')
                        );
                        if (uploadDivider) {
                            fontSelect.insertBefore(option, uploadDivider.nextSibling);
                        } else {
                            fontSelect.appendChild(option);
                        }
                        
                        successCount++;
                    } catch (error) {
                        console.error(`加载字体 ${fileName} 失败:`, error);
                        alert(`&#10060; 加载字体 "${fileName}" 失败\n可能是损坏的字体文件或浏览器不支持`);
                    }
                }
                
                if (successCount > 0) {
                    uploadSuccessMsg.textContent = `&#9989; 成功上传 ${successCount} 个字体!已添加到字体列表`;
                    uploadSuccessMsg.style.display = 'block';
                    setTimeout(() => {
                        uploadSuccessMsg.style.display = 'none';
                    }, 3000);
                }
                
                fontFileInput.value = '';
                generateIcon();
            });
            
            // 本机字体加载功能
            loadSystemFontsBtn.addEventListener('click', async function() {
                if (systemFontsLoaded) {
                    alert('&#9989; 本机字体已加载完成!可直接在字体列表中选择使用');
                    return;
                }
                
                try {
                    systemFontLoading.style.display = 'inline-block';
                    loadSystemFontsBtn.disabled = true;
                    
                    if (!('queryLocalFonts' in window)) {
                        alert('&#10060; 您的浏览器不支持加载本机字体功能\n\n推荐使用:\n&#8226; Chrome 103+ 浏览器\n&#8226; Edge 103+ 浏览器\n&#8226; Opera 89+ 浏览器\n\n请升级浏览器后重试');
                        return;
                    }
                    
                    try {
                        const permission = await navigator.permissions.query({ name: 'local-fonts' });
                        if (permission.state !== 'granted') {
                            alert('&#128274; 需要您授予字体访问权限\n\n请在浏览器弹出的权限请求中选择"允许",以便读取本机字体库');
                            return;
                        }
                    } catch (permErr) {
                        console.log('权限查询不支持,直接尝试获取字体');
                    }
                    
                    console.log('正在读取本机字体库...');
                    const fonts = await window.queryLocalFonts();
                    
                    const uniqueFonts = Array.from(new Map(
                        fonts.map(font => [font.family.toLowerCase(), font])
                    )).map(([_, font]) => font)
                      .sort((a, b) => (a.fullName || a.family).localeCompare(b.fullName || b.family));
                    
                    const systemFontGroups = {
                        '中文字体': [],
                        '英文字体': [],
                        '其他字体': []
                    };
                    const chineseRegex = /[\u4e00-\u9fa5]/;
                    
                    uniqueFonts.forEach(font => {
                        const fontName = font.fullName || font.family;
                        const fontFamily = font.family;
                        
                        if (chineseRegex.test(fontName) || chineseRegex.test(fontFamily)) {
                            systemFontGroups['中文字体'].push({ family: fontFamily, name: fontName });
                        } else if (/^[a-zA-Z\s]+$/.test(fontName)) {
                            systemFontGroups['英文字体'].push({ family: fontFamily, name: fontName });
                        } else {
                            systemFontGroups['其他字体'].push({ family: fontFamily, name: fontName });
                        }
                    });
                    
                    const systemDivider = Array.from(fontSelect.options).find(
                        opt => opt.textContent.includes('本机已安装字体')
                    );
                    if (systemDivider) {
                        Object.entries(systemFontGroups).forEach(([groupName, fonts]) => {
                            if (fonts.length === 0) return;
                            
                            const groupOption = document.createElement('option');
                            groupOption.disabled = true;
                            groupOption.innerHTML = `&#128421;&#65039; 本机${groupName}`;
                            groupOption.className = 'font-group';
                            fontSelect.insertBefore(groupOption, systemDivider.nextSibling);
                            
                            fonts.forEach(font => {
                                const option = document.createElement('option');
                                option.value = font.family;
                                option.textContent = `  ${font.name}`;
                                fontSelect.insertBefore(option, systemDivider.nextSibling);
                            });
                        });
                    }
                    
                    systemFontsLoaded = true;
                    alert(`&#9989; 成功加载 ${uniqueFonts.length} 个本机字体!\n已添加到字体列表中`);
                    
                } catch (error) {
                    console.error('加载本机字体失败:', error);
                    alert(`&#10060; 加载本机字体失败:${error.message}\n\n可能原因:\n1. 浏览器权限未授予\n2. 浏览器版本过低\n3. 系统字体库访问受限`);
                } finally {
                    systemFontLoading.style.display = 'none';
                    loadSystemFontsBtn.disabled = false;
                }
            });
            
            // 透明背景切换
            transparentBg.addEventListener('change', function() {
                if (this.checked) {
                    bgColorInput.disabled = true;
                    bgColorPreview.style.backgroundColor = 'transparent';
                    bgColorPreview.style.border = '1px dashed #ddd';
                } else {
                    bgColorInput.disabled = false;
                    bgColorPreview.style.backgroundColor = bgColorInput.value;
                    bgColorPreview.style.border = '1px solid #ddd';
                }
                generateIcon();
            });
            
            // 初始化背景色预览
            bgColorPreview.style.backgroundColor = 'transparent';
            bgColorPreview.style.border = '1px dashed #ddd';
            bgColorInput.disabled = true;
            
            // 字符计数
            textInput.addEventListener('input', function() {
                const count = this.value.length;
                charCount.textContent = count;
                if (count > 6) {
                    charCount.classList.add('max-chars');
                } else {
                    charCount.classList.remove('max-chars');
                }
                generateIcon();
            });
            
            // 自动换行切换
            autoWrap.addEventListener('change', generateIcon);
            
            // 颜色预览更新
            colorInput.addEventListener('input', function() {
                colorPreview.style.backgroundColor = colorInput.value;
                generateIcon();
            });
            
            bgColorInput.addEventListener('input', function() {
                if (!transparentBg.checked) {
                    bgColorPreview.style.backgroundColor = this.value;
                    generateIcon();
                }
            });
            
            // 新增:自动拉伸切换时禁用/启用字体大小滑块
            autoStretch.addEventListener('change', function() {
                fontSizeSlider.disabled = this.checked;
                if (this.checked) {
                    document.querySelector('.font-size-note').style.opacity = '0.7';
                } else {
                    document.querySelector('.font-size-note').style.opacity = '1';
                }
                generateIcon();
            });
            
            // 初始化字体大小滑块状态
            fontSizeSlider.disabled = autoStretch.checked;
            if (autoStretch.checked) {
                document.querySelector('.font-size-note').style.opacity = '0.7';
            }
            
            // 新增:字体大小滑块更新
            fontSizeSlider.addEventListener('input', function() {
                fontSizeValue.textContent = `${this.value}%`;
                generateIcon();
            });
            
            // 拉伸滑块更新
            horizontalStretch.addEventListener('input', function() {
                horizontalValue.textContent = `${this.value}%`;
                generateIcon();
            });
            
            verticalStretch.addEventListener('input', function() {
                verticalValue.textContent = `${this.value}%`;
                generateIcon();
            });
            
            // 偏移滑块更新
            horizontalOffset.addEventListener('input', function() {
                horizontalOffsetValue.textContent = `${this.value}px`;
                generateIcon();
            });
            
            verticalOffset.addEventListener('input', function() {
                verticalOffsetValue.textContent = `${this.value}px`;
                generateIcon();
            });
            
            // 形状选择
            shapeOptions.forEach(option => {
                option.addEventListener('click', function() {
                    shapeOptions.forEach(opt => opt.classList.remove('active'));
                    this.classList.add('active');
                    selectedShape = this.dataset.shape;
                    generateIcon();
                });
            });
            
            // 尺寸选择
            sizeOptions.forEach(option => {
                option.addEventListener('click', function() {
                    sizeOptions.forEach(opt => opt.classList.remove('active'));
                    this.classList.add('active');
                    selectedSize = parseInt(this.dataset.size);
                    generateIcon();
                });
            });
            
            // 新增:位置选择
            positionOptions.forEach(option => {
                option.addEventListener('click', function() {
                    positionOptions.forEach(opt => opt.classList.remove('active'));
                    this.classList.add('active');
                    selectedPosition = this.dataset.position;
                    generateIcon();
                });
            });
            
            // 生成图标按钮
            generateBtn.addEventListener('click', generateIcon);
            
            // 创建Canvas元素
            function createCanvas(size) {
                const canvas = document.createElement('canvas');
                canvas.width = size;
                canvas.height = size;
                return canvas;
            }
            
            // 修复:获取位置偏移(上下颠倒问题)
            function getPositionOffset(size) {
                const offsets = {
                    'top-left': { x: size * 0.25, y: size * 0.25 },
                    'top-center': { x: size * 0.5, y: size * 0.25 },
                    'top-right': { x: size * 0.75, y: size * 0.25 },
                    'center-left': { x: size * 0.25, y: size * 0.5 },
                    'center-center': { x: size * 0.5, y: size * 0.5 },
                    'center-right': { x: size * 0.75, y: size * 0.5 },
                    'bottom-left': { x: size * 0.25, y: size * 0.75 },
                    'bottom-center': { x: size * 0.5, y: size * 0.75 },
                    'bottom-right': { x: size * 0.75, y: size * 0.75 }
                };
                return offsets[selectedPosition] || offsets['center-center'];
            }
            
            // 绘制图标(增强版)
            function drawIcon(canvas, size) {
                const ctx = canvas.getContext('2d');
                const text = textInput.value || '图标';
                const wrapEnabled = autoWrap.checked;
                let selectedFont = fontSelect.value;
                
                ctx.clearRect(0, 0, size, size);
                
                // 绘制背景
                if (!transparentBg.checked) {
                    ctx.fillStyle = bgColorInput.value;
                    
                    switch(selectedShape) {
                        case 'square':
                            ctx.fillRect(0, 0, size, size);
                            break;
                        case 'circle':
                            ctx.beginPath();
                            ctx.arc(size/2, size/2, size/2, 0, Math.PI * 2);
                            ctx.fill();
                            break;
                        case 'rounded':
                            const radius = size * 0.1;
                            ctx.beginPath();
                            ctx.moveTo(radius, 0);
                            ctx.lineTo(size - radius, 0);
                            ctx.quadraticCurveTo(size, 0, size, radius);
                            ctx.lineTo(size, size - radius);
                            ctx.quadraticCurveTo(size, size, size - radius, size);
                            ctx.lineTo(radius, size);
                            ctx.quadraticCurveTo(0, size, 0, size - radius);
                            ctx.lineTo(0, radius);
                            ctx.quadraticCurveTo(0, 0, radius, 0);
                            ctx.closePath();
                            ctx.fill();
                            break;
                    }
                }
                
                // 设置裁剪区域
                ctx.save();
                switch(selectedShape) {
                    case 'circle':
                        ctx.beginPath();
                        ctx.arc(size/2, size/2, size/2, 0, Math.PI * 2);
                        ctx.clip();
                        break;
                    case 'rounded':
                        const radius = size * 0.1;
                        ctx.beginPath();
                        ctx.moveTo(radius, 0);
                        ctx.lineTo(size - radius, 0);
                        ctx.quadraticCurveTo(size, 0, size, radius);
                        ctx.lineTo(size, size - radius);
                        ctx.quadraticCurveTo(size, size, size - radius, size);
                        ctx.lineTo(radius, size);
                        ctx.quadraticCurveTo(0, size, 0, size - radius);
                        ctx.lineTo(0, radius);
                        ctx.quadraticCurveTo(0, 0, radius, 0);
                        ctx.closePath();
                        ctx.clip();
                        break;
                }
                
                // 绘制文字
                ctx.fillStyle = colorInput.value;
                
                // 计算字体大小
                let fontSize;
                if (autoStretch.checked) {
                    fontSize = calculateOptimalFontSize(ctx, text, size, selectedShape, wrapEnabled, selectedFont);
                } else {
                    // 使用手动设置的字体大小
                    fontSize = (size * parseInt(fontSizeSlider.value) / 100) * 0.8;
                }
                
                // 处理字体名称
                let fontFamily = selectedFont;
                if (!uploadedFonts.has(selectedFont) && fontFamily.includes(' ') && !fontFamily.startsWith("'") && !fontFamily.startsWith('"')) {
                    fontFamily = `'${fontFamily}'`;
                }
                
                ctx.font = `bold ${fontSize}px ${fontFamily}`;
                
                // 获取位置偏移
                const position = getPositionOffset(size);
                
                // 应用拉伸和偏移
                const hStretch = parseInt(horizontalStretch.value) / 100;
                const vStretch = parseInt(verticalStretch.value) / 100;
                const hOffset = parseInt(horizontalOffset.value);
                const vOffset = parseInt(verticalOffset.value);
                
                ctx.translate(position.x, position.y);
                ctx.scale(hStretch, vStretch);
                const offsetX = hOffset * (size / 256);
                const offsetY = vOffset * (size / 256);
                
                // 设置文字对齐方式
                const posParts = selectedPosition.split('-');
                const hAlign = posParts[1] === 'left' ? 'left' : posParts[1] === 'right' ? 'right' : 'center';
                const vAlign = posParts[0] === 'top' ? 'alphabetic' : posParts[0] === 'bottom' ? 'bottom' : 'middle';
                
                ctx.textAlign = hAlign;
                ctx.textBaseline = vAlign;
                
                // 绘制文字
                if (wrapEnabled && text.length > 1) {
                    drawWrappedText(ctx, text, offsetX, offsetY, fontSize, size, fontFamily, hAlign, vAlign);
                } else {
                    ctx.fillText(text, offsetX, offsetY);
                }
                
                ctx.restore();
            }
            
            // 修复:绘制换行文字(上下颠倒问题)
            function drawWrappedText(ctx, text, offsetX, offsetY, fontSize, size, fontFamily, hAlign, vAlign) {
                const lines = [];
                const charsPerLine = text.length <= 2 ? 1 : 2;
                
                for (let i = 0; i < text.length; i += charsPerLine) {
                    lines.push(text.substring(i, i + charsPerLine));
                }
                
                const lineHeight = fontSize * 1.2;
                const totalHeight = lines.length * lineHeight;
                
                // 根据垂直对齐方式调整起始位置(修复上下颠倒)
                let startY = offsetY;
                if (vAlign === 'middle') {
                    startY -= (totalHeight - lineHeight) / 2;
                } else if (vAlign === 'bottom') {
                    startY -= totalHeight - lineHeight;
                } else if (vAlign === 'alphabetic') {
                    startY += lineHeight * 0.2; // 顶部对齐时微调
                }
                
                ctx.font = `bold ${fontSize}px ${fontFamily}`;
                ctx.textAlign = hAlign;
                ctx.textBaseline = vAlign;
                
                lines.forEach((line, index) => {
                    ctx.fillText(line, offsetX, startY + index * lineHeight);
                });
            }
            
            // 计算最佳字体大小
            function calculateOptimalFontSize(ctx, text, size, shape, wrapEnabled, selectedFont) {
                let availableWidth, availableHeight;
                switch(shape) {
                    case 'square':
                    case 'rounded':
                        availableWidth = size * 0.9;
                        availableHeight = size * 0.9;
                        break;
                    case 'circle':
                        availableWidth = size * 0.8;
                        availableHeight = size * 0.8;
                        break;
                }
                
                if (wrapEnabled && text.length > 1) {
                    const lines = Math.ceil(text.length / (text.length <= 2 ? 1 : 2));
                    availableHeight = availableHeight / lines * 0.8;
                }
                
                let fontSize = Math.min(availableWidth, availableHeight);
                let minFont = 1;
                let maxFont = fontSize * 2;
                
                let fontFamily = selectedFont;
                if (!uploadedFonts.has(selectedFont) && fontFamily.includes(' ') && !fontFamily.startsWith("'") && !fontFamily.startsWith('"')) {
                    fontFamily = `'${fontFamily}'`;
                }
                
                for (let i = 0; i < 10; i++) {
                    ctx.font = `bold ${fontSize}px ${fontFamily}`;
                    
                    let textWidth;
                    if (wrapEnabled && text.length > 1) {
                        const charsPerLine = text.length <= 2 ? 1 : 2;
                        let maxLineWidth = 0;
                        for (let i = 0; i < text.length; i += charsPerLine) {
                            const line = text.substring(i, i + charsPerLine);
                            const metrics = ctx.measureText(line);
                            maxLineWidth = Math.max(maxLineWidth, metrics.width);
                        }
                        textWidth = maxLineWidth;
                    } else {
                        const metrics = ctx.measureText(text);
                        textWidth = metrics.width;
                    }
                    
                    if (textWidth <= availableWidth && fontSize <= availableHeight) {
                        minFont = fontSize;
                    } else {
                        maxFont = fontSize;
                    }
                    
                    fontSize = (minFont + maxFont) / 2;
                }
                
                return Math.floor(fontSize);
            }
            
            // 生成SVG字符串(支持新功能)
            function generateSvgString(size) {
                const text = textInput.value || '图标';
                let selectedFont = fontSelect.value;
                const textColor = colorInput.value;
                const bgColor = transparentBg.checked ? 'none' : bgColorInput.value;
                const shape = selectedShape;
                const wrapEnabled = autoWrap.checked;
                
                let fontFamily = selectedFont;
                if (!uploadedFonts.has(selectedFont) && fontFamily.includes(' ') && !fontFamily.startsWith("'") && !fontFamily.startsWith('"')) {
                    fontFamily = `'${fontFamily}'`;
                }
                
                const tempCanvas = document.createElement('canvas');
                tempCanvas.width = size;
                tempCanvas.height = size;
                const tempCtx = tempCanvas.getContext('2d');
                
                let fontSize;
                if (autoStretch.checked) {
                    fontSize = calculateOptimalFontSize(tempCtx, text, size, shape, wrapEnabled, selectedFont);
                } else {
                    fontSize = (size * parseInt(fontSizeSlider.value) / 100) * 0.8;
                }
                
                const hStretch = parseInt(horizontalStretch.value) / 100;
                const vStretch = parseInt(verticalStretch.value) / 100;
                const hOffset = parseInt(horizontalOffset.value);
                const vOffset = parseInt(verticalOffset.value);
                
                const position = getPositionOffset(size);
                
                // 构建SVG
                let svg = `<svg width="${size}" height="${size}" viewBox="0 0 ${size} ${size}" xmlns="http://www.w3.org/2000/svg">`;
                
                // 裁剪路径
                let clipPath = '';
                switch(shape) {
                    case 'circle':
                        clipPath = `<circle cx="${size/2}" cy="${size/2}" r="${size/2}"/>`;
                        break;
                    case 'rounded':
                        const radius = size * 0.1;
                        clipPath = `<rect width="100%" height="100%" rx="${radius}" ry="${radius}"/>`;
                        break;
                    default:
                        clipPath = `<rect width="100%" height="100%"/>`;
                }
                svg += `<defs><clipPath id="shapeClip">${clipPath}</clipPath></defs>`;
                
                // 背景
                if (!transparentBg.checked) {
                    switch(shape) {
                        case 'square':
                            svg += `<rect width="100%" height="100%" fill="${bgColor}"/>`;
                            break;
                        case 'circle':
                            svg += `<circle cx="${size/2}" cy="${size/2}" r="${size/2}" fill="${bgColor}"/>`;
                            break;
                        case 'rounded':
                            const radius = size * 0.1;
                            svg += `<rect width="100%" height="100%" rx="${radius}" ry="${radius}" fill="${bgColor}"/>`;
                            break;
                    }
                }
                
                // 文字层
                svg += `<g clip-path="url(#shapeClip)">`;
                svg += `<g transform="translate(${position.x} ${position.y}) scale(${hStretch} ${vStretch}) translate(${hOffset * (size / 256)} ${vOffset * (size / 256)})">`;
                
                // 获取对齐方式(修复上下颠倒)
                const posParts = selectedPosition.split('-');
                const hAlign = posParts[1] === 'left' ? 'start' : posParts[1] === 'right' ? 'end' : 'middle';
                const vAlign = posParts[0] === 'top' ? 'hanging' : posParts[0] === 'bottom' ? 'baseline' : 'middle';
                
                // 换行处理
                if (wrapEnabled && text.length > 1) {
                    const lines = [];
                    const charsPerLine = text.length <= 2 ? 1 : 2;
                    for (let i = 0; i < text.length; i += charsPerLine) {
                        lines.push(text.substring(i, i + charsPerLine));
                    }
                    
                    const lineHeight = fontSize * 1.2;
                    const totalHeight = lines.length * lineHeight;
                    let startY = 0;
                    
                    if (vAlign === 'middle') {
                        startY -= (totalHeight - lineHeight) / 2;
                    } else if (vAlign === 'baseline') {
                        startY -= totalHeight - lineHeight;
                    }
                    
                    lines.forEach((line, index) => {
                        svg += `<text x="0" y="${startY + index * lineHeight}" font-family="${fontFamily}" font-size="${fontSize}" fill="${textColor}" text-anchor="${hAlign}" dominant-baseline="${vAlign}">${line}</text>`;
                    });
                } else {
                    svg += `<text x="0" y="0" font-family="${fontFamily}" font-size="${fontSize}" fill="${textColor}" text-anchor="${hAlign}" dominant-baseline="${vAlign}">${text}</text>`;
                }
                
                svg += `</g></g></svg>`;
                return svg;
            }
            
            // 生成图标并更新预览
            function generateIcon() {
                drawIcon(previewCanvas, selectedSize);
                updateSizePreview();
            }
            
            // 更新尺寸预览
            function updateSizePreview() {
                sizePreview.innerHTML = '';
                const sizes = [16, 32, 48, 64, 128, 256];
                
                sizes.forEach(size => {
                    const previewItem = document.createElement('div');
                    previewItem.className = 'size-preview-item';
                    
                    const previewCanvas = document.createElement('canvas');
                    previewCanvas.className = 'size-preview-canvas';
                    previewCanvas.width = Math.min(64, size);
                    previewCanvas.height = Math.min(64, size);
                    
                    const scale = Math.min(1, 64 / size);
                    const ctx = previewCanvas.getContext('2d');
                    
                    ctx.save();
                    ctx.scale(scale, scale);
                    drawIcon(previewCanvas, size);
                    ctx.restore();
                    
                    const sizeLabel = document.createElement('div');
                    sizeLabel.textContent = `${size}×${size}`;
                    sizeLabel.style.fontSize = '12px';
                    sizeLabel.style.color = '#666';
                    
                    previewItem.appendChild(previewCanvas);
                    previewItem.appendChild(sizeLabel);
                    sizePreview.appendChild(previewItem);
                });
            }
            
            // 输入变化实时更新
            textInput.addEventListener('input', generateIcon);
            fontSelect.addEventListener('change', generateIcon);
            colorInput.addEventListener('input', generateIcon);
            autoStretch.addEventListener('change', generateIcon);
            fontSizeSlider.addEventListener('input', generateIcon); // 新增
            
            // 初始化生成图标
            generateIcon();
            
            // 清理资源
            window.addEventListener('beforeunload', function() {
                if (progressInterval) clearInterval(progressInterval);
                if (progressPercentInterval) clearInterval(progressPercentInterval);
                if (downloadTimeout) clearTimeout(downloadTimeout);
                
                uploadedFonts.forEach((fontData) => {
                    URL.revokeObjectURL(fontData.url);
                    document.fonts.delete(fontData.face);
                });
            });
        });
    </script>
</body>
</html>









免费评分

参与人数 6吾爱币 +11 热心值 +5 收起 理由
lsb2pojie + 1 + 1 热心回复!
zz4zyfox + 1 鼓励转贴优秀软件安全工具和文档!
gun008 + 1 用心讨论,共获提升!
hrh123 + 7 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!
yklt168 + 1 + 1 热心回复!
kokonews + 1 + 1 用心讨论,共获提升!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

推荐
gong084 发表于 2025-12-1 19:55
本帖最后由 gong084 于 2025-12-1 20:30 编辑

目前原代码中文字换行只支持“自动换行”,还不支持手动换行。比如你想输入五个字,让上面显示两个、下面显示三个,目前是实现不了的。
建议把输入框改成 textarea,支持多行输入,这样文字排列会更整齐美观。(修改后的代码支持多行输入)
[HTML] 纯文本查看 复制代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>图标生成器 - 文字转PNG/ICO/SVG</title>
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
        }
         
        body {
            background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
            color: #333;
            min-height: 100vh;
            padding: 10px;
        }
         
        .container {
            max-width: 1200px;
            margin: 0 auto;
            background-color: white;
            border-radius: 15px;
            box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1);
            overflow: hidden;
        }
         
        header {
            background: linear-gradient(90deg, #4b6cb7 0%, #182848 100%);
            color: white;
            padding: 25px 30px;
            text-align: center;
        }
         
        header h1 {
            font-size: 2.2rem;
            margin-bottom: 10px;
        }
         
        header p {
            opacity: 0.9;
            font-size: 1.1rem;
        }
         
        .app-content {
            display: flex;
            flex-wrap: wrap;
            padding: 20px;
            min-height: calc(100vh - 180px);
        }
         
        .controls {
            flex: 1;
            min-width: 300px;
            padding: 20px;
            border-right: 1px solid #eee;
            overflow-y: auto;
            max-height: calc(100vh - 180px);
        }
         
        .preview {
            flex: 1;
            min-width: 300px;
            padding: 20px;
            display: flex;
            flex-direction: column;
            align-items: center;
            justify-content: center;
            gap: 20px;
        }
         
        .control-group {
            margin-bottom: 25px;
            padding: 15px;
            background: #f8f9fa;
            border-radius: 10px;
            box-shadow: 0 2px 5px rgba(0,0,0,0.05);
        }
         
        .control-group h3 {
            margin-bottom: 15px;
            color: #4b6cb7;
            border-bottom: 1px solid #eaeaea;
            padding-bottom: 8px;
        }
         
        .form-group {
            margin-bottom: 15px;
        }
         
        label {
            display: block;
            margin-bottom: 5px;
            font-weight: 500;
        }
         
        input, select, button, textarea {
            width: 100%;
            padding: 10px 15px;
            border: 1px solid #ddd;
            border-radius: 5px;
            font-size: 1rem;
        }
         
        textarea {
            resize: vertical;
            min-height: 80px;
            font-family: inherit;
            line-height: 1.4;
        }
         
        button {
            background: linear-gradient(90deg, #4b6cb7 0%, #182848 100%);
            color: white;
            border: none;
            cursor: pointer;
            font-weight: 600;
            transition: all 0.3s ease;
            margin-top: 10px;
        }
         
        button:hover {
            transform: translateY(-2px);
            box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1);
        }
         
        #loadSystemFonts {
            background: linear-gradient(90deg, #27ae60 0%, #219653 100%);
        }
        #loadSystemFonts:hover {
            box-shadow: 0 5px 15px rgba(39, 174, 96, 0.2);
        }
        #uploadFontBtn {
            background: linear-gradient(90deg, #e67e22 0%, #d35400 100%);
        }
        #uploadFontBtn:hover {
            box-shadow: 0 5px 15px rgba(230, 126, 34, 0.2);
        }
         
        .color-input {
            display: flex;
            align-items: center;
        }
         
        .color-input input {
            flex: 1;
        }
         
        .color-preview {
            width: 30px;
            height: 30px;
            border-radius: 5px;
            margin-left: 10px;
            border: 1px solid #ddd;
        }
         
        .shape-options, .size-options {
            display: flex;
            flex-wrap: wrap;
            gap: 10px;
        }
         
        .position-options {
            display: grid;
            grid-template-columns: repeat(3, 1fr);
            gap: 8px;
            width: 100%;
        }
         
        .shape-option, .size-option {
            flex: 1;
            min-width: 80px;
            text-align: center;
            padding: 10px;
            border: 2px solid #ddd;
            border-radius: 5px;
            cursor: pointer;
            transition: all 0.2s;
        }
         
        .position-option {
            padding: 12px 5px;
            font-size: 0.9rem;
            border: 2px solid #ddd;
            border-radius: 5px;
            cursor: pointer;
            transition: all 0.2s;
            text-align: center;
            background: #f8f9fa;
        }
         
        .shape-option:hover, .size-option:hover, .position-option:hover {
            border-color: #4b6cb7;
        }
         
        .shape-option.active, .size-option.active, .position-option.active {
            border-color: #4b6cb7;
            background-color: rgba(75, 108, 183, 0.1);
        }
         
        .checkbox-group {
            display: flex;
            align-items: center;
            margin-bottom: 10px;
        }
         
        .checkbox-group input {
            width: auto;
            margin-right: 10px;
        }
         
        #transparentBgGroup {
            padding: 8px;
            background: rgba(75, 108, 183, 0.05);
            border-radius: 5px;
            margin-top: 5px;
        }
                 
        .char-count {
            font-size: 0.8rem;
            color: #666;
            margin-top: 5px;
        }
         
        .max-chars {
            color: #e74c3c;
        }
         
        .stretch-controls, .font-size-controls {
            display: flex;
            gap: 15px;
            margin-top: 10px;
        }
         
        .stretch-control, .font-size-control {
            flex: 1;
            text-align: center;
        }
         
        .stretch-control label, .font-size-control label {
            font-size: 0.9rem;
            margin-bottom: 5px;
        }
         
        .font-size-note {
            font-size: 0.8rem;
            color: #e67e22;
            margin-top: 5px;
            padding: 5px;
            background: rgba(230, 126, 34, 0.05);
            border-radius: 4px;
        }
         
        .stretch-control input, .font-size-control input {
            width: 100%;
        }
         
        .stretch-value, .font-size-value {
            font-size: 0.8rem;
            color: #666;
            margin-top: 5px;
        }
         
        .preview-area {
            width: 256px;
            height: 256px;
            border: 1px solid #ddd;
            border-radius: 10px;
            display: flex;
            align-items: center;
            justify-content: center;
            overflow: hidden;
            background:
                linear-gradient(45deg, #f0f0f0 25%, transparent 25%),
                linear-gradient(-45deg, #f0f0f0 25%, transparent 25%),
                linear-gradient(45deg, transparent 75%, #f0f0f0 75%),
                linear-gradient(-45deg, transparent 75%, #f0f0f0 75%);
            background-size: 20px 20px;
            background-position: 0 0, 0 10px, 10px -10px, -10px 0px;
            box-shadow: 0 5px 15px rgba(0, 0, 0, 0.05);
            position: relative;
        }
         
        canvas {
            max-width: 100%;
            max-height: 100%;
        }
         
        .download-options {
            display: flex;
            gap: 10px;
            width: 100%;
            max-width: 400px;
        }
         
        .download-options button {
            flex: 1;
        }
         
        .size-preview {
            display: flex;
            flex-wrap: wrap;
            gap: 10px;
            justify-content: center;
            width: 100%;
            max-width: 400px;
        }
         
        .size-preview-item {
            display: flex;
            flex-direction: column;
            align-items: center;
            margin-bottom: 10px;
        }
         
        .size-preview-canvas {
            border: 1px solid #ddd;
            margin-bottom: 5px;
            background:
                linear-gradient(45deg, #f0f0f0 25%, transparent 25%),
                linear-gradient(-45deg, #f0f0f0 25%, transparent 25%),
                linear-gradient(45deg, transparent 75%, #f0f0f0 75%),
                linear-gradient(-45deg, transparent 75%, #f0f0f0 75%);
            background-size: 8px 8px;
            background-position: 0 0, 0 4px, 4px -4px, -4px 0px;
        }
         
        footer {
            text-align: center;
            padding: 20px;
            color: #666;
            font-size: 0.9rem;
            border-top: 1px solid #eee;
            height: 80px;
        }
         
        .font-loading {
            display: inline-block;
            margin-left: 10px;
            animation: spin 1s linear infinite;
        }
         
        @keyframes spin {
            0% { transform: rotate(0deg); }
            100% { transform: rotate(360deg); }
        }
         
        .font-group {
            margin: 5px 0;
            padding: 8px;
            background: #e9ecef;
            border-radius: 4px;
            font-weight: 600;
            color: #2d3436;
        }
         
        .font-upload-area {
            margin: 15px 0;
            padding: 15px;
            border: 2px dashed #e67e22;
            border-radius: 5px;
            text-align: center;
            transition: all 0.3s;
        }
        .font-upload-area:hover {
            background: rgba(230, 126, 34, 0.05);
        }
        #fontFileInput {
            display: none;
        }
        .upload-hint {
            font-size: 0.85rem;
            color: #666;
            margin-top: 8px;
        }
        .upload-success {
            margin-top: 10px;
            padding: 8px;
            background: rgba(46, 204, 113, 0.1);
            color: #27ae60;
            border-radius: 4px;
            font-size: 0.9rem;
            display: none;
        }
 
        /* 进度条样式(优化动画) */
        .progress-modal {
            position: fixed;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            background: rgba(0, 0, 0, 0.5);
            display: flex;
            flex-direction: column;
            align-items: center;
            justify-content: center;
            z-index: 1000;
            opacity: 0;
            visibility: hidden;
            transition: all 0.3s ease;
        }
        .progress-modal.active {
            opacity: 1;
            visibility: visible;
        }
        .progress-container {
            background: white;
            padding: 30px;
            border-radius: 10px;
            width: 90%;
            max-width: 500px;
            box-shadow: 0 10px 30px rgba(0, 0, 0, 0.2);
        }
        .progress-title {
            font-size: 1.2rem;
            font-weight: 600;
            color: #333;
            margin-bottom: 15px;
            text-align: center;
        }
        .progress-bar-container {
            width: 100%;
            height: 12px;
            background: #f1f1f1;
            border-radius: 6px;
            overflow: hidden;
            margin-bottom: 15px;
            position: relative;
        }
        .progress-bar {
            height: 100%;
            background: linear-gradient(90deg, #4b6cb7 0%, #182848 100%);
            width: 0%;
            border-radius: 6px;
            position: absolute;
            left: 0;
            top: 0;
            transition: width 2s ease-out; /* 改为2秒平滑动画 */
        }
        .progress-text {
            font-size: 0.9rem;
            color: #666;
            text-align: center;
        }
        .progress-success {
            color: #27ae60;
            font-weight: 600;
            display: none;
        }
 
        /* 新增:手动换行提示样式 */
        .manual-wrap-hint {
            font-size: 0.8rem;
            color: #666;
            margin-top: 5px;
            padding: 5px;
            background: rgba(52, 152, 219, 0.05);
            border-radius: 4px;
            display: none;
        }
        .manual-wrap-hint.active {
            display: block;
        }
 
        /* 响应式适配 */
        @media (max-width: 768px) {
            .app-content {
                flex-direction: column;
                min-height: auto;
            }
             
            .controls {
                border-right: none;
                border-bottom: 1px solid #eee;
                max-height: none;
            }
             
            .preview {
                min-height: 500px;
                justify-content: flex-start;
                padding-top: 30px;
            }
             
            .stretch-controls, .font-size-controls {
                flex-direction: column;
            }
             
            .download-options {
                flex-direction: column;
                max-width: 100%;
            }
             
            .progress-container {
                padding: 20px;
            }
             
            .position-options {
                grid-template-columns: repeat(3, 1fr);
            }
        }
    </style>
</head>
<body>
    <div class="container">
        <header>
            <h1>图标生成器 - 文字转PNG/ICO/SVG (增强版)</h1>
        </header>
         
        <div class="app-content">
            <div class="controls">
                <div class="control-group">
                    <h3>文字设置</h3>
                    <div class="form-group">
                        <label for="textInput">输入文字或Emoji表情符号(≤20个字符)</label>
                        <textarea id="textInput" maxlength="20" placeholder="可输入文字或Emoji,支持手动换行">图</textarea>
                        <div class="char-count">当前字符数: <span id="charCount">1</span>/20</div>
                        <div class="manual-wrap-hint" id="manualWrapHint">
                            &#128161; 手动换行已启用:按Enter键换行,支持多行显示
                        </div>
                    </div>
                     
                    <div class="form-group">
                        <label for="fontSelect">选择字体(内置+本机+上传)</label>
                        <select id="fontSelect" size="8" style="height: 200px; overflow-y: auto;">
                            <!-- 字体选项通过JS动态填充 -->
                        </select>
                    </div>
                     
                    <!-- 本机字体加载区域 -->
                    <div class="form-group">
                        <button id="loadSystemFonts">
                            加载本机已安装字体库
                            <span id="systemFontLoading" class="font-loading" style="display: none;">&#10227;</span>
                        </button>
                        <p style="font-size: 0.8rem; color: #666; margin-top: 5px;">
                            &#128204; 支持Chrome/Edge/Opera最新版 | 仅本地读取不上传 | 加载后永久可用
                        </p>
                    </div>
                     
                    <!-- 手动上传字体区域 -->
                    <div class="font-upload-area">
                        <label for="fontFileInput" style="cursor: pointer; font-weight: 600; color: #e67e22;">
                            点击选择本地字体文件(TTF/OTF)
                        </label>
                        <input type="file" id="fontFileInput" accept=".ttf,.otf,.ttc" multiple>
                        <p class="upload-hint">
                            支持格式:TTF/OTF/TTC | 可批量上传 | 仅临时使用(刷新后失效)
                        </p>
                        <div id="uploadSuccessMsg" class="upload-success">
                            &#9989; 字体上传成功!已添加到字体列表末尾
                        </div>
                    </div>
                     
                    <div class="stretch-controls">
                        <div class="stretch-control">
                            <label for="colorInput">文字颜色(点击选择)</label>
                            <div class="color-input">
                                <input type="color" id="colorInput" value="#ea1026">
                                <div class="color-preview" id="colorPreview"></div>
                            </div>
                        </div>
                         
                        <div class="stretch-control">
                            <label for="bgColorInput">背景颜色</label>
                            <div class="color-input">
                                <input type="color" id="bgColorInput" value="#ffffff">
                                <div class="color-preview" id="bgColorPreview"></div>
                            </div>
                        </div>
                    </div>
                                         
                                        <!-- 透明背景选项 -->
                    <div class="checkbox-group" id="transparentBgGroup">
                        <input type="checkbox" id="transparentBg" checked>
                        <label for="transparentBg">启用透明背景(取消则显示上方背景色)</label>
                    </div>
                     
                    <div class="checkbox-group">
                        <input type="checkbox" id="autoWrap" checked>
                        <label for="autoWrap">自动换行显示多个文字</label>
                    </div>
                     
                    <div class="checkbox-group">
                        <input type="checkbox" id="autoStretch" checked>
                        <label for="autoStretch">自动拉伸文字以适应图标</label>
                    </div>
                     
                    <!-- 新增:字体大小调整 -->
                    <div class="font-size-controls">
                        <div class="font-size-control">
                            <label for="fontSizeSlider">字体大小</label>
                            <input type="range" id="fontSizeSlider" min="10" max="200" value="80">
                            <div class="font-size-value" id="fontSizeValue">80%</div>
                            <div class="font-size-note">&#128161; 提示:需先关闭"自动拉伸"才能手动调整字体大小</div>
                        </div>
                    </div>
                     
                    <div class="stretch-controls">
                        <div class="stretch-control">
                            <label for="horizontalStretch">水平拉伸</label>
                            <input type="range" id="horizontalStretch" min="50" max="500" value="141">
                            <div class="stretch-value" id="horizontalValue">141%</div>
                        </div>
                         
                        <div class="stretch-control">
                            <label for="verticalStretch">垂直拉伸</label>
                            <input type="range" id="verticalStretch" min="50" max="500" value="126">
                            <div class="stretch-value" id="verticalValue">126%</div>
                        </div>
                    </div>
                     
                    <div class="stretch-controls">
                        <div class="stretch-control">
                            <label for="horizontalOffset">横向偏移</label>
                            <input type="range" id="horizontalOffset" min="-50" max="50" value="-5">
                            <div class="stretch-value" id="horizontalOffsetValue">-5px</div>
                        </div>
                         
                        <div class="stretch-control">
                            <label for="verticalOffset">垂直偏移</label>
                            <input type="range" id="verticalOffset" min="-50" max="50" value="2">
                            <div class="stretch-value" id="verticalOffsetValue">2px</div>
                        </div>
                    </div>
                     
                    <!-- 新增:9方位位置选择 -->
                    <div class="form-group" style="margin-top: 20px;">
                        <label>文字位置(九宫格)</label>
                        <div class="position-options">
                            <div class="position-option" data-position="top-left">左上</div>
                            <div class="position-option" data-position="top-center">中上</div>
                            <div class="position-option" data-position="top-right">右上</div>
                            <div class="position-option" data-position="center-left">左中</div>
                            <div class="position-option active" data-position="center-center">居中</div>
                            <div class="position-option" data-position="center-right">右中</div>
                            <div class="position-option" data-position="bottom-left">左下</div>
                            <div class="position-option" data-position="bottom-center">中下</div>
                            <div class="position-option" data-position="bottom-right">右下</div>
                        </div>
                    </div>
                 
                    <h3>图标形状</h3>
                    <div class="shape-options">
                        <div class="shape-option" data-shape="square">方形</div>
                        <div class="shape-option" data-shape="circle">圆形</div>
                        <div class="shape-option active" data-shape="rounded">圆角方形</div>
                    </div>
                </div>
                 
                <button id="generateBtn" style="display:none;">生成图标</button>
            </div>
             
            <div class="preview">
                <div class="preview-area">
                    <canvas id="previewCanvas" width="256" height="256"></canvas>
                </div>
                <div class="control-group">
                    <h3>图标尺寸</h3>
                    <div class="size-options">
                        <div class="size-option" data-size="16">16×16</div>
                        <div class="size-option" data-size="32">32×32</div>
                        <div class="size-option" data-size="48">48×48</div>
                        <div class="size-option" data-size="64">64×64</div>
                        <div class="size-option" data-size="128">128×128</div>
                        <div class="size-option active" data-size="256">256×256</div>
                    </div>
                </div>
                 
                <div class="download-options">
                    <button id="downloadPngBtn">下载PNG</button>
                    <button id="downloadIcoBtn">下载ICO</button>
                    <button id="downloadSvgBtn">下载SVG</button>
                </div>
                 
                <div class="size-preview">
                    <!-- 尺寸预览区域通过JS动态生成 -->
                </div>
            </div>
        </div>
         
        <footer>
            <p>图标生成器 &#169; 2025 - 支持PNG、ICO和SVG格式输出 | 增强版:进度条+字体大小+9方位调整+手动换行</p>
        </footer>
    </div>
 
    <!-- 下载进度条弹窗 -->
    <div class="progress-modal" id="downloadProgressModal">
        <div class="progress-container">
            <div class="progress-title" id="progressTitle">正在准备下载...</div>
            <div class="progress-bar-container">
                <div class="progress-bar" id="progressBar"></div>
            </div>
            <div class="progress-text">
                <span id="progressPercent">0%</span> |
                <span id="progressStep">初始化...</span>
                <span id="progressSuccess" class="progress-success">下载准备完成!</span>
            </div>
        </div>
    </div>
 
    <script>
        document.addEventListener('DOMContentLoaded', function() {
            // 获取DOM元素
            const textInput = document.getElementById('textInput');
            const charCount = document.getElementById('charCount');
            const manualWrapHint = document.getElementById('manualWrapHint');
            const autoWrap = document.getElementById('autoWrap');
            const fontSelect = document.getElementById('fontSelect');
            const loadSystemFontsBtn = document.getElementById('loadSystemFonts');
            const systemFontLoading = document.getElementById('systemFontLoading');
            const fontFileInput = document.getElementById('fontFileInput');
            const uploadSuccessMsg = document.getElementById('uploadSuccessMsg');
            const colorInput = document.getElementById('colorInput');
            const colorPreview = document.getElementById('colorPreview');
            const bgColorInput = document.getElementById('bgColorInput');
            const bgColorPreview = document.getElementById('bgColorPreview');
            const transparentBg = document.getElementById('transparentBg');
            const autoStretch = document.getElementById('autoStretch');
            const fontSizeSlider = document.getElementById('fontSizeSlider'); // 新增
            const fontSizeValue = document.getElementById('fontSizeValue'); // 新增
            const horizontalStretch = document.getElementById('horizontalStretch');
            const verticalStretch = document.getElementById('verticalStretch');
            const horizontalOffset = document.getElementById('horizontalOffset');
            const verticalOffset = document.getElementById('verticalOffset');
            const horizontalValue = document.getElementById('horizontalValue');
            const verticalValue = document.getElementById('verticalValue');
            const horizontalOffsetValue = document.getElementById('horizontalOffsetValue');
            const verticalOffsetValue = document.getElementById('verticalOffsetValue');
            const shapeOptions = document.querySelectorAll('.shape-option');
            const sizeOptions = document.querySelectorAll('.size-option');
            const positionOptions = document.querySelectorAll('.position-option'); // 新增
            const generateBtn = document.getElementById('generateBtn');
            const downloadPngBtn = document.getElementById('downloadPngBtn');
            const downloadIcoBtn = document.getElementById('downloadIcoBtn');
            const downloadSvgBtn = document.getElementById('downloadSvgBtn');
            const previewCanvas = document.getElementById('previewCanvas');
            const sizePreview = document.querySelector('.size-preview');
            // 进度条相关元素
            const progressModal = document.getElementById('downloadProgressModal');
            const progressTitle = document.getElementById('progressTitle');
            const progressBar = document.getElementById('progressBar');
            const progressPercent = document.getElementById('progressPercent');
            const progressStep = document.getElementById('progressStep');
            const progressSuccess = document.getElementById('progressSuccess');
             
            // 初始化变量
            let selectedShape = 'rounded';
            let selectedSize = 256;
            let selectedPosition = 'center-center'; // 新增
            let ctx = previewCanvas.getContext('2d');
            let systemFontsLoaded = false;
            let uploadedFonts = new Map();
            let fontCounter = 1;
            let progressInterval = null;
            let progressPercentInterval = null;
            let downloadTimeout = null; // 新增:控制下载延迟
             
            // 内置字体库(分类整理)
            const builtInFonts = [
                { group: '常用中文字体', fonts: [
                    { family: 'Microsoft YaHei', name: '微软雅黑' },
                    { family: '微软雅黑 Light', name: '微软雅黑 Light' },
                    { family: 'SimSun', name: '宋体' },
                    { family: '新宋体', name: '新宋体' },
                    { family: 'FangSong', name: '仿宋' },
                    { family: 'KaiTi', name: '楷体' },
                    { family: 'LiSu', name: '隶书' },
                    { family: 'YouYuan', name: '幼圆' },
                    { family: '黑体', name: '黑体' },
                    { family: '等线', name: '等线' },
                    { family: '等线 Light', name: '等线 Light' }
                ]},
                { group: '思源字体', fonts: [
                    { family: "'Noto Sans SC', sans-serif", name: '思源黑体 (Noto Sans SC)' },
                    { family: "'Noto Serif SC', serif", name: '思源宋体 (Noto Serif SC)' }
                ]},
                { group: '华文系列', fonts: [
                    { family: '华文中宋', name: '华文中宋' },
                    { family: '华文仿宋', name: '华文仿宋' },
                    { family: '华文宋体', name: '华文宋体' },
                    { family: '华文彩云', name: '华文彩云' },
                    { family: '华文新魏', name: '华文新魏' },
                    { family: '华文楷体', name: '华文楷体' },
                    { family: '华文琥珀', name: '华文琥珀' },
                    { family: '华文细黑', name: '华文细黑' },
                    { family: '华文行楷', name: '华文行楷' },
                    { family: '华文隶书', name: '华文隶书' }
                ]},
                { group: '方正系列', fonts: [
                    { family: '方正姚体', name: '方正姚体' },
                    { family: '方正舒体', name: '方正舒体' }
                ]},
                { group: '英文字体', fonts: [
                    { family: 'Arial', name: 'Arial' },
                    { family: 'Verdana', name: 'Verdana' },
                    { family: 'Helvetica', name: 'Helvetica' },
                    { family: 'Georgia', name: 'Georgia' },
                    { family: 'Times New Roman', name: 'Times New Roman' },
                    { family: 'Courier New', name: 'Courier New' },
                    { family: 'Impact', name: 'Impact' },
                    { family: 'Comic Sans MS', name: 'Comic Sans MS' }
                ]}
            ];
             
            // 初始化字体选择框
            function initFontSelect() {
                fontSelect.innerHTML = '';
                 
                // 添加内置字体(分组显示)
                builtInFonts.forEach(group => {
                    const groupOption = document.createElement('option');
                    groupOption.disabled = true;
                    groupOption.innerHTML = `&#128193; ${group.group}`;
                    groupOption.className = 'font-group';
                    fontSelect.appendChild(groupOption);
                     
                    group.fonts.forEach(font => {
                        const option = document.createElement('option');
                        option.value = font.family;
                        option.textContent = `  ${font.name}`;
                        if (font.family === 'SimSun') {
                            option.selected = true;
                        }
                        fontSelect.appendChild(option);
                    });
                });
                 
                // 添加分隔线(本机字体区域)
                const systemDivider = document.createElement('option');
                systemDivider.disabled = true;
                systemDivider.textContent = '────────── 本机已安装字体(点击上方按钮加载) ──────────';
                fontSelect.appendChild(systemDivider);
                 
                // 添加分隔线(上传字体区域)
                const uploadDivider = document.createElement('option');
                uploadDivider.disabled = true;
                uploadDivider.textContent = '────────── 本地上传字体(临时使用) ──────────';
                fontSelect.appendChild(uploadDivider);
            }
             
            // 初始化字体选择框
            initFontSelect();
             
            // 进度条初始化(优化动画)
            function initProgressBar(format, fileName) {
                // 清除之前的定时器
                if (progressInterval) clearInterval(progressInterval);
                if (progressPercentInterval) clearInterval(progressPercentInterval);
                if (downloadTimeout) clearTimeout(downloadTimeout);
                 
                // 重置进度条状态
                progressModal.classList.add('active');
                progressTitle.textContent = `正在准备下载 ${format} 文件:${fileName}`;
                progressBar.style.width = '0%';
                progressPercent.textContent = '0%';
                progressSuccess.style.display = 'none';
                progressStep.textContent = '初始化...';
                 
                // 进度步骤提示
                const steps = [
                    '初始化下载参数...',
                    '正在渲染图标内容...',
                    '正在优化图像质量...',
                    '正在处理文件数据...',
                    '正在生成下载链接...',
                    '最后检查文件完整性...'
                ];
                 
                // 分步更新进度条
                let stepIndex = 0;
                let currentProgress = 0;
                 
                // 每300ms更新一次进度
                progressInterval = setInterval(() => {
                    currentProgress += 2; // 每次增加2%
                    if (currentProgress > 100) currentProgress = 100;
                     
                    progressBar.style.width = `${currentProgress}%`;
                    progressPercent.textContent = `${currentProgress}%`;
                     
                    // 更新步骤提示
                    const stepPosition = Math.floor(currentProgress / (100 / steps.length));
                    if (stepPosition < steps.length) {
                        progressStep.textContent = steps[stepPosition];
                    } else {
                        progressStep.textContent = '准备完成...';
                    }
                     
                    // 进度完成后停止
                    if (currentProgress >= 100) {
                        clearInterval(progressInterval);
                        progressInterval = null;
                    }
                }, 30);
            }
             
            // 关闭进度条弹窗(增加延迟)
            function closeProgressBar() {
                progressStep.textContent = '文件生成完成!';
                progressSuccess.style.display = 'inline-block';
                 
                // 保持进度条显示2秒后关闭
                setTimeout(() => {
                    progressModal.classList.remove('active');
                     
                    // 重置进度条状态
                    setTimeout(() => {
                        progressSuccess.style.display = 'none';
                        progressBar.style.width = '0%';
                        progressPercent.textContent = '0%';
                    }, 300);
                }, 800); // 显示完成状态800ms
            }
             
            // 错误状态进度条
            function errorProgressBar(format, errorMsg) {
                if (progressInterval) clearInterval(progressInterval);
                if (progressPercentInterval) clearInterval(progressPercentInterval);
                 
                progressModal.classList.add('active');
                progressTitle.textContent = `下载 ${format} 文件失败`;
                progressBar.style.width = '0%';
                progressPercent.textContent = '0%';
                progressStep.textContent = `&#10060; ${errorMsg}`;
                progressStep.style.color = '#e74c3c';
                progressSuccess.style.display = 'none';
                 
                setTimeout(() => {
                    progressModal.classList.remove('active');
                    setTimeout(() => {
                        progressStep.style.color = '';
                    }, 300);
                }, 3000);
            }
             
            // 获取自定义下载文件名
            function getCustomFileName(format) {
                let content = textInput.value.trim() || '图标';
                // 获取第一行作为文件名(如果有多行)
                content = content.split('\n')[0];
                const invalidChars = /[\\/:*?"<>|]/g;
                content = content.replace(invalidChars, '-');
                if (content.length > 10) {
                    content = content.substring(0, 10) + '...';
                }
                return `${content}-${selectedSize}.${format}`;
            }
             
            // 下载PNG(优化进度条显示)
            downloadPngBtn.addEventListener('click', async function() {
                try {
                    const format = 'png';
                    const fileName = getCustomFileName(format);
                    initProgressBar('PNG', fileName);
                     
                    // 生成文件
                    const canvas = createCanvas(selectedSize);
                    drawIcon(canvas, selectedSize);
                     
                    const link = document.createElement('a');
                    link.download = fileName;
                    link.href = canvas.toDataURL(`image/${format}`);
                     
                    // 等待进度条动画完成后触发下载
                    setTimeout(() => {
                        link.click();
                        closeProgressBar();
                    }, 1200); // 等待1.2秒让进度条动画完成
                     
                } catch (error) {
                    console.error('PNG下载失败:', error);
                    errorProgressBar('PNG', '文件生成失败,请重试');
                }
            });
             
            // 下载ICO(优化进度条显示)
            downloadIcoBtn.addEventListener('click', async function() {
                try {
                    const format = 'ico';
                    const downloadSize = parseInt(selectedSize);
                    const fileName = getCustomFileName(format);
                    initProgressBar('ICO', fileName);
                     
                    // 生成文件
                    const canvas = document.createElement('canvas');
                    canvas.width = downloadSize;
                    canvas.height = downloadSize;
                    const ctx = canvas.getContext('2d');
                    ctx.clearRect(0, 0, downloadSize, downloadSize);
                    drawIcon(canvas, downloadSize);
                     
                    const pngData = canvas.toDataURL('image/png').split(',')[1];
                    const pngBuffer = Uint8Array.from(atob(pngData), c => c.charCodeAt(0));
                     
                    const icoHeader = new Uint8Array([0, 0, 1, 0, 1, 0]);
                    const icoDir = new Uint8Array(16);
                    icoDir[0] = downloadSize > 255 ? 0 : downloadSize;
                    icoDir[1] = downloadSize > 255 ? 0 : downloadSize;
                    icoDir[2] = 0;
                    icoDir[3] = 0;
                    icoDir[4] = 1; icoDir[5] = 0;
                    icoDir[6] = 32; icoDir[7] = 0;
                    const size = pngBuffer.length;
                    icoDir[8] = size & 0xFF;
                    icoDir[9] = (size >> 8) & 0xFF;
                    icoDir[10] = (size >> 16) & 0xFF;
                    icoDir[11] = (size >> 24) & 0xFF;
                    const offset = icoHeader.length + icoDir.length;
                    icoDir[12] = offset & 0xFF;
                    icoDir[13] = (offset >> 8) & 0xFF;
                    icoDir[14] = (offset >> 16) & 0xFF;
                    icoDir[15] = (offset >> 24) & 0xFF;
                     
                    const icoData = new Uint8Array(icoHeader.length + icoDir.length + pngBuffer.length);
                    icoData.set(icoHeader);
                    icoData.set(icoDir, icoHeader.length);
                    icoData.set(pngBuffer, icoHeader.length + icoDir.length);
                     
                    const blob = new Blob([icoData], { type: 'image/x-icon' });
                    const link = document.createElement('a');
                    link.href = URL.createObjectURL(blob);
                    link.download = fileName;
                    link.style.display = 'none';
                    document.body.appendChild(link);
                     
                    // 等待进度条动画完成后触发下载
                    setTimeout(() => {
                        link.click();
                        setTimeout(() => {
                            document.body.removeChild(link);
                            URL.revokeObjectURL(link.href);
                            closeProgressBar();
                        }, 100);
                    }, 1200); // 等待1.2秒
                     
                } catch (error) {
                    console.error('ICO下载失败:', error);
                    errorProgressBar('ICO', '文件生成失败,请重试');
                }
            });
             
            // 下载SVG(优化进度条显示)
            downloadSvgBtn.addEventListener('click', async function() {
                try {
                    const format = 'svg';
                    const fileName = getCustomFileName(format);
                    initProgressBar('SVG', fileName);
                     
                    // 生成文件
                    const svgString = generateSvgString(selectedSize);
                    const blob = new Blob([svgString], { type: 'image/svg+xml' });
                    const url = URL.createObjectURL(blob);
                    const link = document.createElement('a');
                    link.href = url;
                    link.download = fileName;
                     
                    // 等待进度条动画完成后触发下载
                    setTimeout(() => {
                        link.click();
                        URL.revokeObjectURL(url);
                        closeProgressBar();
                    }, 1200); // 等待1.2秒
                     
                } catch (error) {
                    console.error('SVG下载失败:', error);
                    errorProgressBar('SVG', '文件生成失败,请重试');
                }
            });
             
            // 字体上传功能
            fontFileInput.addEventListener('change', async function(e) {
                const files = e.target.files;
                if (!files || files.length === 0) return;
                 
                let successCount = 0;
                const validExtensions = ['ttf', 'otf', 'ttc'];
                 
                for (const file of files) {
                    const fileName = file.name;
                    const fileExt = fileName.split('.').pop().toLowerCase();
                     
                    if (!validExtensions.includes(fileExt)) {
                        alert(`&#10060; 文件 "${fileName}" 格式不支持\n仅支持TTF/OTF/TTC格式`);
                        continue;
                    }
                     
                    try {
                        const fontUniqueName = `UploadedFont_${fontCounter++}_${fileName.replace(/\.[^/.]+$/, "")}`;
                        const fontUrl = URL.createObjectURL(file);
                        const fontFace = new FontFace(fontUniqueName, `url(${fontUrl})`);
                         
                        await fontFace.load();
                        document.fonts.add(fontFace);
                        uploadedFonts.set(fontUniqueName, {
                            face: fontFace,
                            url: fontUrl,
                            fileName: fileName
                        });
                         
                        const option = document.createElement('option');
                        option.value = fontUniqueName;
                        option.textContent = `  &#128228; ${fileName}`;
                        const uploadDivider = Array.from(fontSelect.options).find(
                            opt => opt.textContent.includes('本地上传字体')
                        );
                        if (uploadDivider) {
                            fontSelect.insertBefore(option, uploadDivider.nextSibling);
                        } else {
                            fontSelect.appendChild(option);
                        }
                         
                        successCount++;
                    } catch (error) {
                        console.error(`加载字体 ${fileName} 失败:`, error);
                        alert(`&#10060; 加载字体 "${fileName}" 失败\n可能是损坏的字体文件或浏览器不支持`);
                    }
                }
                 
                if (successCount > 0) {
                    uploadSuccessMsg.textContent = `&#9989; 成功上传 ${successCount} 个字体!已添加到字体列表`;
                    uploadSuccessMsg.style.display = 'block';
                    setTimeout(() => {
                        uploadSuccessMsg.style.display = 'none';
                    }, 3000);
                }
                 
                fontFileInput.value = '';
                generateIcon();
            });
             
            // 本机字体加载功能
            loadSystemFontsBtn.addEventListener('click', async function() {
                if (systemFontsLoaded) {
                    alert('&#9989; 本机字体已加载完成!可直接在字体列表中选择使用');
                    return;
                }
                 
                try {
                    systemFontLoading.style.display = 'inline-block';
                    loadSystemFontsBtn.disabled = true;
                     
                    if (!('queryLocalFonts' in window)) {
                        alert('&#10060; 您的浏览器不支持加载本机字体功能\n\n推荐使用:\n&#8226; Chrome 103+ 浏览器\n&#8226; Edge 103+ 浏览器\n&#8226; Opera 89+ 浏览器\n\n请升级浏览器后重试');
                        return;
                    }
                     
                    try {
                        const permission = await navigator.permissions.query({ name: 'local-fonts' });
                        if (permission.state !== 'granted') {
                            alert('&#128274; 需要您授予字体访问权限\n\n请在浏览器弹出的权限请求中选择"允许",以便读取本机字体库');
                            return;
                        }
                    } catch (permErr) {
                        console.log('权限查询不支持,直接尝试获取字体');
                    }
                     
                    console.log('正在读取本机字体库...');
                    const fonts = await window.queryLocalFonts();
                     
                    const uniqueFonts = Array.from(new Map(
                        fonts.map(font => [font.family.toLowerCase(), font])
                    )).map(([_, font]) => font)
                      .sort((a, b) => (a.fullName || a.family).localeCompare(b.fullName || b.family));
                     
                    const systemFontGroups = {
                        '中文字体': [],
                        '英文字体': [],
                        '其他字体': []
                    };
                    const chineseRegex = /[\u4e00-\u9fa5]/;
                     
                    uniqueFonts.forEach(font => {
                        const fontName = font.fullName || font.family;
                        const fontFamily = font.family;
                         
                        if (chineseRegex.test(fontName) || chineseRegex.test(fontFamily)) {
                            systemFontGroups['中文字体'].push({ family: fontFamily, name: fontName });
                        } else if (/^[a-zA-Z\s]+$/.test(fontName)) {
                            systemFontGroups['英文字体'].push({ family: fontFamily, name: fontName });
                        } else {
                            systemFontGroups['其他字体'].push({ family: fontFamily, name: fontName });
                        }
                    });
                     
                    const systemDivider = Array.from(fontSelect.options).find(
                        opt => opt.textContent.includes('本机已安装字体')
                    );
                    if (systemDivider) {
                        Object.entries(systemFontGroups).forEach(([groupName, fonts]) => {
                            if (fonts.length === 0) return;
                             
                            const groupOption = document.createElement('option');
                            groupOption.disabled = true;
                            groupOption.innerHTML = `&#128421;&#65039; 本机${groupName}`;
                            groupOption.className = 'font-group';
                            fontSelect.insertBefore(groupOption, systemDivider.nextSibling);
                             
                            fonts.forEach(font => {
                                const option = document.createElement('option');
                                option.value = font.family;
                                option.textContent = `  ${font.name}`;
                                fontSelect.insertBefore(option, systemDivider.nextSibling);
                            });
                        });
                    }
                     
                    systemFontsLoaded = true;
                    alert(`&#9989; 成功加载 ${uniqueFonts.length} 个本机字体!\n已添加到字体列表中`);
                     
                } catch (error) {
                    console.error('加载本机字体失败:', error);
                    alert(`&#10060; 加载本机字体失败:${error.message}\n\n可能原因:\n1. 浏览器权限未授予\n2. 浏览器版本过低\n3. 系统字体库访问受限`);
                } finally {
                    systemFontLoading.style.display = 'none';
                    loadSystemFontsBtn.disabled = false;
                }
            });
             
            // 透明背景切换
            transparentBg.addEventListener('change', function() {
                if (this.checked) {
                    bgColorInput.disabled = true;
                    bgColorPreview.style.backgroundColor = 'transparent';
                    bgColorPreview.style.border = '1px dashed #ddd';
                } else {
                    bgColorInput.disabled = false;
                    bgColorPreview.style.backgroundColor = bgColorInput.value;
                    bgColorPreview.style.border = '1px solid #ddd';
                }
                generateIcon();
            });
             
            // 初始化背景色预览
            bgColorPreview.style.backgroundColor = 'transparent';
            bgColorPreview.style.border = '1px dashed #ddd';
            bgColorInput.disabled = true;
             
            // 字符计数
            textInput.addEventListener('input', function() {
                const count = this.value.length;
                charCount.textContent = count;
                if (count > 20) {
                    charCount.classList.add('max-chars');
                } else {
                    charCount.classList.remove('max-chars');
                }
                generateIcon();
            });
             
            // 自动换行切换 - 显示/隐藏手动换行提示
            autoWrap.addEventListener('change', function() {
                if (this.checked) {
                    manualWrapHint.classList.remove('active');
                } else {
                    manualWrapHint.classList.add('active');
                }
                generateIcon();
            });
             
            // 初始化手动换行提示显示状态
            if (!autoWrap.checked) {
                manualWrapHint.classList.add('active');
            }
             
            // 颜色预览更新
            colorInput.addEventListener('input', function() {
                colorPreview.style.backgroundColor = colorInput.value;
                generateIcon();
            });
             
            bgColorInput.addEventListener('input', function() {
                if (!transparentBg.checked) {
                    bgColorPreview.style.backgroundColor = this.value;
                    generateIcon();
                }
            });
             
            // 新增:自动拉伸切换时禁用/启用字体大小滑块
            autoStretch.addEventListener('change', function() {
                fontSizeSlider.disabled = this.checked;
                if (this.checked) {
                    document.querySelector('.font-size-note').style.opacity = '0.7';
                } else {
                    document.querySelector('.font-size-note').style.opacity = '1';
                }
                generateIcon();
            });
             
            // 初始化字体大小滑块状态
            fontSizeSlider.disabled = autoStretch.checked;
            if (autoStretch.checked) {
                document.querySelector('.font-size-note').style.opacity = '0.7';
            }
             
            // 新增:字体大小滑块更新
            fontSizeSlider.addEventListener('input', function() {
                fontSizeValue.textContent = `${this.value}%`;
                generateIcon();
            });
             
            // 拉伸滑块更新
            horizontalStretch.addEventListener('input', function() {
                horizontalValue.textContent = `${this.value}%`;
                generateIcon();
            });
             
            verticalStretch.addEventListener('input', function() {
                verticalValue.textContent = `${this.value}%`;
                generateIcon();
            });
             
            // 偏移滑块更新
            horizontalOffset.addEventListener('input', function() {
                horizontalOffsetValue.textContent = `${this.value}px`;
                generateIcon();
            });
             
            verticalOffset.addEventListener('input', function() {
                verticalOffsetValue.textContent = `${this.value}px`;
                generateIcon();
            });
             
            // 形状选择
            shapeOptions.forEach(option => {
                option.addEventListener('click', function() {
                    shapeOptions.forEach(opt => opt.classList.remove('active'));
                    this.classList.add('active');
                    selectedShape = this.dataset.shape;
                    generateIcon();
                });
            });
             
            // 尺寸选择
            sizeOptions.forEach(option => {
                option.addEventListener('click', function() {
                    sizeOptions.forEach(opt => opt.classList.remove('active'));
                    this.classList.add('active');
                    selectedSize = parseInt(this.dataset.size);
                    generateIcon();
                });
            });
             
            // 新增:位置选择
            positionOptions.forEach(option => {
                option.addEventListener('click', function() {
                    positionOptions.forEach(opt => opt.classList.remove('active'));
                    this.classList.add('active');
                    selectedPosition = this.dataset.position;
                    generateIcon();
                });
            });
             
            // 生成图标按钮
            generateBtn.addEventListener('click', generateIcon);
             
            // 创建Canvas元素
            function createCanvas(size) {
                const canvas = document.createElement('canvas');
                canvas.width = size;
                canvas.height = size;
                return canvas;
            }
             
            // 修复:获取位置偏移(上下颠倒问题)
            function getPositionOffset(size) {
                const offsets = {
                    'top-left': { x: size * 0.25, y: size * 0.25 },
                    'top-center': { x: size * 0.5, y: size * 0.25 },
                    'top-right': { x: size * 0.75, y: size * 0.25 },
                    'center-left': { x: size * 0.25, y: size * 0.5 },
                    'center-center': { x: size * 0.5, y: size * 0.5 },
                    'center-right': { x: size * 0.75, y: size * 0.5 },
                    'bottom-left': { x: size * 0.25, y: size * 0.75 },
                    'bottom-center': { x: size * 0.5, y: size * 0.75 },
                    'bottom-right': { x: size * 0.75, y: size * 0.75 }
                };
                return offsets[selectedPosition] || offsets['center-center'];
            }
             
            // 绘制图标(增强版)- 支持手动换行
            function drawIcon(canvas, size) {
                const ctx = canvas.getContext('2d');
                const text = textInput.value || '图标';
                const wrapEnabled = autoWrap.checked;
                let selectedFont = fontSelect.value;
                 
                ctx.clearRect(0, 0, size, size);
                 
                // 绘制背景
                if (!transparentBg.checked) {
                    ctx.fillStyle = bgColorInput.value;
                     
                    switch(selectedShape) {
                        case 'square':
                            ctx.fillRect(0, 0, size, size);
                            break;
                        case 'circle':
                            ctx.beginPath();
                            ctx.arc(size/2, size/2, size/2, 0, Math.PI * 2);
                            ctx.fill();
                            break;
                        case 'rounded':
                            const radius = size * 0.1;
                            ctx.beginPath();
                            ctx.moveTo(radius, 0);
                            ctx.lineTo(size - radius, 0);
                            ctx.quadraticCurveTo(size, 0, size, radius);
                            ctx.lineTo(size, size - radius);
                            ctx.quadraticCurveTo(size, size, size - radius, size);
                            ctx.lineTo(radius, size);
                            ctx.quadraticCurveTo(0, size, 0, size - radius);
                            ctx.lineTo(0, radius);
                            ctx.quadraticCurveTo(0, 0, radius, 0);
                            ctx.closePath();
                            ctx.fill();
                            break;
                    }
                }
                 
                // 设置裁剪区域
                ctx.save();
                switch(selectedShape) {
                    case 'circle':
                        ctx.beginPath();
                        ctx.arc(size/2, size/2, size/2, 0, Math.PI * 2);
                        ctx.clip();
                        break;
                    case 'rounded':
                        const radius = size * 0.1;
                        ctx.beginPath();
                        ctx.moveTo(radius, 0);
                        ctx.lineTo(size - radius, 0);
                        ctx.quadraticCurveTo(size, 0, size, radius);
                        ctx.lineTo(size, size - radius);
                        ctx.quadraticCurveTo(size, size, size - radius, size);
                        ctx.lineTo(radius, size);
                        ctx.quadraticCurveTo(0, size, 0, size - radius);
                        ctx.lineTo(0, radius);
                        ctx.quadraticCurveTo(0, 0, radius, 0);
                        ctx.closePath();
                        ctx.clip();
                        break;
                }
                 
                // 绘制文字
                ctx.fillStyle = colorInput.value;
                 
                // 计算字体大小
                let fontSize;
                if (autoStretch.checked) {
                    fontSize = calculateOptimalFontSize(ctx, text, size, selectedShape, wrapEnabled, selectedFont);
                } else {
                    // 使用手动设置的字体大小
                    fontSize = (size * parseInt(fontSizeSlider.value) / 100) * 0.8;
                }
                 
                // 处理字体名称
                let fontFamily = selectedFont;
                if (!uploadedFonts.has(selectedFont) && fontFamily.includes(' ') && !fontFamily.startsWith("'") && !fontFamily.startsWith('"')) {
                    fontFamily = `'${fontFamily}'`;
                }
                 
                ctx.font = `bold ${fontSize}px ${fontFamily}`;
                 
                // 获取位置偏移
                const position = getPositionOffset(size);
                 
                // 应用拉伸和偏移
                const hStretch = parseInt(horizontalStretch.value) / 100;
                const vStretch = parseInt(verticalStretch.value) / 100;
                const hOffset = parseInt(horizontalOffset.value);
                const vOffset = parseInt(verticalOffset.value);
                 
                ctx.translate(position.x, position.y);
                ctx.scale(hStretch, vStretch);
                const offsetX = hOffset * (size / 256);
                const offsetY = vOffset * (size / 256);
                 
                // 设置文字对齐方式
                const posParts = selectedPosition.split('-');
                const hAlign = posParts[1] === 'left' ? 'left' : posParts[1] === 'right' ? 'right' : 'center';
                const vAlign = posParts[0] === 'top' ? 'alphabetic' : posParts[0] === 'bottom' ? 'bottom' : 'middle';
                 
                ctx.textAlign = hAlign;
                ctx.textBaseline = vAlign;
                 
                // 绘制文字 - 根据是否启用自动换行选择绘制方式
                if (!wrapEnabled && text.includes('\n')) {
                    // 手动换行模式:按用户输入的换行符显示
                    drawManualWrappedText(ctx, text, offsetX, offsetY, fontSize, size, fontFamily, hAlign, vAlign);
                } else if (wrapEnabled && text.length > 1) {
                    // 自动换行模式:忽略手动换行符,按自动逻辑排列
                    drawAutoWrappedText(ctx, text.replace(/\n/g, ''), offsetX, offsetY, fontSize, size, fontFamily, hAlign, vAlign);
                } else {
                    // 单行模式:不换行
                    ctx.fillText(text.replace(/\n/g, ' '), offsetX, offsetY);
                }
                 
                ctx.restore();
            }
             
            // 新增:绘制手动换行文字
            function drawManualWrappedText(ctx, text, offsetX, offsetY, fontSize, size, fontFamily, hAlign, vAlign) {
                const lines = text.split('\n').filter(line => line.trim() !== '');
                if (lines.length === 0) return;
                 
                const lineHeight = fontSize * 1.2;
                const totalHeight = lines.length * lineHeight;
                 
                // 根据垂直对齐方式调整起始位置(修复上下颠倒)
                let startY = offsetY;
                if (vAlign === 'middle') {
                    startY -= (totalHeight - lineHeight) / 2;
                } else if (vAlign === 'bottom') {
                    startY -= totalHeight - lineHeight;
                } else if (vAlign === 'alphabetic') {
                    startY += lineHeight * 0.2; // 顶部对齐时微调
                }
                 
                ctx.font = `bold ${fontSize}px ${fontFamily}`;
                ctx.textAlign = hAlign;
                ctx.textBaseline = vAlign;
                 
                lines.forEach((line, index) => {
                    ctx.fillText(line, offsetX, startY + index * lineHeight);
                });
            }
             
            // 修复:绘制自动换行文字(上下颠倒问题)
            function drawAutoWrappedText(ctx, text, offsetX, offsetY, fontSize, size, fontFamily, hAlign, vAlign) {
                const lines = [];
                const charsPerLine = text.length <= 2 ? 1 : 2;
                 
                for (let i = 0; i < text.length; i += charsPerLine) {
                    lines.push(text.substring(i, i + charsPerLine));
                }
                 
                const lineHeight = fontSize * 1.2;
                const totalHeight = lines.length * lineHeight;
                 
                // 根据垂直对齐方式调整起始位置(修复上下颠倒)
                let startY = offsetY;
                if (vAlign === 'middle') {
                    startY -= (totalHeight - lineHeight) / 2;
                } else if (vAlign === 'bottom') {
                    startY -= totalHeight - lineHeight;
                } else if (vAlign === 'alphabetic') {
                    startY += lineHeight * 0.2; // 顶部对齐时微调
                }
                 
                ctx.font = `bold ${fontSize}px ${fontFamily}`;
                ctx.textAlign = hAlign;
                ctx.textBaseline = vAlign;
                 
                lines.forEach((line, index) => {
                    ctx.fillText(line, offsetX, startY + index * lineHeight);
                });
            }
             
            // 计算最佳字体大小
            function calculateOptimalFontSize(ctx, text, size, shape, wrapEnabled, selectedFont) {
                let availableWidth, availableHeight;
                switch(shape) {
                    case 'square':
                    case 'rounded':
                        availableWidth = size * 0.9;
                        availableHeight = size * 0.9;
                        break;
                    case 'circle':
                        availableWidth = size * 0.8;
                        availableHeight = size * 0.8;
                        break;
                }
                 
                const textWithoutNewlines = text.replace(/\n/g, '');
                
                if (!wrapEnabled && text.includes('\n')) {
                    // 手动换行模式:考虑行数
                    const lines = text.split('\n').filter(line => line.trim() !== '');
                    availableHeight = availableHeight / lines.length * 0.8;
                } else if (wrapEnabled && textWithoutNewlines.length > 1) {
                    // 自动换行模式
                    const lines = Math.ceil(textWithoutNewlines.length / (textWithoutNewlines.length <= 2 ? 1 : 2));
                    availableHeight = availableHeight / lines * 0.8;
                }
                 
                let fontSize = Math.min(availableWidth, availableHeight);
                let minFont = 1;
                let maxFont = fontSize * 2;
                 
                let fontFamily = selectedFont;
                if (!uploadedFonts.has(selectedFont) && fontFamily.includes(' ') && !fontFamily.startsWith("'") && !fontFamily.startsWith('"')) {
                    fontFamily = `'${fontFamily}'`;
                }
                 
                for (let i = 0; i < 10; i++) {
                    ctx.font = `bold ${fontSize}px ${fontFamily}`;
                     
                    let textWidth;
                    if (!wrapEnabled && text.includes('\n')) {
                        // 手动换行模式:取最宽的一行
                        const lines = text.split('\n').filter(line => line.trim() !== '');
                        let maxLineWidth = 0;
                        lines.forEach(line => {
                            const metrics = ctx.measureText(line);
                            maxLineWidth = Math.max(maxLineWidth, metrics.width);
                        });
                        textWidth = maxLineWidth;
                    } else if (wrapEnabled && textWithoutNewlines.length > 1) {
                        // 自动换行模式
                        const charsPerLine = textWithoutNewlines.length <= 2 ? 1 : 2;
                        let maxLineWidth = 0;
                        for (let i = 0; i < textWithoutNewlines.length; i += charsPerLine) {
                            const line = textWithoutNewlines.substring(i, i + charsPerLine);
                            const metrics = ctx.measureText(line);
                            maxLineWidth = Math.max(maxLineWidth, metrics.width);
                        }
                        textWidth = maxLineWidth;
                    } else {
                        // 单行模式
                        const metrics = ctx.measureText(textWithoutNewlines);
                        textWidth = metrics.width;
                    }
                     
                    if (textWidth <= availableWidth && fontSize <= availableHeight) {
                        minFont = fontSize;
                    } else {
                        maxFont = fontSize;
                    }
                     
                    fontSize = (minFont + maxFont) / 2;
                }
                 
                return Math.floor(fontSize);
            }
             
            // 生成SVG字符串(支持新功能)
            function generateSvgString(size) {
                const text = textInput.value || '图标';
                let selectedFont = fontSelect.value;
                const textColor = colorInput.value;
                const bgColor = transparentBg.checked ? 'none' : bgColorInput.value;
                const shape = selectedShape;
                const wrapEnabled = autoWrap.checked;
                 
                let fontFamily = selectedFont;
                if (!uploadedFonts.has(selectedFont) && fontFamily.includes(' ') && !fontFamily.startsWith("'") && !fontFamily.startsWith('"')) {
                    fontFamily = `'${fontFamily}'`;
                }
                 
                const tempCanvas = document.createElement('canvas');
                tempCanvas.width = size;
                tempCanvas.height = size;
                const tempCtx = tempCanvas.getContext('2d');
                 
                let fontSize;
                if (autoStretch.checked) {
                    fontSize = calculateOptimalFontSize(tempCtx, text, size, shape, wrapEnabled, selectedFont);
                } else {
                    fontSize = (size * parseInt(fontSizeSlider.value) / 100) * 0.8;
                }
                 
                const hStretch = parseInt(horizontalStretch.value) / 100;
                const vStretch = parseInt(verticalStretch.value) / 100;
                const hOffset = parseInt(horizontalOffset.value);
                const vOffset = parseInt(verticalOffset.value);
                 
                const position = getPositionOffset(size);
                 
                // 构建SVG
                let svg = `<svg width="${size}" height="${size}" viewBox="0 0 ${size} ${size}" xmlns="http://www.w3.org/2000/svg">`;
                 
                // 裁剪路径
                let clipPath = '';
                switch(shape) {
                    case 'circle':
                        clipPath = `<circle cx="${size/2}" cy="${size/2}" r="${size/2}"/>`;
                        break;
                    case 'rounded':
                        const radius = size * 0.1;
                        clipPath = `<rect width="100%" height="100%" rx="${radius}" ry="${radius}"/>`;
                        break;
                    default:
                        clipPath = `<rect width="100%" height="100%"/>`;
                }
                svg += `<defs><clipPath id="shapeClip">${clipPath}</clipPath></defs>`;
                 
                // 背景
                if (!transparentBg.checked) {
                    switch(shape) {
                        case 'square':
                            svg += `<rect width="100%" height="100%" fill="${bgColor}"/>`;
                            break;
                        case 'circle':
                            svg += `<circle cx="${size/2}" cy="${size/2}" r="${size/2}" fill="${bgColor}"/>`;
                            break;
                        case 'rounded':
                            const radius = size * 0.1;
                            svg += `<rect width="100%" height="100%" rx="${radius}" ry="${radius}" fill="${bgColor}"/>`;
                            break;
                    }
                }
                 
                // 文字层
                svg += `<g clip-path="url(#shapeClip)">`;
                svg += `<g transform="translate(${position.x} ${position.y}) scale(${hStretch} ${vStretch}) translate(${hOffset * (size / 256)} ${vOffset * (size / 256)})">`;
                 
                // 获取对齐方式(修复上下颠倒)
                const posParts = selectedPosition.split('-');
                const hAlign = posParts[1] === 'left' ? 'start' : posParts[1] === 'right' ? 'end' : 'middle';
                const vAlign = posParts[0] === 'top' ? 'hanging' : posParts[0] === 'bottom' ? 'baseline' : 'middle';
                 
                // 换行处理
                if (!wrapEnabled && text.includes('\n')) {
                    // 手动换行模式
                    const lines = text.split('\n').filter(line => line.trim() !== '');
                    if (lines.length === 0) return svg + '</g></g></svg>';
                     
                    const lineHeight = fontSize * 1.2;
                    const totalHeight = lines.length * lineHeight;
                    let startY = 0;
                     
                    if (vAlign === 'middle') {
                        startY -= (totalHeight - lineHeight) / 2;
                    } else if (vAlign === 'baseline') {
                        startY -= totalHeight - lineHeight;
                    } else if (vAlign === 'hanging') {
                        startY += lineHeight * 0.2;
                    }
                     
                    lines.forEach((line, index) => {
                        svg += `<text x="0" y="${startY + index * lineHeight}" font-family="${fontFamily}" font-size="${fontSize}" fill="${textColor}" text-anchor="${hAlign}" dominant-baseline="${vAlign}">${line}</text>`;
                    });
                } else if (wrapEnabled && text.replace(/\n/g, '').length > 1) {
                    // 自动换行模式:忽略手动换行符
                    const textWithoutNewlines = text.replace(/\n/g, '');
                    const lines = [];
                    const charsPerLine = textWithoutNewlines.length <= 2 ? 1 : 2;
                    for (let i = 0; i < textWithoutNewlines.length; i += charsPerLine) {
                        lines.push(textWithoutNewlines.substring(i, i + charsPerLine));
                    }
                     
                    const lineHeight = fontSize * 1.2;
                    const totalHeight = lines.length * lineHeight;
                    let startY = 0;
                     
                    if (vAlign === 'middle') {
                        startY -= (totalHeight - lineHeight) / 2;
                    } else if (vAlign === 'baseline') {
                        startY -= totalHeight - lineHeight;
                    } else if (vAlign === 'hanging') {
                        startY += lineHeight * 0.2;
                    }
                     
                    lines.forEach((line, index) => {
                        svg += `<text x="0" y="${startY + index * lineHeight}" font-family="${fontFamily}" font-size="${fontSize}" fill="${textColor}" text-anchor="${hAlign}" dominant-baseline="${vAlign}">${line}</text>`;
                    });
                } else {
                    // 单行模式:不换行
                    svg += `<text x="0" y="0" font-family="${fontFamily}" font-size="${fontSize}" fill="${textColor}" text-anchor="${hAlign}" dominant-baseline="${vAlign}">${text.replace(/\n/g, ' ')}</text>`;
                }
                 
                svg += `</g></g></svg>`;
                return svg;
            }
             
            // 生成图标并更新预览
            function generateIcon() {
                drawIcon(previewCanvas, selectedSize);
                updateSizePreview();
            }
             
            // 更新尺寸预览
            function updateSizePreview() {
                sizePreview.innerHTML = '';
                const sizes = [16, 32, 48, 64, 128, 256];
                 
                sizes.forEach(size => {
                    const previewItem = document.createElement('div');
                    previewItem.className = 'size-preview-item';
                     
                    const previewCanvas = document.createElement('canvas');
                    previewCanvas.className = 'size-preview-canvas';
                    previewCanvas.width = Math.min(64, size);
                    previewCanvas.height = Math.min(64, size);
                     
                    const scale = Math.min(1, 64 / size);
                    const ctx = previewCanvas.getContext('2d');
                     
                    ctx.save();
                    ctx.scale(scale, scale);
                    drawIcon(previewCanvas, size);
                    ctx.restore();
                     
                    const sizeLabel = document.createElement('div');
                    sizeLabel.textContent = `${size}×${size}`;
                    sizeLabel.style.fontSize = '12px';
                    sizeLabel.style.color = '#666';
                     
                    previewItem.appendChild(previewCanvas);
                    previewItem.appendChild(sizeLabel);
                    sizePreview.appendChild(previewItem);
                });
            }
             
            // 输入变化实时更新
            textInput.addEventListener('input', generateIcon);
            fontSelect.addEventListener('change', generateIcon);
            colorInput.addEventListener('input', generateIcon);
            autoStretch.addEventListener('change', generateIcon);
            fontSizeSlider.addEventListener('input', generateIcon); // 新增
             
            // 初始化生成图标
            generateIcon();
             
            // 清理资源
            window.addEventListener('beforeunload', function() {
                if (progressInterval) clearInterval(progressInterval);
                if (progressPercentInterval) clearInterval(progressPercentInterval);
                if (downloadTimeout) clearTimeout(downloadTimeout);
                 
                uploadedFonts.forEach((fontData) => {
                    URL.revokeObjectURL(fontData.url);
                    document.fonts.delete(fontData.face);
                });
            });
        });
    </script>
</body>
</html>

PixPin_2025-12-01_20-01-22.png (130.94 KB, 下载次数: 0)

PixPin_2025-12-01_20-01-22.png

免费评分

参与人数 2吾爱币 +2 热心值 +2 收起 理由
zylz9941 + 1 谢谢@Thanks!
lxhwan100 + 2 + 1 谢谢@Thanks!

查看全部评分

沙发
kokonews 发表于 2025-12-1 19:43
4#
wzj8080 发表于 2025-12-1 21:25
5#
souny 发表于 2025-12-1 21:30
感谢分享。。。!
6#
cccuuuiii 发表于 2025-12-1 22:40
真是好工具,支持原创。
7#
cccuuuiii 发表于 2025-12-1 22:45
gong084 发表于 2025-12-1 19:55
目前原代码中文字换行只支持“自动换行”,还不支持手动换行。比如你想输入五个字,让上面显示两个、下面显 ...

真的挺好用的。谢谢分享。
8#
dada02 发表于 2025-12-2 05:52
本帖最后由 dada02 于 2025-12-2 09:23 编辑
gong084 发表于 2025-12-1 19:55
目前原代码中文字换行只支持“自动换行”,还不支持手动换行。比如你想输入五个字,让上面显示两个、下面显 ...

都是高手!


9#
HSX19841230 发表于 2025-12-2 06:59
研究研究代码,现在AI真方便
10#
daoye9988 发表于 2025-12-2 07:59
增强版来啦,功能增加不少
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - 52pojie.cn ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2025-12-6 02:31

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表