import { deflateSync } from 'zlib' import { nativeImage, type NativeImage } from 'electron' // CRC32 table polynomial used by PNG. function crc32(buf: Buffer): number { let crc = 0xffffffff for (const b of buf) { crc ^= b for (let i = 0; i < 8; i++) crc = crc & 1 ? (crc >>> 1) ^ 0xedb88320 : crc >>> 1 } return (crc ^ 0xffffffff) >>> 0 } function pngChunk(type: string, data: Buffer): Buffer { const t = Buffer.from(type, 'ascii') const len = Buffer.alloc(4) len.writeUInt32BE(data.length) const crc = Buffer.alloc(4) crc.writeUInt32BE(crc32(Buffer.concat([t, data]))) return Buffer.concat([len, t, data, crc]) } /** * Build a 16×16 RGBA PNG containing a solid-colour filled circle. Used for the * Windows taskbar overlay badge. No external deps — pure Node.js (Buffer + zlib). */ function makeDotPng(r: number, g: number, b: number): NativeImage { const W = 16, H = 16 const px = Buffer.alloc(W * H * 4, 0) // transparent bg const cx = W / 2, cy = H / 2, rad = W / 2 - 1.5 for (let y = 0; y < H; y++) { for (let x = 0; x < W; x++) { const dx = x + 0.5 - cx, dy = y + 0.5 - cy if (dx * dx + dy * dy <= rad * rad) { const i = (y * W + x) * 4 px[i] = r px[i + 1] = g px[i + 2] = b px[i + 3] = 255 } } } // PNG: IHDR (8-bit RGBA, no interlace), filter-0 rows, deflated IDAT, IEND. const ihdr = Buffer.alloc(13) ihdr.writeUInt32BE(W, 0) ihdr.writeUInt32BE(H, 4) ihdr[8] = 8 // bit depth ihdr[9] = 6 // colour type: RGBA const rows = Buffer.alloc(H * (1 + W * 4)) for (let y = 0; y < H; y++) { rows[y * (1 + W * 4)] = 0 // filter type: None px.copy(rows, y * (1 + W * 4) + 1, y * W * 4, (y + 1) * W * 4) } const sig = Buffer.from([137, 80, 78, 71, 13, 10, 26, 10]) const png = Buffer.concat([ sig, pngChunk('IHDR', ihdr), pngChunk('IDAT', deflateSync(rows)), pngChunk('IEND', Buffer.alloc(0)) ]) return nativeImage.createFromBuffer(png) } // Lazy-initialised singletons — created on first use so this module is safe to // import before the app is ready (nativeImage.createFromBuffer is fine post-ready). let activeBadge: NativeImage | null = null let errorBadge: NativeImage | null = null /** Green dot badge for the taskbar overlay — shown when downloads are active. */ export function getActiveBadge(): NativeImage { if (!activeBadge) activeBadge = makeDotPng(58, 185, 108) // #3ab96c return activeBadge } /** Red dot badge for the taskbar overlay — shown when a download has errored. */ export function getErrorBadge(): NativeImage { if (!errorBadge) errorBadge = makeDotPng(217, 48, 37) // #d93025 return errorBadge }