/** * Aggressively compresses all photos in public/assets/photos/ to max 1280px * and quality 70 using sharp. Target: all files under 200KB. */ import sharp from 'sharp'; import { readdir, stat } from 'fs/promises'; import { join } from 'path'; const PHOTOS_DIR = 'public/assets/photos'; const MAX_WIDTH = 1280; const QUALITY = 70; const MAX_BYTES = 200_000; const files = await readdir(PHOTOS_DIR); const imageFiles = files.filter(f => /\.(jpg|jpeg|JPG|JPEG)$/i.test(f)); let compressed = 0; let skipped = 0; for (const file of imageFiles) { const fullPath = join(PHOTOS_DIR, file); const { size } = await stat(fullPath); if (size <= MAX_BYTES) { skipped++; continue; } console.log(`Compressing: ${file} (${Math.round(size / 1024)}KB)`); try { const buf = await sharp(fullPath) .rotate() // auto-orient from EXIF .resize({ width: MAX_WIDTH, withoutEnlargement: true }) .jpeg({ quality: QUALITY, progressive: true, mozjpeg: true }) .toBuffer(); await sharp(buf).toFile(fullPath); const afterSize = (await stat(fullPath)).size; console.log(` → ${Math.round(afterSize / 1024)}KB (saved ${Math.round((size - afterSize) / 1024)}KB)`); compressed++; } catch (err) { console.error(` ✗ Failed: ${err.message}`); } } console.log(`\nDone: ${compressed} compressed, ${skipped} already small.`);