使用Canvas API实现前端图片压缩功能
作者:DawsonT
这篇文章主要为大家详细介绍了如何使用Canvas API实现前端图片压缩功能,文章的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下
前言
最近我在工作上遇到用户上传大尺寸图片的需求,发现直接上传原始图片会消耗过多带宽和存储空间。于是在网上找了一些像 图片压缩网站 这样的工具能在浏览器里直接完成压缩,无需上传到服务器,这让我很受启发。经过研究,我找到了使用Canvas API的简单实现方案,下面是自己实现的代码和想法。
核心实现原理
Canvas图片压缩主要利用以下技术流程:
- 将原始图片绘制到Canvas画布上
- 调整Canvas尺寸以实现分辨率压缩
- 使用有损编码(如JPEG)和可调质量参数输出图片
- 将结果转换为Blob或Base64格式
关键代码实现
1. 图片加载与绘制
function loadImage(file) {
return new Promise((resolve, reject) => {
const img = new Image();
const url = URL.createObjectURL(file);
img.onload = () => {
URL.revokeObjectURL(url);
resolve(img);
};
img.onerror = (e) => {
reject(e);
};
img.src = url;
});
}
2. 核心压缩函数
async function compressImage(file, options = {}) {
const {
quality = 0.8,
maxWidth = 800,
maxHeight = 800,
mimeType = 'image/jpeg'
} = options;
// 加载原始图片
const img = await loadImage(file);
// 计算缩放比例
const [newWidth, newHeight] = calculateSize(img, maxWidth, maxHeight);
// 创建canvas并绘制
const canvas = document.createElement('canvas');
canvas.width = newWidth;
canvas.height = newHeight;
const ctx = canvas.getContext('2d');
ctx.drawImage(img, 0, 0, newWidth, newHeight);
// 转换为Blob对象
return new Promise((resolve) => {
canvas.toBlob(
(blob) => resolve(blob),
mimeType,
quality
);
});
}
// 辅助函数:计算新尺寸
function calculateSize(img, maxWidth, maxHeight) {
let width = img.width;
let height = img.height;
// 计算缩放比例
if (width > height) {
if (width > maxWidth) {
height = Math.round((height * maxWidth) / width);
width = maxWidth;
}
} else {
if (height > maxHeight) {
width = Math.round((width * maxHeight) / height);
height = maxHeight;
}
}
return [width, height];
}
3. 使用示例
const fileInput = document.querySelector('input[type="file"]');
fileInput.addEventListener('change', async (e) => {
const file = e.target.files[0];
if (!file) return;
try {
const compressedBlob = await compressImage(file, {
quality: 0.7,
maxWidth: 1024,
maxHeight: 1024
});
// 使用压缩后的Blob
console.log(`原始大小: ${file.size} bytes`);
console.log(`压缩后: ${compressedBlob.size} bytes`);
// 可以上传到服务器或提供给用户下载
} catch (error) {
console.error('压缩失败:', error);
}
});
关键参数说明
quality (0-1) : 控制JPEG压缩质量,数值越小压缩率越高
maxWidth/maxHeight: 限制图片最大尺寸,实现分辨率压缩
mimeType: 可指定为'image/jpeg'(有损)、'image/png'(无损)等
浏览器兼容性
Canvas压缩功能在现代浏览器中支持良好,包括:
- Chrome 50+
- Firefox 50+
- Safari 10+
- Edge 15+
方法补充
使用canvas实现图片压缩上传
实现思路
- 使用 FileReader 对象获取本地文件(使用文件选择 input 元素)的 base64 内容
- 使用 context.drawImage 把获取到的文件画在 canvas 上
- 使用 canvas.toBlob 对图片做质量压缩
完整代码
/**
* 对选中的图片文件处理
*
* @param {obj} event 图片文件
* */
uploadImg (event) {
// 为选择文件返回
if (!event.target.files[0]) return;
let file = event.target.files[0],
fileName = file.name.substring(file.name.lastIndexOf(".") + 1).toLowerCase();
// 文件格式校验
if (fileName != "jpg" && fileName != "png" && fileName != "gif" ) {
this.$store.commit('setPrompt', {status: true, text: '请选择正确的图片格式上传(jpg,png,gif)'})
return
}
// gif图片格式不做处理,其他静态图片做质量压缩处理以减小图片大小
if (fileName == 'gif') {
this.uploadApi(file, file.name)
} else {
let _this = this;
// 压缩图片需要的一些元素和对象
let reader = new FileReader(), img = new Image();
reader.readAsDataURL(file);
// 缩放图片需要的canvas
let canvas = document.createElement('canvas');
let context = canvas.getContext('2d');
// base64地址图片加载完毕后
img.onload = function() {
// 图片原始尺寸
let originWidth = this.width;
let originHeight = this.height;
canvas.width = originWidth;
canvas.height = originHeight;
// 清除画布
context.clearRect(0, 0, originWidth, originHeight);
// 图片压缩
context.drawImage(img, 0, 0, originWidth, originHeight);
// canvas转为blob并上传
canvas.toBlob(function(blob) {
_this.uploadApi(blob, file.name)
}, file.type == 'image/gif' ? 'image/gif' : "image/jpeg", 0.6);
}
// 文件base64化,以便获知图片原始尺寸
reader.onload = function(e) {
img.src = e.target.result;
};
}
},
/**
* 上传选中的图片文件
*
* @param {obj} file 图片文件
* @param {string} fileName 文件名称
* */
uploadApi(file, fileName) {
let formData = new FormData()
formData.append('img', file, fileName)
axios.post('/upload/upload-img', formData, {headers: {'Content-Type': 'multipart/form-data'}}).then((res) => {
if (res.data.code == 200) {
this.img_list.splice(this.img_list.length, 1, res.data.url)
} else {
this.$store.commit('setPrompt', {status: true, text: res.data.message})
}
})
}
到此这篇关于使用Canvas API实现前端图片压缩功能的文章就介绍到这了,更多相关Canvas图片压缩内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
