import sharp from "sharp"; import { existsSync } from "fs"; import { join } from "path"; const SRC = "assets/logos/source"; const OUT = "assets/logos"; const SIZE = 128; const ICON_W = 56; const ICON_H = 96; const sources = [ ["hourglass-mint-full.png", "00-full"], ["hourglass-mint-25pct.png", "01-25pct"], ["hourglass-mint-15pct.png", "02-15pct"], ["hourglass-mint-3grains.png", "03-3grains"], ["hourglass-mint-1grain.png", "04-1grain"], ]; async function normalize(input, name) { const pipeline = sharp(input).ensureAlpha().trim({ threshold: 12 }); const trimmed = await pipeline.toBuffer(); const meta = await sharp(trimmed).metadata(); const icon = await sharp(trimmed) .resize(ICON_W, ICON_H, { fit: "contain", background: { r: 0, g: 0, b: 0, alpha: 0 } }) .extend({ top: Math.floor((SIZE - ICON_H) / 2), bottom: Math.ceil((SIZE - ICON_H) / 2), left: Math.floor((SIZE - ICON_W) / 2), right: Math.ceil((SIZE - ICON_W) / 2), background: { r: 0, g: 0, b: 0, alpha: 1 }, }) .flatten({ background: { r: 0, g: 0, b: 0 } }) .png() .toBuffer(); await sharp(icon).resize(128, 128).toFile(join(OUT, `${name}-128.png`)); await sharp(icon).resize(64, 64).toFile(join(OUT, `${name}-64.png`)); console.log(`${name}: ${meta.width}x${meta.height} → ${ICON_W}x${ICON_H} → 64/128px`); } for (const [file, name] of sources) { const path = join(SRC, file); if (!existsSync(path)) { console.warn("skip missing", path); continue; } await normalize(path, name); }