Files
inkreach-agent/apps/desktop/scripts/make-icons.cjs
T
Rick Ye a5951849c8 v0.6.0: beautifului 整合 + 会话/工作区/队列/权限/命令/附件全链路
- beautifului.dev 组件直连:Sidebar Nav、Tool Chips、Approval Card(抽屉化)、Streaming/Thinking、Code Block、Selection Actions、Prompt Bar、Search
2026-09-06 09:57:14 +08:00

88 lines
3.0 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.
// 生成应用图标(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(
`<!doctype html><html><body style="margin:0;background:transparent">` +
`<div style="display:flex;align-items:center;justify-content:center;width:${size}px;height:${size}px">` +
`<img src="${svgDataUrl}" style="width:${Math.round(size * 0.86)}px;height:auto;display:block"/>` +
`</div></body></html>`
)
)
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)
})