104 lines
3.6 KiB
JavaScript
104 lines
3.6 KiB
JavaScript
|
|
// Generate PWA icons
|
||
|
|
const fs = require('fs');
|
||
|
|
const path = require('path');
|
||
|
|
|
||
|
|
const sizes = [192, 512];
|
||
|
|
|
||
|
|
async function main() {
|
||
|
|
try {
|
||
|
|
const sharp = require('sharp');
|
||
|
|
for (const size of sizes) {
|
||
|
|
const svg = `<svg xmlns="http://www.w3.org/2000/svg" width="${size}" height="${size}">
|
||
|
|
<rect width="${size}" height="${size}" rx="${size * 0.1667}" fill="#0891b2"/>
|
||
|
|
<text x="${size / 2}" y="${size * 0.7}" font-family="system-ui, sans-serif" font-size="${size * 0.6}" font-weight="bold" fill="white" text-anchor="middle">M</text>
|
||
|
|
</svg>`;
|
||
|
|
await sharp(Buffer.from(svg)).png().toFile(path.join(__dirname, '..', 'public', `icon-${size}.png`));
|
||
|
|
console.log(`Created icon-${size}.png`);
|
||
|
|
}
|
||
|
|
} catch {
|
||
|
|
// sharp not available, create minimal valid PNG manually
|
||
|
|
console.log('sharp not available, creating minimal PNGs');
|
||
|
|
// Minimal 1x1 blue PNG
|
||
|
|
for (const size of [192, 512]) {
|
||
|
|
// Create a minimal valid PNG - will just be a solid blue square
|
||
|
|
// PNG signature
|
||
|
|
const sig = Buffer.from([137, 80, 78, 71, 13, 10, 26, 10]);
|
||
|
|
// IHDR chunk
|
||
|
|
const ihdrData = Buffer.alloc(13);
|
||
|
|
ihdrData.writeUInt32BE(size, 0); // width
|
||
|
|
ihdrData.writeUInt32BE(size, 4); // height
|
||
|
|
ihdrData[8] = 8; // bit depth
|
||
|
|
ihdrData[9] = 2; // color type (RGB)
|
||
|
|
ihdrData[10] = 0; // compression
|
||
|
|
ihdrData[11] = 0; // filter
|
||
|
|
ihdrData[12] = 0; // interlace
|
||
|
|
|
||
|
|
const ihdrLen = Buffer.alloc(4);
|
||
|
|
ihdrLen.writeUInt32BE(13);
|
||
|
|
const ihdrType = Buffer.from('IHDR');
|
||
|
|
const ihdrCRC = crc32(Buffer.concat([ihdrType, ihdrData]));
|
||
|
|
const ihdrCRCbuf = Buffer.alloc(4);
|
||
|
|
ihdrCRCbuf.writeUInt32BE(ihdrCRC);
|
||
|
|
|
||
|
|
// IDAT - raw filtered image data (each row: filter byte 0 + RGB pixels)
|
||
|
|
const rowSize = 1 + size * 3; // filter byte + RGB per pixel
|
||
|
|
const rawData = Buffer.alloc(rowSize * size);
|
||
|
|
for (let y = 0; y < size; y++) {
|
||
|
|
rawData[y * rowSize] = 0; // no filter
|
||
|
|
for (let x = 0; x < size; x++) {
|
||
|
|
const offset = y * rowSize + 1 + x * 3;
|
||
|
|
rawData[offset] = 8; // R
|
||
|
|
rawData[offset+1] = 145; // G
|
||
|
|
rawData[offset+2] = 178; // B
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// Zlib compress
|
||
|
|
const zlib = require('zlib');
|
||
|
|
const compressed = zlib.deflateSync(rawData);
|
||
|
|
|
||
|
|
const idatLen = Buffer.alloc(4);
|
||
|
|
idatLen.writeUInt32BE(compressed.length);
|
||
|
|
const idatType = Buffer.from('IDAT');
|
||
|
|
const idatCRC = crc32(Buffer.concat([idatType, compressed]));
|
||
|
|
const idatCRCbuf = Buffer.alloc(4);
|
||
|
|
idatCRCbuf.writeUInt32BE(idatCRC);
|
||
|
|
|
||
|
|
// IEND
|
||
|
|
const iendLen = Buffer.alloc(4);
|
||
|
|
iendLen.writeUInt32BE(0);
|
||
|
|
const iendType = Buffer.from('IEND');
|
||
|
|
const iendCRC = crc32(iendType);
|
||
|
|
const iendCRCbuf = Buffer.alloc(4);
|
||
|
|
iendCRCbuf.writeUInt32BE(iendCRC);
|
||
|
|
|
||
|
|
const png = Buffer.concat([
|
||
|
|
sig, ihdrLen, ihdrType, ihdrData, ihdrCRCbuf,
|
||
|
|
idatLen, idatType, compressed, idatCRCbuf,
|
||
|
|
iendLen, iendType, iendCRCbuf
|
||
|
|
]);
|
||
|
|
|
||
|
|
fs.writeFileSync(path.join(__dirname, '..', 'public', `icon-${size}.png`), png);
|
||
|
|
console.log(`Created icon-${size}.png (minimal)`);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
function crc32(buf) {
|
||
|
|
let crc = 0xFFFFFFFF;
|
||
|
|
const table = new Uint32Array(256);
|
||
|
|
for (let i = 0; i < 256; i++) {
|
||
|
|
let c = i;
|
||
|
|
for (let j = 0; j < 8; j++) {
|
||
|
|
c = (c & 1) ? (0xEDB88320 ^ (c >>> 1)) : (c >>> 1);
|
||
|
|
}
|
||
|
|
table[i] = c;
|
||
|
|
}
|
||
|
|
for (let i = 0; i < buf.length; i++) {
|
||
|
|
crc = table[(crc ^ buf[i]) & 0xFF] ^ (crc >>> 8);
|
||
|
|
}
|
||
|
|
return (crc ^ 0xFFFFFFFF) >>> 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
main();
|