🎨 Canvas实现智能图像压缩与尺寸优化
📝 需求背景
在前端开发中,经常需要处理用户上传的图片。过大的图片会影响加载速度和用户体验,因此需要在保证图片质量的同时进行合理压缩。
🔧 核心实现
完整代码实现
js
/**
* 图片压缩函数
* @param {File[]} imgFiles - 待压缩的图片文件数组
* @returns {Promise} 返回压缩后的图片数据
*/
const compressImg = (imgFiles) => {
return new Promise((resolve, reject) => {
// 存储压缩后的图片和原始文件信息
const compressedImages = [];
const fileData = [];
let compressedCount = 0;
imgFiles.forEach((imgFile) => {
// 创建文件读取器
const reader = new FileReader();
reader.onload = function (event) {
// 创建图片对象
const img = new Image();
img.src = event.target.result;
img.onload = function () {
// 创建Canvas环境
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
// 设置最大尺寸阈值(像素)
const maxThreshold = 2048;
// 初始化画布尺寸
canvas.width = img.width;
canvas.height = img.height;
// 智能调整尺寸,保持宽高比
if (Math.max(img.width, img.height) > maxThreshold) {
const aspectRatio = img.width / img.height;
if (img.width > img.height) {
canvas.width = maxThreshold;
canvas.height = maxThreshold / aspectRatio;
} else {
canvas.height = maxThreshold;
canvas.width = maxThreshold * aspectRatio;
}
}
// 在画布上绘制调整后的图片
ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
// 将画布内容转换为Blob
canvas.toBlob(
function (blob) {
compressedImages.push(blob);
fileData.push({
fileName: imgFile.name,
data: reader.result
});
compressedCount++;
// 所有图片处理完成后返回结果
if (compressedCount === imgFiles.length) {
resolve({ compressedImages, fileData });
}
},
'image/jpeg', // 输出格式
0.8 // 压缩质量(0-1)
);
};
};
// 错误处理
reader.onerror = function (error) {
reject(error);
};
// 以DataURL形式读取文件
reader.readAsDataURL(imgFile);
});
});
};🔍 核心原理解析
1. 图片加载流程
- 使用
FileReader读取文件 - 创建
Image对象加载图片 - 使用
Canvas进行处理
2. 智能压缩策略
📏 尺寸控制:
- 设置最大阈值(2048px)
- 等比例缩放,保持图片比例
- 智能判断长边进行适配
🎯 质量控制:
- 使用
toBlob方法压缩 - 质量参数设为0.8(可调整)
- 输出格式为JPEG(体积更小)
- 使用
3. 关键技术点
- ⚡ 异步处理:使用Promise处理多图片压缩
- 🔄 等比缩放:保持宽高比例不变
- 📊 批量处理:支持多图片同时压缩
📈 使用示例
js
// 单图片压缩
const handleSingleImage = async (file) => {
try {
const result = await compressImg([file]);
console.log('压缩后的图片:', result.compressedImages[0]);
} catch (error) {
console.error('压缩失败:', error);
}
};
// 多图片压缩
const handleMultipleImages = async (files) => {
try {
const result = await compressImg(Array.from(files));
console.log('压缩后的图片组:', result.compressedImages);
} catch (error) {
console.error('压缩失败:', error);
}
};💡 优化建议
内存优化
- 及时释放Canvas对象
- 处理大量图片时考虑分批处理
性能优化
- 可以添加Worker处理大量图片
- 考虑使用
createImageBitmap优化性能
体验优化
- 添加压缩进度提示
- 提供压缩质量参数配置选项
🎯 应用场景
- 📱 移动端图片上传
- 🖼️ 图片预览优化
- 📂 相册批量处理
- 🚀 前端性能优化