Files
drawlogo/scripts/gen-icon-avatars-png.js
T

82 lines
3.5 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* 🎯 简洁科技感头像 PNG —— 从资源库直接挑 10 个 lucide 线性图标
* 10 个图标:bot / brain-circuit / cpu / sparkles / satellite / radar /
* circuit-board / atom / terminal / rocket
* 统一深蓝渐变圆底 + 白色线性图标 + 亮蓝细环,Chrome headless 导出 1024×1024 PNG。
*
* 用法:node scripts/gen-icon-avatars-png.js
*/
'use strict';
const fs = require('fs');
const path = require('path');
const vm = require('vm');
const { execFileSync } = require('child_process');
const ROOT = path.resolve(__dirname, '..');
const OUT_DIR = path.join(ROOT, 'output', 'agent-avatars-png');
const TMP_DIR = path.join(ROOT, 'output', '.tmp-icons');
const CHROME = 'C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe';
// —— 1. 加载资源库 lucide 源 ——
global.window = global;
const lucideFile = path.join(ROOT, 'js', 'data', 'sources', 'lucide.js');
vm.runInThisContext(fs.readFileSync(lucideFile, 'utf8'), { filename: lucideFile });
const lucideIcons = window['HGB_Source_lucide'].icons;
// —— 2. 挑选 10 个科技感图标(按名称匹配,保证存在)——
const PICK = ['bot', 'brain-circuit', 'cpu', 'sparkles', 'satellite', 'radar', 'circuit-board', 'atom', 'terminal', 'rocket'];
const picked = PICK.map(name => {
const icon = lucideIcons.find(x => x.name === name);
if (!icon) { console.error('❌ 资源库未找到 lucide:' + name); process.exit(1); }
return { id: icon.id, name, body: icon.svg };
});
const BG_FROM = '#0b1220', BG_TO = '#16294a';
const RING = '#3b82f6';
const S = 24; // lucide 画布 24
const ZOOM = 20; // 放大到 480px
function buildHtml(body) {
return `<!DOCTYPE html>
<html><head><meta charset="utf-8">
<style>html,body{margin:0;padding:0;width:1024px;height:1024px;overflow:hidden;background:transparent}</style>
</head><body>
<svg xmlns="http://www.w3.org/2000/svg" width="1024" height="1024" viewBox="0 0 1024 1024">
<defs>
<linearGradient id="bg" x1="0" y1="0" x2="1" y2="1">
<stop offset="0%" stop-color="${BG_FROM}"/><stop offset="100%" stop-color="${BG_TO}"/>
</linearGradient>
<clipPath id="circle"><circle cx="512" cy="512" r="512"/></clipPath>
</defs>
<rect width="1024" height="1024" fill="url(#bg)" clip-path="url(#circle)"/>
<circle cx="512" cy="512" r="452" fill="none" stroke="${RING}" stroke-width="5" opacity=".45"/>
<g transform="translate(512 512) scale(${ZOOM}) translate(${-S / 2} ${-S / 2})"
fill="none" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">${body}</g>
</svg>
</body></html>`;
}
// —— 3. 导出 PNG ——
fs.mkdirSync(OUT_DIR, { recursive: true });
fs.mkdirSync(TMP_DIR, { recursive: true });
picked.forEach((p, i) => {
const idx = String(i + 1).padStart(2, '0');
const htmlFile = path.join(TMP_DIR, `avatar-${idx}.html`);
const pngFile = path.join(OUT_DIR, `agent-${idx}.png`);
fs.writeFileSync(htmlFile, buildHtml(p.body), 'utf8');
try {
execFileSync(CHROME, [
'--headless=new', '--disable-gpu', '--hide-scrollbars',
'--force-device-scale-factor=1', '--default-background-color=00000000',
'--window-size=1024,1024', '--virtual-time-budget=1000',
`--screenshot=${pngFile}`,
'file:///' + htmlFile.replace(/\\/g, '/')
], { stdio: 'pipe' });
console.log(`✅ agent-${idx}.png ← lucide:${p.name}`);
} catch (e) {
console.error(`❌ agent-${idx}.png 失败:`, e.message.split('\n')[0]);
}
});
fs.rmSync(TMP_DIR, { recursive: true, force: true });
console.log('\n🎉 完成 → output/agent-avatars-png/');