// 生成应用图标(build/icon.ico + build/icon.png): // npx electron scripts/make-icons.cjs // 用 Electron 离屏渲染 build/icon.svg(居中于方形画布、留 9% 边距), // 输出多尺寸 PNG 并打包为 PNG 内嵌式 ICO(Vista+ 支持)。 const { app, BrowserWindow } = require('electron') const { readFileSync, writeFileSync } = require('node:fs') const { join } = require('node:path') app.commandLine.appendSwitch('disable-gpu') const SIZES = [16, 24, 32, 48, 64, 128, 256] const ROOT = join(__dirname, '..') const sleep = (ms) => new Promise((r) => setTimeout(r, ms)) /** PNG 内嵌式 ICO 打包 */ function buildIco(pngs) { const count = pngs.length const header = Buffer.alloc(6) header.writeUInt16LE(0, 0) // reserved header.writeUInt16LE(1, 2) // type: icon header.writeUInt16LE(count, 4) const entries = Buffer.alloc(16 * count) const blobs = [] let offset = 6 + 16 * count pngs.forEach((png, i) => { const size = png.size entries.writeUInt8(size >= 256 ? 0 : size, i * 16 + 0) // width entries.writeUInt8(size >= 256 ? 0 : size, i * 16 + 1) // height entries.writeUInt8(0, i * 16 + 2) // palette entries.writeUInt8(0, i * 16 + 3) // reserved entries.writeUInt16LE(1, i * 16 + 4) // planes entries.writeUInt16LE(32, i * 16 + 6) // bpp entries.writeUInt32LE(png.data.length, i * 16 + 8) entries.writeUInt32LE(offset, i * 16 + 12) offset += png.data.length blobs.push(png.data) }) return Buffer.concat([header, entries, ...blobs]) } async function renderSize(win, svgDataUrl, size) { await win.loadURL( 'data:text/html,' + encodeURIComponent( `` + `
` + `` + `
` ) ) await sleep(350) const image = await win.webContents.capturePage({ x: 0, y: 0, width: size, height: size }) return image.toPNG() } async function run() { const svg = readFileSync(join(ROOT, 'build', 'icon.svg'), 'utf8') const svgDataUrl = 'data:image/svg+xml;base64,' + Buffer.from(svg, 'utf8').toString('base64') const win = new BrowserWindow({ width: 256, height: 256, show: false, frame: false, transparent: true, webPreferences: { paintWhenInitiallyHidden: true, offscreen: true } }) const pngs = [] for (const size of SIZES) { await win.setSize ? win.setSize(size, size) : null const png = await renderSize(win, svgDataUrl, size) pngs.push({ size, data: png }) console.log('rendered', size, `${png.length}B`) } writeFileSync(join(ROOT, 'build', 'icon.png'), pngs.find((p) => p.size === 256).data) writeFileSync(join(ROOT, 'build', 'icon.ico'), buildIco(pngs)) console.log('written build/icon.ico & build/icon.png') app.exit(0) } app.whenReady().then(run).catch((err) => { console.error(err) app.exit(1) })