import sharp from 'sharp' import { readFileSync } from 'fs' import { resolve, dirname } from 'path' import { fileURLToPath } from 'url' const __dirname = dirname(fileURLToPath(import.meta.url)) const publicDir = resolve(__dirname, '../public') // og-image: SVG → PNG 1200×630 const svgBuffer = readFileSync(resolve(publicDir, 'og-image.svg')) await sharp(svgBuffer) .resize(1200, 630) .png({ quality: 90 }) .toFile(resolve(publicDir, 'og-image.png')) console.log('✓ og-image.png (1200×630)') // apple-touch-icon: logo.png → 180×180 await sharp(resolve(publicDir, 'logo.png')) .resize(180, 180, { fit: 'contain', background: { r: 255, g: 255, b: 255, alpha: 1 } }) .png() .toFile(resolve(publicDir, 'apple-touch-icon.png')) console.log('✓ apple-touch-icon.png (180×180)') // favicon.ico: logo.png → multi-size ICO (16, 32, 48) import { writeFileSync } from 'fs' const icoSizes = [16, 32, 48] const pngBuffers = await Promise.all( icoSizes.map(size => sharp(resolve(publicDir, 'logo.png')) .resize(size, size, { fit: 'contain', background: { r: 0, g: 0, b: 0, alpha: 0 } }) .png() .toBuffer() ) ) // Build ICO: header + directory + image data const count = icoSizes.length const headerSize = 6 const dirEntrySize = 16 const dirSize = count * dirEntrySize let offset = headerSize + dirSize const header = Buffer.alloc(headerSize) header.writeUInt16LE(0, 0) // reserved header.writeUInt16LE(1, 2) // type: 1 = ICO header.writeUInt16LE(count, 4) const dirs = [] for (let i = 0; i < count; i++) { const dir = Buffer.alloc(dirEntrySize) const size = icoSizes[i] dir.writeUInt8(size === 256 ? 0 : size, 0) // width dir.writeUInt8(size === 256 ? 0 : size, 1) // height dir.writeUInt8(0, 2) // color count dir.writeUInt8(0, 3) // reserved dir.writeUInt16LE(1, 4) // color planes dir.writeUInt16LE(32, 6) // bits per pixel dir.writeUInt32LE(pngBuffers[i].length, 8) dir.writeUInt32LE(offset, 12) offset += pngBuffers[i].length dirs.push(dir) } const ico = Buffer.concat([header, ...dirs, ...pngBuffers]) writeFileSync(resolve(publicDir, 'favicon.ico'), ico) console.log('✓ favicon.ico (16×16, 32×32, 48×48)')