import fs from "node:fs"; import path from "node:path"; import process from "node:process"; import { PNG } from "pngjs"; const root = process.cwd(); const output = path.join(root, "build", "icon.ico"); const size = 256; const png = new PNG({ width: size, height: size }); const glyph = [ "0111000000", "1000100000", "1000100000", "1000100000", "1111100000", "1000100000", "1000100000", "1000100000", "1000100000", "1000100000" ]; function insideRoundedSquare(x, y, radius) { const clampX = Math.min(Math.max(x, radius), size - 1 - radius); const clampY = Math.min(Math.max(y, radius), size - 1 - radius); return (x - clampX) ** 2 + (y - clampY) ** 2 <= radius ** 2; } for (let y = 0; y < size; y += 1) { for (let x = 0; x < size; x += 1) { const index = (size * y + x) << 2; const visible = insideRoundedSquare(x, y, 34); const gradient = (x + y) / (2 * (size - 1)); png.data[index] = visible ? Math.round(37 + (30 - 37) * gradient) : 0; png.data[index + 1] = visible ? Math.round(99 + (58 - 99) * gradient) : 0; png.data[index + 2] = visible ? Math.round(235 + (138 - 235) * gradient) : 0; png.data[index + 3] = visible ? 255 : 0; if (visible) { const glyphX = Math.round((x - 78) / 10); const glyphY = Math.round((y - 68) / 12); if (glyphY >= 0 && glyphY < glyph.length && glyphX >= 0 && glyphX < glyph[glyphY].length && glyph[glyphY][glyphX] === "1") { png.data[index] = 255; png.data[index + 1] = 255; png.data[index + 2] = 255; png.data[index + 3] = 255; } } } } const chunks = []; png.pack() .on("data", (chunk) => chunks.push(chunk)) .on("end", () => { const image = Buffer.concat(chunks); const directory = Buffer.alloc(6); directory.writeUInt16LE(0, 0); directory.writeUInt16LE(1, 2); directory.writeUInt16LE(1, 4); const entry = Buffer.alloc(16); entry[0] = 0; entry[1] = 0; entry[2] = 0; entry[3] = 0; entry.writeUInt16LE(1, 4); entry.writeUInt16LE(32, 6); entry.writeUInt32LE(image.length, 8); entry.writeUInt32LE(22, 12); fs.mkdirSync(path.dirname(output), { recursive: true }); fs.writeFileSync(output, Buffer.concat([directory, entry, image])); console.log(`[icon] generated ${output} (${image.length + 22} bytes)`); }) .on("error", (error) => { console.error(error); process.exitCode = 1; });