// scripts/generate-icons.mjs // build/icon.svg → build/icon.png(1024) + build/icon.ico(멀티사이즈) // 사용: node apps/desktop/scripts/generate-icons.mjs // 의존: sharp (모노레포 루트 node_modules), Pillow는 불필요(ico도 sharp 산출 PNG로 조립) import sharp from 'sharp' import { writeFileSync } from 'node:fs' import { fileURLToPath } from 'node:url' import { dirname, join } from 'node:path' const buildDir = join(dirname(fileURLToPath(import.meta.url)), '..', 'build') const SVG = join(buildDir, 'icon.svg') /** ICO 컨테이너 조립 — PNG 임베드 방식 (Vista+ 표준, 모든 현대 Windows 지원) */ 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 = [] let offset = 6 + 16 * count for (const { size, buf } of pngs) { const e = Buffer.alloc(16) e.writeUInt8(size >= 256 ? 0 : size, 0) // width (0=256) e.writeUInt8(size >= 256 ? 0 : size, 1) // height e.writeUInt8(0, 2) // palette e.writeUInt8(0, 3) // reserved e.writeUInt16LE(1, 4) // planes e.writeUInt16LE(32, 6) // bpp e.writeUInt32LE(buf.length, 8) e.writeUInt32LE(offset, 12) entries.push(e) offset += buf.length } return Buffer.concat([header, ...entries, ...pngs.map((p) => p.buf)]) } async function render(size) { return sharp(SVG, { density: (72 * size) / 1024 }) .resize(size, size) .png() .toBuffer() } // 1) 마스터 PNG (electron-builder가 mac icns/linux 아이콘 자동 생성에 사용) writeFileSync(join(buildDir, 'icon.png'), await render(1024)) console.log('build/icon.png (1024)') // 2) Windows ICO — 표준 사이즈 세트 const icoSizes = [256, 128, 64, 48, 32, 16] const pngs = [] for (const size of icoSizes) { pngs.push({ size, buf: await render(size) }) } writeFileSync(join(buildDir, 'icon.ico'), buildIco(pngs)) console.log(`build/icon.ico (${icoSizes.join('/')})`)