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

87 lines
3.6 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.
/**
* 🏠 emoji 头像 PNG 批量生成
* 从资源库 twemoji 源提取 house 表情彩色 SVG,
* 生成 10 个渐变背景圆形头像(1024×1024),用 Chrome headless 导出 PNG。
*
* 用法:node scripts/gen-emoji-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-emoji');
const CHROME = 'C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe';
// —— 1. 从资源库读取 twemoji 源,提取 house(🏠)彩色 SVG ——
global.window = global;
vm.runInThisContext(fs.readFileSync(path.join(ROOT, 'js', 'data', 'sources', 'twemoji.js'), 'utf8'), { filename: 'twemoji.js' });
const icons = window['HGB_Source_twemoji'].icons;
const house = icons.find(x => x.id === 'twemoji:house');
if (!house) { console.error('❌ 资源库未找到 twemoji:house'); process.exit(1); }
const houseBody = house.svg; // 24 坐标系的 g 内容(含 translate(0 0) scale(0.666…))
// —— 2. 10 个渐变背景(16 进制)——
const BG = [
{ from: '#667eea', to: '#764ba2' }, // 蓝紫
{ from: '#2193b0', to: '#6dd5ed' }, // 青蓝
{ from: '#11998e', to: '#38ef7d' }, // 绿
{ from: '#f7971e', to: '#ffd200' }, // 橙黄
{ from: '#ee9ca7', to: '#ffdde1' }, // 粉
{ from: '#cb2d3e', to: '#ef473a' }, // 红
{ from: '#41295a', to: '#2F0743' }, // 紫黑
{ from: '#1e3c72', to: '#2a5298' }, // 深蓝
{ from: '#f953c6', to: '#b91d73' }, // 玫红
{ from: '#0575e6', to: '#021B79' } // 靛蓝
];
// —— 3. 生成 HTML:1024×1024 圆形渐变底 + 🏠 居中(emoji 内容按 24 坐标缩放 22 → 528px)——
function buildHtml(from, to) {
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="${from}"/><stop offset="100%" stop-color="${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)"/>
<g transform="translate(512 512) scale(22) translate(-12 -12)">${houseBody}</g>
</svg>
</body></html>`;
}
// —— 4. 逐张导出 PNG ——
fs.mkdirSync(OUT_DIR, { recursive: true });
fs.mkdirSync(TMP_DIR, { recursive: true });
for (let i = 0; i < BG.length; 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(BG[i].from, BG[i].to), '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 ${BG[i].from} → ${BG[i].to}`);
} catch (e) {
console.error(`❌ agent-${idx}.png 失败:`, e.message.split('\n')[0]);
}
}
// 清理临时 HTML
fs.rmSync(TMP_DIR, { recursive: true, force: true });
console.log('\n🎉 完成 → output/agent-avatars-png/');