73 lines
2.8 KiB
JavaScript
73 lines
2.8 KiB
JavaScript
/**
|
||
* 🖼️ 14 风格 × 100 = 1400 个 透明底 PNG 渲染脚本(512×512)
|
||
* 读取 output/agent-avatars-png/avatars/{style}/{file}.svg,
|
||
* Chrome headless 截图 → 透明背景 PNG(SVG 自带圆底,外部透明)。
|
||
*
|
||
* 用法:node scripts/gen-avatars-png.js
|
||
*/
|
||
'use strict';
|
||
const fs = require('fs');
|
||
const path = require('path');
|
||
const { spawn } = require('child_process');
|
||
|
||
const ROOT = path.resolve(__dirname, '..');
|
||
const SVG_ROOT = path.join(ROOT, 'output', 'agent-avatars-png', 'avatars');
|
||
const TMP_DIR = path.join(ROOT, 'output', '.tmp-av');
|
||
const CHROME = 'C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe';
|
||
const SIZE = 512;
|
||
|
||
// —— 1. 收集全部 SVG 文件 ——
|
||
const files = [];
|
||
for (const dir of fs.readdirSync(SVG_ROOT, { withFileTypes: true })) {
|
||
if (!dir.isDirectory()) continue;
|
||
for (const f of fs.readdirSync(path.join(SVG_ROOT, dir.name))) {
|
||
if (f.endsWith('.svg')) files.push(path.join(dir.name, f));
|
||
}
|
||
}
|
||
files.sort();
|
||
console.log('📦 待渲染 SVG:' + files.length + ' 个');
|
||
|
||
// —— 2. 生成 HTML(透明背景 + SVG 居中,放大到 SIZE)——
|
||
fs.mkdirSync(TMP_DIR, { recursive: true });
|
||
const jobs = files.map((rel, i) => {
|
||
const svg = fs.readFileSync(path.join(SVG_ROOT, rel), 'utf8');
|
||
const html = `<!DOCTYPE html><html><head><meta charset="utf-8">
|
||
<style>html,body{margin:0;padding:0;width:${SIZE}px;height:${SIZE}px;overflow:hidden;background:transparent}
|
||
.wrap{width:${SIZE}px;height:${SIZE}px;display:flex;align-items:center;justify-content:center}</style>
|
||
</head><body><div class="wrap">${svg.replace('<svg ', '<svg width="' + SIZE + '" height="' + SIZE + '" ')}</div></body></html>`;
|
||
const hf = path.join(TMP_DIR, 'a' + i + '.html');
|
||
fs.writeFileSync(hf, html, 'utf8');
|
||
return { hf, out: path.join(SVG_ROOT, rel.replace(/\.svg$/, '.png')) };
|
||
});
|
||
|
||
// —— 3. 并发截图(透明底)——
|
||
function shot(job) {
|
||
return new Promise((res) => {
|
||
const p = spawn(CHROME, [
|
||
'--headless=new', '--disable-gpu', '--hide-scrollbars',
|
||
'--default-background-color=00000000',
|
||
'--force-device-scale-factor=1',
|
||
'--window-size=' + SIZE + ',' + SIZE, '--virtual-time-budget=600',
|
||
'--screenshot=' + job.out,
|
||
'file:///' + job.hf.replace(/\\/g, '/')
|
||
], { stdio: 'ignore' });
|
||
p.on('close', () => res());
|
||
p.on('error', () => res());
|
||
});
|
||
}
|
||
|
||
(async () => {
|
||
let done = 0, t0 = Date.now();
|
||
const CONC = 8;
|
||
for (let s = 0; s < jobs.length; s += CONC) {
|
||
const batch = jobs.slice(s, s + CONC);
|
||
await Promise.all(batch.map(shot));
|
||
done += batch.length;
|
||
if (done % 200 === 0 || done === jobs.length) {
|
||
console.log(`⏳ ${done}/${jobs.length} ${((Date.now() - t0) / 1000).toFixed(1)}s`);
|
||
}
|
||
}
|
||
fs.rmSync(TMP_DIR, { recursive: true, force: true });
|
||
console.log('🎉 完成 → 透明底 PNG(512×512),与 SVG 同目录');
|
||
})();
|