File size: 6,153 Bytes
20c5151
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
#!/usr/bin/env node

/**
 * Image Optimization Script
 * 
 * Provides recommendations for image optimization
 * Note: Requires external tools for actual optimization
 */

const fs = require('fs');
const path = require('path');

function getFileSize(filePath) {
    try {
        const stats = fs.statSync(filePath);
        return stats.size;
    } catch {
        return 0;
    }
}

function formatSize(bytes) {
    return (bytes / 1024).toFixed(2) + ' KB';
}

function analyzeImages(dir, extensions = ['.jpg', '.jpeg', '.png', '.gif', '.webp', '.svg']) {
    let images = [];
    
    try {
        const items = fs.readdirSync(dir);
        
        for (const item of items) {
            const fullPath = path.join(dir, item);
            const stat = fs.statSync(fullPath);
            
            if (stat.isDirectory()) {
                images = images.concat(analyzeImages(fullPath, extensions));
            } else if (stat.isFile()) {
                const ext = path.extname(item).toLowerCase();
                if (extensions.includes(ext)) {
                    images.push({
                        path: fullPath.replace(process.cwd(), ''),
                        name: item,
                        size: stat.size,
                        ext: ext
                    });
                }
            }
        }
    } catch (error) {
        console.error(`Error analyzing directory ${dir}:`, error.message);
    }
    
    return images;
}

console.log('🖼️  Image Optimization Analysis\n');
console.log('='.repeat(60));

const publicDir = path.join(__dirname, '..', 'public');
const iconsDir = path.join(publicDir, 'icons');

// Analyze images
const images = analyzeImages(publicDir);

if (images.length === 0) {
    console.log('\nNo images found to optimize.');
    process.exit(0);
}

console.log(`\nFound ${images.length} images\n`);

// Group by type
const byType = {};
images.forEach(img => {
    if (!byType[img.ext]) {
        byType[img.ext] = [];
    }
    byType[img.ext].push(img);
});

// Report by type
let totalSize = 0;
let potentialSavings = 0;

for (const [ext, imgs] of Object.entries(byType)) {
    console.log(`\n${ext.toUpperCase()} Images:`);
    console.log('-'.repeat(60));
    
    const typeSize = imgs.reduce((sum, img) => sum + img.size, 0);
    totalSize += typeSize;
    
    // Calculate potential savings based on type
    let savings = 0;
    let recommendation = '';
    
    switch (ext) {
        case '.png':
            savings = typeSize * 0.4; // ~40% savings with compression
            recommendation = 'Use pngquant or TinyPNG. Consider WebP format.';
            break;
        case '.jpg':
        case '.jpeg':
            savings = typeSize * 0.3; // ~30% savings
            recommendation = 'Use mozjpeg or jpegoptim. Consider WebP format.';
            break;
        case '.svg':
            savings = typeSize * 0.2; // ~20% savings
            recommendation = 'Use SVGO to optimize.';
            break;
        case '.gif':
            savings = typeSize * 0.5; // ~50% savings
            recommendation = 'Convert to WebP or use gifsicle.';
            break;
        default:
            savings = 0;
            recommendation = 'Already optimized format.';
    }
    
    potentialSavings += savings;
    
    // Show largest images
    imgs.sort((a, b) => b.size - a.size);
    imgs.slice(0, 5).forEach(img => {
        console.log(`   ${img.name.padEnd(30)} ${formatSize(img.size).padStart(12)}`);
    });
    
    if (imgs.length > 5) {
        console.log(`   ... and ${imgs.length - 5} more`);
    }
    
    console.log(`   Total: ${formatSize(typeSize)}`);
    console.log(`   💡 ${recommendation}`);
    console.log(`   Potential savings: ${formatSize(savings)}`);
}

console.log('\n\n📊 Summary');
console.log('='.repeat(60));
console.log(`   Total images: ${images.length}`);
console.log(`   Total size: ${formatSize(totalSize)}`);
console.log(`   Potential savings: ${formatSize(potentialSavings)} (${((potentialSavings/totalSize)*100).toFixed(1)}%)`);

console.log('\n\n💡 Optimization Recommendations');
console.log('='.repeat(60));

console.log('\n1. Install optimization tools:');
console.log('   npm install -g svgo');
console.log('   # For PNG: brew install pngquant (macOS) or apt-get install pngquant (Linux)');
console.log('   # For JPEG: brew install mozjpeg (macOS) or apt-get install mozjpeg (Linux)');

console.log('\n2. Optimize SVG icons:');
console.log('   svgo -f public/icons -o public/icons-optimized');

console.log('\n3. Convert to WebP (best compression):');
console.log('   # For each image:');
console.log('   # cwebp input.png -q 80 -o output.webp');

console.log('\n4. Use modern image formats:');
console.log('   • WebP: Best compression, wide support');
console.log('   • AVIF: Better than WebP, limited support');
console.log('   • Provide fallbacks for older browsers');

console.log('\n5. Implement responsive images:');
console.log('   <picture>');
console.log('     <source srcset="image.webp" type="image/webp">');
console.log('     <source srcset="image.jpg" type="image/jpeg">');
console.log('     <img src="image.jpg" alt="...">');
console.log('   </picture>');

console.log('\n6. Use lazy loading:');
console.log('   <img src="..." loading="lazy" alt="...">');

console.log('\n\n🎯 Priority Actions:');
console.log('='.repeat(60));

// Find large images that need optimization
const largeImages = images.filter(img => img.size > 100 * 1024).sort((a, b) => b.size - a.size);

if (largeImages.length > 0) {
    console.log('\n⚠️  Large images that need optimization (>100KB):');
    largeImages.slice(0, 10).forEach((img, i) => {
        console.log(`   ${i + 1}. ${img.name} (${formatSize(img.size)})`);
    });
} else {
    console.log('\n✅ No large images found! All images are optimized.');
}

// Check for SVG optimization opportunities
const svgImages = images.filter(img => img.ext === '.svg');
if (svgImages.length > 0) {
    console.log(`\n📝 ${svgImages.length} SVG files can be optimized with SVGO`);
}

console.log('\n' + '='.repeat(60));
console.log('✅ Analysis complete!\n');