import puppeteer from "puppeteer-core"; import fs from "node:fs"; import path from "node:path"; import { fileURLToPath } from "node:url"; const here = path.dirname(fileURLToPath(import.meta.url)); const out = path.join(here, "..", "..", "services", "webmail"); const tile = fs.readFileSync(path.join(here, "logo.svg"), "utf8"), full = fs.readFileSync(path.join(here, "logo-full.svg"), "utf8"), safe = fs.readFileSync(path.join(here, "logo-safe.svg"), "utf8"); const browser = await puppeteer.launch({ executablePath: process.env.CHROME_PATH, headless: true, args: ["--no-sandbox"] }); const page = await browser.newPage(); async function png(svg, size, file, transparent) { await page.setViewport({ width: size, height: size, deviceScaleFactor: 1 }); await page.setContent(`${svg.replace('width="64" height="64"', `width="${size}" height="${size}"`)}`); await page.screenshot({ path: file, omitBackground: transparent }); } await png(full, 180, `${out}/src/app/apple-icon.png`, false); await png(tile, 192, `${out}/public/icons/icon-192.png`, true); await png(tile, 512, `${out}/public/icons/icon-512.png`, true); await png(safe, 512, `${out}/public/icons/maskable-512.png`, false); for (const s of [16, 32, 48]) await png(tile, s, path.join(here, `fav${s}.png`), true); await browser.close(); const imgs = [16, 32, 48].map((s) => ({ s, data: fs.readFileSync(path.join(here, `fav${s}.png`)) })); const head = Buffer.alloc(6); head.writeUInt16LE(1, 2); head.writeUInt16LE(imgs.length, 4); let offset = 6 + 16 * imgs.length; const dir = Buffer.concat(imgs.map(({ s, data }) => { const e = Buffer.alloc(16); e[0] = s; e[1] = s; e.writeUInt16LE(1, 4); e.writeUInt16LE(32, 6); e.writeUInt32LE(data.length, 8); e.writeUInt32LE(offset, 12); offset += data.length; return e; })); fs.writeFileSync(`${out}/src/app/favicon.ico`, Buffer.concat([head, dir, ...imgs.map((i) => i.data)])); console.log("icons done");