import sharp from 'sharp'; import { readdir, mkdir } from 'fs/promises'; import { join, dirname, basename, extname } from 'path'; import { fileURLToPath } from 'url'; import { existsSync } from 'fs'; const __filename = fileURLToPath(import.meta.url); const __dirname = dirname(__filename); // Mehr Größen für bessere Mobile-Unterstützung const SIZES = [200, 300, 400, 600, 800, 1200]; const INPUT_DIR = join(__dirname, '../source-images/projects'); const OUTPUT_DIR = join(__dirname, '../public/images/projects'); async function processImage(inputPath, projectSlug) { const filename = basename(inputPath, extname(inputPath)); const ext = extname(inputPath).toLowerCase(); if (!['.jpg', '.jpeg', '.png', '.webp'].includes(ext)) { return; } const outputDir = join(OUTPUT_DIR, projectSlug); await mkdir(outputDir, { recursive: true }); console.log(`Processing: ${projectSlug}/${filename}${ext}`); // Optimierte Originalversion (cover.jpg) const originalOutputPath = join(outputDir, `${filename}.jpg`); try { await sharp(inputPath) .jpeg({ quality: 85, progressive: true }) .toFile(originalOutputPath); console.log(` Created: ${filename}.jpg (optimized original)`); } catch (error) { console.error(` Error creating optimized original:`, error.message); } // JPG-Versionen in verschiedenen Größen for (const width of SIZES) { const outputFilename = `${filename}-${width}w.jpg`; const outputPath = join(outputDir, outputFilename); try { await sharp(inputPath) .resize(width, null, { withoutEnlargement: true, fit: 'inside' }) .jpeg({ quality: 80, progressive: true }) .toFile(outputPath); console.log(` Created: ${outputFilename}`); } catch (error) { console.error(` Error creating ${outputFilename}:`, error.message); } } // WebP-Versionen in verschiedenen Größen for (const width of SIZES) { const webpFilename = `${filename}-${width}w.webp`; const webpPath = join(outputDir, webpFilename); try { await sharp(inputPath) .resize(width, null, { withoutEnlargement: true, fit: 'inside' }) .webp({ quality: 75 }) .toFile(webpPath); console.log(` Created: ${webpFilename}`); } catch (error) { console.error(` Error creating ${webpFilename}:`, error.message); } } // Volle WebP-Version const webpFullPath = join(outputDir, `${filename}.webp`); try { await sharp(inputPath) .webp({ quality: 80 }) .toFile(webpFullPath); console.log(` Created: ${filename}.webp`); } catch (error) { console.error(` Error creating full WebP:`, error.message); } } async function processDirectory(dirPath) { if (!existsSync(dirPath)) { console.error(`Error: Source directory not found: ${dirPath}`); console.log('\nPlease ensure original images are placed in:'); console.log(' source-images/projects//cover.jpg'); process.exit(1); } const entries = await readdir(dirPath, { withFileTypes: true }); for (const entry of entries) { const fullPath = join(dirPath, entry.name); if (entry.isDirectory()) { const coverPath = join(fullPath, 'cover.jpg'); if (existsSync(coverPath)) { await processImage(coverPath, entry.name); } else { console.log(`Skipping ${entry.name}: no cover.jpg found`); } } } } async function main() { console.log('Starting image optimization...'); console.log(`Source: ${INPUT_DIR}`); console.log(`Output: ${OUTPUT_DIR}`); console.log(`Sizes: ${SIZES.join(', ')}px\n`); try { await processDirectory(INPUT_DIR); console.log('\nImage optimization complete!'); } catch (error) { console.error('Error during optimization:', error); process.exit(1); } } main();