公司最近有需要压缩上传图片功能,查找了些资料并实现了一把。
主要用到的原生组件:FileReader、Canvas、Blob、FormData
逻辑步骤:
- FileReader.readAsDataURL将上传的图片文件转为Base64格式
- 将img绘制到canvas上,canvas.toDataURL压缩图片
- new Blob将压缩后的Base64转为Blob格式
- FormData.append将图片文件数据存入formdata
Code:
this.compressImage(files[0], (file)=>{ console.log(file); const formData = new FormData(); formData.append('file', file, file.name || '上传图片.jpeg');}, $.noop);//压缩图片compressImage = (file, success, error) => { // 图片小于1M不压缩 if (file.size < Math.pow(1024, 2)) { return success(file); } const name = file.name; //文件名 const reader = new FileReader(); reader.readAsDataURL(file); reader.onload = (e) => { const src = e.target.result; const img = new Image(); img.src = src; img.onload = (e) => { const w = img.width; const h = img.height; const quality = 0.8; // 默认图片质量为0.92 //生成canvas const canvas = document.createElement('canvas'); const ctx = canvas.getContext('2d'); // 创建属性节点 const anw = document.createAttribute("width"); anw.nodeValue = w; const anh = document.createAttribute("height"); anh.nodeValue = h; canvas.setAttributeNode(anw); canvas.setAttributeNode(anh); //铺底色 PNG转JPEG时透明区域会变黑色 ctx.fillStyle = "#fff"; ctx.fillRect(0, 0, w, h); ctx.drawImage(img, 0, 0, w, h); // quality值越小,所绘制出的图像越模糊 const base64 = canvas.toDataURL('image/jpeg', quality); //图片格式jpeg或webp可以选0-1质量区间 // 返回base64转blob的值 console.log(`原图${(src.length/1024).toFixed(2)}kb`, `新图${(base64.length/1024).toFixed(2)}kb`); //去掉url的头,并转换为byte const bytes = window.atob(base64.split(',')[1]); //处理异常,将ascii码小于0的转换为大于0 const ab = new ArrayBuffer(bytes.length); const ia = new Uint8Array(ab); for (let i = 0; i < bytes.length; i++) { ia[i] = bytes.charCodeAt(i); } file = new Blob( [ab] , {type : 'image/jpeg'}); file.name = name; success(file); } img.onerror = (e) => { error(e); } } reader.onerror = (e) => { error(e); }}
遇到的一些坑:
- PNG转JPEG时PNG格式的透明区域会变黑色,需要先手动铺底色
- toDataURL参数为PNG时不支持传图片质量,所以需要写死image/jpeg或image/webp,具体可以参考toDataURL的api
- formData.append第三个参数filename是有浏览器兼容性问题的,如果不传就是filename=blob,后端校验文件名可能过不去
- ajax的contentType和processData需要传false,这和本文关系不大直接带过
- 网上说的ios中canvas绘制图片大小限制我在iphone6上测试没遇到,可能和机型或系统有关系,如果有可以在下面留言
结语,压缩功能比较适合移动端,毕竟PC端带宽比较好而且不能兼容IE老版本。