import { deflateSync } from 'zlib' import { writeFileSync, mkdirSync } from 'fs' import { dirname, resolve } from 'path' import { fileURLToPath } from 'url' /** 生成一个简洁的托盘图标(粉色唱片盘),输出到 resources/tray.png */ const __dirname = dirname(fileURLToPath(import.meta.url)) const SIZE = 32 const cx = SIZE / 2 - 0.5 const cy = SIZE / 2 - 0.5 const rOuter = 15 const rHole = 4 function px(x, y) { const dx = x - cx const dy = y - cy const d = Math.sqrt(dx * dx + dy * dy) // 抗锯齿边缘 const edge = (r) => Math.max(0, Math.min(1, r - d + 0.5)) const inDisc = edge(rOuter) const inHole = edge(rHole) if (inDisc <= 0) return [0, 0, 0, 0] // 唱片主体粉色,中心孔洞白色 const pink = [255, 55, 95] const white = [255, 255, 255] const a = Math.round(255 * inDisc) if (inHole > 0) { const t = inHole return [ Math.round(pink[0] * (1 - t) + white[0] * t), Math.round(pink[1] * (1 - t) + white[1] * t), Math.round(pink[2] * (1 - t) + white[2] * t), a ] } return [pink[0], pink[1], pink[2], a] } // 构造原始 RGBA 扫描行(每行前置 filter 0) const raw = Buffer.alloc((SIZE * 4 + 1) * SIZE) let p = 0 for (let y = 0; y < SIZE; y++) { raw[p++] = 0 for (let x = 0; x < SIZE; x++) { const [r, g, b, a] = px(x, y) raw[p++] = r raw[p++] = g raw[p++] = b raw[p++] = a } } const crcTable = (() => { const t = [] for (let n = 0; n < 256; n++) { let c = n for (let k = 0; k < 8; k++) c = c & 1 ? 0xedb88320 ^ (c >>> 1) : c >>> 1 t[n] = c >>> 0 } return t })() function crc32(buf) { let c = 0xffffffff for (let i = 0; i < buf.length; i++) c = crcTable[(c ^ buf[i]) & 0xff] ^ (c >>> 8) return (c ^ 0xffffffff) >>> 0 } function chunk(type, data) { const len = Buffer.alloc(4) len.writeUInt32BE(data.length, 0) const typeBuf = Buffer.from(type, 'ascii') const body = Buffer.concat([typeBuf, data]) const crc = Buffer.alloc(4) crc.writeUInt32BE(crc32(body), 0) return Buffer.concat([len, body, crc]) } const sig = Buffer.from([137, 80, 78, 71, 13, 10, 26, 10]) const ihdr = Buffer.alloc(13) ihdr.writeUInt32BE(SIZE, 0) ihdr.writeUInt32BE(SIZE, 4) ihdr[8] = 8 // bit depth ihdr[9] = 6 // color type RGBA const png = Buffer.concat([ sig, chunk('IHDR', ihdr), chunk('IDAT', deflateSync(raw)), chunk('IEND', Buffer.alloc(0)) ]) const out = resolve(__dirname, '../resources/tray.png') mkdirSync(dirname(out), { recursive: true }) writeFileSync(out, png) console.log('wrote', out, png.length, 'bytes')