主题
图片批量压缩工具(基于 Sharp)
使用场景
- UI 给的图片体积过大(几 MB)
- 一张张压缩效率极低
- 希望一键压缩 + 自动输出
核心思路
- 使用
sharp进行图片压缩 - 支持 jpg / png / webp
- 可配置最大尺寸、压缩质量
- 自动生成压缩报告
技术选型
sharp:高性能图片处理库fs-extra:增强版文件系统 API- Node.js 脚本自动化处理
compress-images-advanced.js
js
// compress-images-advanced.js
const sharp = require('sharp');
const fs = require('fs-extra');
const path = require('path');
// 配置选项
const config = {
inputDir: 'src/images',
outputDir: 'dist/images',
// 保持原格式
keepOriginalFormat: true,
// 可选:设置最大尺寸
resize: {
enabled: true,
maxWidth: 1920,
maxHeight: 1080
},
// 格式特定的质量设置
quality: {
jpg: 80,
png: 80,
webp: 80,
tiff: 80
}
};
async function compressImages() {
const { inputDir, outputDir, keepOriginalFormat, resize, quality } = config;
await fs.ensureDir(outputDir);
const files = await fs.readdir(inputDir);
let results = [];
console.log('🚀 开始批量图片处理...\n');
for (const file of files) {
const result = await processFile(file, {
inputDir,
outputDir,
keepOriginalFormat,
resize,
quality
});
results.push(result);
}
generateReport(results);
}
async function processFile(file, options) {
const { inputDir, outputDir, keepOriginalFormat, resize, quality } = options;
const ext = path.extname(file).toLowerCase();
const inputPath = path.join(inputDir, file);
const outputPath = path.join(outputDir, file);
try {
const stats = await fs.stat(inputPath);
const originalSize = stats.size;
let sharpInstance = sharp(inputPath);
// 如果需要调整尺寸
if (resize.enabled) {
sharpInstance = sharpInstance.resize({
width: resize.maxWidth,
height: resize.maxHeight,
fit: 'inside',
withoutEnlargement: true
});
}
// 根据格式处理
switch (ext) {
case '.jpg':
case '.jpeg':
await sharpInstance
.jpeg({ quality: quality.jpg, mozjpeg: true })
.toFile(outputPath);
break;
case '.png':
await sharpInstance
.png({ quality: quality.png, compressionLevel: 9 })
.toFile(outputPath);
break;
case '.webp':
await sharpInstance
.webp({ quality: quality.webp, effort: 6 })
.toFile(outputPath);
break;
default:
// 不支持的格式或保持原格式
await fs.copy(inputPath, outputPath);
}
const compressedStats = await fs.stat(outputPath);
const compressedSize = compressedStats.size;
return {
file,
originalSize,
compressedSize,
success: true,
format: ext
};
} catch (error) {
console.error(`❌ 处理 ${file} 失败:`, error.message);
// 出错时复制原文件
await fs.copy(inputPath, outputPath);
const stats = await fs.stat(inputPath);
return {
file,
originalSize: stats.size,
compressedSize: stats.size,
success: false,
error: error.message,
format: ext
};
}
}
function generateReport(results) {
const successful = results.filter(r => r.success);
const failed = results.filter(r => !r.success);
let totalOriginal = 0;
let totalCompressed = 0;
successful.forEach(r => {
totalOriginal += r.originalSize;
totalCompressed += r.compressedSize;
});
console.log('\n📊 ========== 处理报告 ==========');
console.log(`总计文件: ${results.length}`);
console.log(`成功处理: ${successful.length}`);
console.log(`处理失败: ${failed.length}`);
if (failed.length > 0) {
console.log('\n❌ 失败文件:');
failed.forEach(f => console.log(` - ${f.file}: ${f.error}`));
}
console.log('\n💰 空间节省统计:');
console.log(`原始总大小: ${formatSize(totalOriginal)}`);
console.log(`压缩后总大小: ${formatSize(totalCompressed)}`);
if (totalOriginal > 0) {
const saved = totalOriginal - totalCompressed;
const percent = (saved / totalOriginal * 100).toFixed(1);
if (saved > 0) {
console.log(`节省空间: ${formatSize(saved)} (${percent}%)`);
} else {
console.log('⚠️ 文件大小未减少(可能已是最佳质量)');
}
}
console.log('================================\n');
console.log('✅ 所有文件已保存到 dist/images 目录');
}
function formatSize(bytes) {
if (bytes === 0) return '0 B';
const k = 1024;
const sizes = ['B', 'KB', 'MB', 'GB'];
const i = Math.floor(Math.log(bytes) / Math.log(k));
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
}
// 运行
compressImages();功能亮点
- ✅ 保持原图片格式
- ✅ 自动限制最大分辨率(防止放大)
- ✅ 不同格式独立质量配置
- ✅ 自动统计压缩前后体积
- ✅ 异常兜底(失败则复制原图)
使用步骤
- 安装依赖
bash
npm install sharp fs-extra- 放入待压缩图片
text
src/images/- 执行命令
bash
node compress-images-advanced.js- 输出结果
text
dist/images/终端会自动输出:
- 成功 / 失败数量
- 压缩前后体积
- 节省空间百分比