97 lines
3.0 KiB
JavaScript
97 lines
3.0 KiB
JavaScript
// 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.');
|