Files

68 lines
2.0 KiB
JavaScript

const fs = require('fs');
const path = require('path');
const zlib = require('zlib');
function crc32(buf) {
let c = ~0;
const table = Array.from({ length: 256 }, (_, n) => {
let c = n;
for (let k = 0; k < 8; k++) {
c = c & 1 ? 0xEDB88320 ^ (c >>> 1) : c >>> 1;
}
return c >>> 0;
});
for (let i = 0; i < buf.length; i++) {
c = table[(c ^ buf[i]) & 0xff] ^ (c >>> 1);
}
return ~(c >>> 0) >>> 0;
}
function pngChunk(type, data) {
const typeBuf = Buffer.from(type, 'ascii');
const buf = Buffer.concat([typeBuf, data]);
const crc = crc32(buf);
const len = Buffer.allocUnsafe(4);
len.writeUInt32BE(data.length, 0);
const crcBuf = Buffer.allocUnsafe(4);
crcBuf.writeUInt32BE(crc, 0);
return Buffer.concat([len, buf, crcBuf]);
}
function createSolidPng(size, r, g, b) {
const header = Buffer.from([0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A]);
const ihdr = Buffer.allocUnsafe(13);
ihdr.writeUInt32BE(size, 0); // width
ihdr.writeUInt32BE(size, 4); // height
ihdr[8] = 8; // bit depth
ihdr[9] = 2; // color type (RGB)
ihdr[10] = 0; // compression
ihdr[11] = 0; // filter method
ihdr[12] = 0; // interlace
const row = Buffer.allocUnsafe(1 + size * 3);
row[0] = 0; // filter byte
for (let x = 0; x < size; x++) {
row[1 + x * 3] = r;
row[1 + x * 3 + 1] = g;
row[1 + x * 3 + 2] = b;
}
const rawData = Buffer.concat(Array.from({ length: size }, () => row));
const idat = zlib.deflateSync(rawData, { level: 9 });
return Buffer.concat([header, pngChunk('IHDR', ihdr), pngChunk('IDAT', idat), pngChunk('IEND', Buffer.alloc(0))]);
}
const dir = path.join(__dirname, 'public', 'icons');
fs.mkdirSync(dir, { recursive: true });
const sizes = [16, 48, 128];
const colors = { 16: [59, 130, 246], 48: [59, 130, 246], 128: [59, 130, 246] };
for (const size of sizes) {
const [r, g, b] = colors[size];
const png = createSolidPng(size, r, g, b);
fs.writeFileSync(path.join(dir, `icon${size}.png`), png);
console.log(`Generated icon${size}.png`);
}