在我的博客,“生活”这模块里,经常需要上传图片。这些图片一般都是我用手机拍摄的,图片质量一般在2-5M左右。所以,我会在图片上传后,使用tinypng接口进行图片压缩。这样,显示的图片会在几百KB左右,点击大图预览才会加载原图。
就在前两个月,在团队项目里。甲方提出了一个需求,要求对上传的图片进行压缩。在我的思维逻辑里,压缩工作是在图片上传后,后端去进行处理的。 经过小组的讨论分析,后端想要把图片质量压缩的工作放在前端去进行处理,这样可以减少请求时间,客户体验感会更好。当时的有点懵逼,前端还能去处理图片的压缩?
显然团队的项目更适用于第三种方法。而且网上一大堆相关的资料。
详细代码解释如下:
function compress (file,callback) { var reader = new FileReader(); // 将file 对象转成 Data URL reader.readAsDataURL(file); reader.onload = function(e) { // 新建一个img 标签(还没嵌入DOM节点) var image = new Image(); image.src = e.target.result; image.onload = function() { // canvas.getContext 进行宽高的改变,从而达到压缩质量的目的 var canvas = document.createElement('canvas'), context = canvas.getContext('2d'); imageWidth = 300, // 压缩质量宽度 imageHeight = 300, // 压缩质量高度 compactData = ''; canvas.width = imageWidth; canvas.height = imageHeight; context.drawImage(image, 0, 0, imageWidth, imageHeight); // 将canvas 元素所展示的图片再次转换成 Data URL // 到这已经压缩完成了 compactData = canvas.toDataURL(file.type); // 最后把Data URL 转成 blob var byteString, mimeString, u8arr, blob; if ( compactData.split(",")[0].indexOf("compactData") >= 0 ) { byteString = atob(compactData.split(",")[1]); } else{ byteString = unescape(compactData.split(",")[1]); } mimeString = compactData .split(",")[0] .split(":")[1] .split(";")[0]; u8arr = new Uint8Array(byteString.length); for ( var i = 0; i < byteString.length; i++ ) { u8arr[i] = byteString.charCodeAt(i); } blob = new Blob([u8arr], { type: mimeString }); // 返回原file 对象、压缩后的file 对象、压缩后的 Data URL callback && callback(file, blob, compactData); }; }; };在上述样例中,主要是经历了图片 -->canvas缩放压缩 --> 图片的过程。在图片压缩完成后,看个人所需,可以做不同的处理。例如将压缩后的图片显示在页面,作为略缩图,或者直接上传压缩图片。
但要注意的是,上传图片必须是blob对象,所以在压缩后,必须转换成blob对象才能进行上传。转换blob对象的方法好几种,原生的canvas也提供转换blob的方法。有兴趣可以去了解。