// Generate PNG icons for the Chrome extension import { writeFileSync, mkdirSync } from 'fs'; import { join, dirname } from 'path'; import { fileURLToPath } from 'url'; import zlib from 'zlib'; const __dirname = dirname(fileURLToPath(import.meta.url)); const iconsDir = join(__dirname, '..', 'src', 'icons'); mkdirSync(iconsDir, { recursive: true }); function crc32(buf) { var crc = 0xFFFFFFFF; for (var i = 0; i < buf.length; i++) { crc ^= buf[i]; for (var j = 0; j < 8; j++) { crc = (crc >>> 1) ^ (crc & 1 ? 0xEDB88320 : 0); } } return (crc ^ 0xFFFFFFFF) >>> 0; } function makeChunk(type, data) { var len = Buffer.alloc(4); len.writeUInt32BE(data.length, 0); var typeBuffer = Buffer.from(type, 'ascii'); var crcData = Buffer.concat([typeBuffer, data]); var crc = crc32(crcData); var crcBuf = Buffer.alloc(4); crcBuf.writeUInt32BE(crc, 0); return Buffer.concat([len, typeBuffer, data, crcBuf]); } function createPNG(width, height) { var signature = Buffer.from([137, 80, 78, 71, 13, 10, 26, 10]); var ihdrData = Buffer.alloc(13); ihdrData.writeUInt32BE(width, 0); ihdrData.writeUInt32BE(height, 4); ihdrData[8] = 8; ihdrData[9] = 2; ihdrData[10] = 0; ihdrData[11] = 0; ihdrData[12] = 0; var ihdr = makeChunk('IHDR', ihdrData); var rawData = []; var cx = width / 2, cy = height / 2; var maxDist = Math.sqrt(cx * cx + cy * cy); var innerR = Math.min(width, height) * 0.35; var handleR = Math.min(width, height) * 0.08; for (var y = 0; y < height; y++) { rawData.push(0); // filter byte for (var x = 0; x < width; x++) { var dist = Math.sqrt((x - cx) * (x - cx) + (y - cy) * (y - cy)); var t = dist / maxDist; // Background gradient: #667eea to #764ba2 var bgR = Math.round(102 * (1 - t) + 118 * t); var bgG = Math.round(126 * (1 - t) + 75 * t); var bgB = Math.round(234 * (1 - t) + 162 * t); var pr = bgR, pg = bgG, pb = bgB; // White circle (magnifying glass lens) if (dist < innerR) { pr = 255; pg = 255; pb = 255; // Inner dark ring (lens border) if (dist > innerR * 0.8) { pr = 80; pg = 80; pb = 120; } } // Handle (bottom-right diagonal) var handleStart = innerR * 0.9; var handleLen = maxDist * 0.5; var hx = x - cx, hy = y - cy; var proj = (hx + hy) / Math.sqrt(2); var perp = Math.abs(hx - hy) / Math.sqrt(2); if (proj > handleStart && proj < handleStart + handleLen && perp < handleR) { pr = 200; pg = 200; pb = 220; } rawData.push(pr, pg, pb); } } var deflated = zlib.deflateSync(Buffer.from(rawData)); var idat = makeChunk('IDAT', deflated); var iend = makeChunk('IEND', Buffer.alloc(0)); return Buffer.concat([signature, ihdr, idat, iend]); } var sizes = [16, 48, 128]; sizes.forEach(function (size) { var png = createPNG(size, size); var filepath = join(iconsDir, 'icon-' + size + '.png'); writeFileSync(filepath, png); console.log('Created ' + filepath + ' (' + png.length + ' bytes)'); }); console.log('Icons generated.');