/** * 画个标 · 技能库:导出类(export) * 注册:HGB_Skills.register([...]) */ (function () { 'use strict'; HGB_Skills.register([ { id: 'export-multi', name: '多格式导出', category: 'export', emoji: '📦', scene: '方案导出 PNG / JPG / SVG / PDF 与多尺寸规格', summary: '封装导出引擎:任意方案一键导出 SVG(矢量)与 PNG/PDF(JPEG 压缩位图),支持 512/1024/2048 等尺寸。', params: [ { name: 'plan', type: 'object', required: true, desc: '方案对象' }, { name: 'format', type: 'string', required: false, desc: 'png/svg/pdf(默认 png)' }, { name: 'size', type: 'number', required: false, desc: '导出边长(默认 1024)' } ], source: '自研导出引擎(SVG 渲染 + Canvas 位图 + 手写 PDF)', run: function (args) { const plan = args.plan || {}; const format = (args.format || 'png').toLowerCase(); const size = args.size || 1024; const svg = HGB_Exporter.buildSvgFrom(plan.elements || [], plan.bg || '#FFFFFF', size); return { plan: plan.name || '未命名', format, size, svgLength: svg.length, supported: ['png', 'jpg', 'svg', 'pdf'], canExport: HGB_Exporter.exportPng && HGB_Exporter.exportSvg ? true : false, note: format === 'pdf' ? 'PDF 内嵌 JPEG 位图,适合打印' : (format === 'svg' ? 'SVG 为矢量,可无限缩放' : 'PNG 为位图,建议 1024+') }; }, test: function () { const plan = HGB_Generator.generateVariant({ industry: HGB_Industries[0], brand: '导出测试' }); const r = this.run({ plan, format: 'svg', size: 1024 }); return { format: r.format, svgLength: r.svgLength, canExport: r.canExport }; } }, { id: 'export-avatar', name: '头像平台规格', category: 'export', emoji: '🪪', scene: '头像导出的主流平台尺寸规格', summary: '返回微信/QQ/抖音/YouTube/App Store/Favicon 等平台头像规格清单,指导按平台要求批量导出头像。', params: [ { name: 'platform', type: 'string', required: false, desc: '指定平台(wechat/qq/douyin/youtube/app/favicon),留空返回全部' } ], source: '自研(平台头像规格表)', run: function (args) { const specs = [ { platform: '微信', size: 300, note: '微信个人/公众号头像推荐' }, { platform: 'QQ', size: 640, note: 'QQ 头像常用尺寸' }, { platform: '抖音', size: 400, note: '抖音头像展示尺寸' }, { platform: 'YouTube', size: 800, note: 'YouTube 频道头像' }, { platform: 'App Store', size: 1024, note: 'App 图标规范' }, { platform: 'Favicon', size: 64, note: '浏览器标签页图标' } ]; const p = String(args.platform || '').toLowerCase(); const map = { wechat: 0, qq: 1, douyin: 2, youtube: 3, app: 4, favicon: 5 }; const list = p && map[p] !== undefined ? [specs[map[p]]] : specs; return { list, total: specs.length, exportNote: '头像导出走 exporter.exportAvatarPngs(圆形裁切)' }; }, test: function () { return { wechat: this.run({ platform: 'wechat' }).list[0], all: this.run({}).list.length }; } }, { id: 'export-sizing', name: '导出尺寸规范', category: 'export', emoji: '📐', scene: 'LOGO 各用途推荐导出尺寸', summary: '按用途(网页/印刷/社交/App 图标)推荐 LOGO 导出尺寸与格式,网页用 PNG/SVG、印刷用矢量或高分辨率位图。', params: [ { name: 'use', type: 'string', required: false, desc: '用途(web/print/social/app)' } ], source: '自研(LOGO 交付尺寸规范)', run: function (args) { const use = String(args.use || 'web').toLowerCase(); const specMap = { web: { use: '网页', size: '512×512 PNG', format: 'PNG/SVG', dpi: '96dpi', note: 'Web 加载快,建议 SVG 为主 PNG 兜底' }, print: { use: '印刷', size: '1024×1024 起', format: 'PDF(矢量)/ 高分辨率 PNG', dpi: '300dpi', note: '印刷务必矢量或 300dpi 位图,避免模糊' }, social: { use: '社交媒体', size: '400~800×400~800', format: 'PNG', dpi: '144dpi', note: '头像/封面按平台规格导出' }, app: { use: 'App 图标', size: '1024×1024', format: 'PNG(含透明)', dpi: '96dpi', note: 'App Store 需 1024px 无圆角原图' } }; return specMap[use] || specMap.web; }, test: function () { return { web: this.run({ use: 'web' }).size, print: this.run({ use: 'print' }).dpi }; } }, { id: 'favicon-kit', name: 'Favicon 全套尺寸', category: 'export', emoji: '🌐', scene: '浏览器/移动端 Favicon 全尺寸导出清单', summary: '列出 Favicon 标准尺寸集(16/32/48/64/180/192/512),并给出各文件用途与浏览器兼容说明。', params: [ { name: 'plan', type: 'object', required: false, desc: '方案对象(可选)' } ], source: '自研(Favicon 规范:HTML5 link 尺寸)', run: function (args) { const specs = [ { file: 'favicon-16x16.png', size: 16, use: '浏览器标签页' }, { file: 'favicon-32x32.png', size: 32, use: '任务栏/快捷键' }, { file: 'favicon-48x48.png', size: 48, use: 'Windows 站点图标' }, { file: 'favicon-64x64.png', size: 64, use: '传统标签页' }, { file: 'apple-touch-icon.png', size: 180, use: 'iOS 主屏书签' }, { file: 'android-chrome-192x192.png', size: 192, use: 'Android 添加到主屏' }, { file: 'android-chrome-512x512.png', size: 512, use: 'PWA 图标' } ]; return { specs, tip: '小尺寸(16~32)务必先过「小尺寸可读性」检查;导出使用 exportSvg → PNG 缩放', canExport: !!(HGB_Exporter && HGB_Exporter.exportPng) }; }, test: function () { const r = this.run({}); return { sizes: r.specs.map(s => s.size).join(','), canExport: r.canExport }; } }, { id: 'transparent-check', name: '透明背景检查', category: 'export', emoji: '👁️', scene: '导出格式的透明背景支持检查', summary: '检查方案背景是否为透明:PNG/SVG 支持透明,JPG 不支持(自动垫白);透明底适合头像/贴纸,深色展示图则建议保留底色。', params: [ { name: 'plan', type: 'object', required: false, desc: '方案对象 {bg}' } ], source: '自研(导出格式透明规则)', run: function (args) { const plan = args.plan || {}; const bg = plan.bg; const transparent = !bg || String(bg).toLowerCase() === 'transparent' || plan.transparent === true; return { background: transparent ? '透明' : (bg || '#FFFFFF'), transparent, png: '支持透明(PNG-24 含 Alpha)', svg: '支持透明(矢量透明)', jpg: '不支持透明(自动填充白色)', verdict: transparent ? '当前为透明背景:适合头像/贴纸/叠加场景,导出 PNG 或 SVG' : '当前为纯色背景:如需透明底,请切换背景为「透明」后导出 PNG', suggest: transparent ? '导出推荐 PNG(保留 Alpha)或 SVG' : '背景为 ' + (bg || '#FFFFFF') + ',导出 JPG 无透明需求时可用' }; }, test: function () { return { transparent: this.run({ plan: { bg: 'transparent' } }).verdict, solid: this.run({ plan: { bg: '#FFFFFF' } }).transparent }; } }, { id: 'print-safety', name: '印刷安全区检查', category: 'export', emoji: '🖨️', scene: 'LOGO 印刷/裁切的安全边距检查', summary: '检查元素是否过于贴近画布边缘:印刷裁切、印章、贴纸需要预留安全边距(出血),贴边元素易被裁掉。', params: [ { name: 'plan', type: 'object', required: true, desc: '方案对象 {elements}' } ], source: '自研(印刷出血/安全边距规范)', run: function (args) { const els = (args.plan || {}).elements || []; const CW = 600, CH = 600, MARGIN = 30; const vis = els.filter(el => el.visible !== false); if (!vis.length) return { pass: true, note: '无可见元素' }; const tight = []; for (const el of vis) { const b = (el.type === 'text') ? { x: el.x - (el.w || 60) / 2, y: el.y - (el.h || 40) / 2, w: el.w || 60, h: el.h || 40 } : { x: el.x, y: el.y, w: el.w || 0, h: el.h || 0 }; if (b.x < MARGIN || b.y < MARGIN || (CW - (b.x + b.w)) < MARGIN || (CH - (b.y + b.h)) < MARGIN) { tight.push(el.text || el.iconId || '元素'); } } const pass = tight.length === 0; return { pass, margin: MARGIN, tightElements: tight, verdict: pass ? '所有元素均在安全区内,印刷裁切安全' : tight.length + ' 个元素贴近边缘(' + tight.join('、') + '),有被裁切风险', suggest: pass ? '无需调整' : '建议把主体元素内缩至安全区(距边缘 ≥ ' + MARGIN + 'px),预留出血' }; }, test: function () { const plan = HGB_Generator.generateVariant({ industry: HGB_Industries[0], brand: '印刷测试' }); return this.run({ plan }); } }, { id: 'format-choose', name: '导出格式推荐', category: 'export', emoji: '🧭', scene: '按使用场景推荐 LOGO 导出格式与尺寸', summary: '按用途(网页/印刷/应用图标/社交头像/视频)推荐最优导出格式(SVG/PNG/JPG)、尺寸、分辨率与背景策略,避免「一张 PNG 走天下」的质量损耗。', params: [ { name: 'usage', type: 'string', required: false, desc: '使用场景:web 网页 / print 印刷 / app 应用图标 / social 社交头像 / video 视频' } ], source: '自研(各平台规格映射)', run: function (args) { const usage = String(args.usage || 'web'); const MAP = { web: { format: 'SVG(主)+ PNG 512/1024', size: '512–1024px', dpi: '72', bg: '透明背景', note: '网页用 SVG 矢量最佳,PNG 用于兼容旧环境' }, print: { format: 'SVG / PDF(矢量)', size: 'A4 及以上', dpi: '300', bg: '含出血版 + 透明版各一份', note: '印刷必须矢量或 300dpi 位图,避免小图放大模糊' }, app: { format: 'PNG', size: '1024×1024', dpi: '72', bg: '不留透明(应用商店要求不透明底)', note: '系统自动圆角,主体需居中并预留约 8% 安全边距' }, social: { format: 'PNG', size: '400–1024px', dpi: '72', bg: '透明背景', note: '头像按圆形裁切展示,图形主体需居中避免切边' }, video: { format: 'PNG(带透明)', size: '1920×1080 或更大', dpi: '72', bg: '透明背景', note: '视频叠加层需透明 PNG,避免 JPG 黑/白底' } }; const hit = MAP[usage] || MAP.web; return { usage, usageCn: ({ web: '网页', print: '印刷', app: '应用图标', social: '社交头像', video: '视频' })[usage] || '网页', format: hit.format, size: hit.size, dpi: hit.dpi, bg: hit.bg, note: hit.note }; }, test: function () { return { web: this.run({ usage: 'web' }).format, print: this.run({ usage: 'print' }).dpi, app: this.run({ usage: 'app' }).bg }; } }, { id: 'file-naming', name: '交付文件命名', category: 'export', emoji: '🏷️', scene: '交付/导出文件的统一命名规范,避免重名与版本混乱', summary: '按「品牌_用途_规格_版本」生成统一文件命名规范(小写 + 连字符),输出各用途(logo/avatar/favicon)示例文件名与命名规则清单。', params: [ { name: 'brand', type: 'string', required: true, desc: '品牌名(自动转小写连字符)' }, { name: 'purpose', type: 'string', required: false, desc: '用途:logo/avatar/favicon/vi(默认 logo)' }, { name: 'version', type: 'string', required: false, desc: '版本号(默认 v1)' } ], source: '自研(交付文件命名规范)', run: function (args) { const raw = String(args.brand || 'brand').toLowerCase().replace(/[^\w-]/g, '-').replace(/-+/g, '-').replace(/^-|-$/g, ''); const brand = raw || 'brand'; const purpose = String(args.purpose || 'logo').toLowerCase(); const ver = String(args.version || 'v1'); const p = ['logo', 'avatar', 'favicon', 'vi'].includes(purpose) ? purpose : 'logo'; const date = new Date().toISOString().slice(0, 10).replace(/-/g, ''); const convention = brand + '-' + p + '-{规格}-' + ver; const examples = p === 'favicon' ? [brand + '-favicon-32-' + ver + '.png', brand + '-favicon-180-' + ver + '.png', brand + '-favicon-512-' + ver + '.png'] : (p === 'avatar' ? [brand + '-avatar-300-' + ver + '.png', brand + '-avatar-640-' + ver + '.png', brand + '-avatar-1024-' + ver + '.png'] : [brand + '-logo-main-' + ver + '.svg', brand + '-logo-reverse-' + ver + '.png', brand + '-logo-mono-' + ver + '.png']); return { brand, purpose: p, version: ver, date, convention, examples, rules: ['小写字母 + 连字符,禁止中文与空格', '「用途」段区分 logo / avatar / favicon / vi 交付物', '「规格」段标注尺寸(512 / 300)或版别(main / reverse / mono)', '「版本」段 v1 / v2…,迭代不覆盖旧版'], tip: '批量交付按「品牌_用途_规格_版本」归档目录,迭代导出时递增版本号,配合版本号联动规则避免同名覆盖' }; }, test: function () { const r = this.run({ brand: '远渡教育', purpose: 'logo', version: 'v2' }); return { convention: r.convention, examples: r.examples.length, rules: r.rules.length }; } } ]); })();