利用谷歌调式工具发现,图片大小直接影响着首屏加载时间。
且考虑到后期服务端压力,图片压缩特别必要。
本文是前端利用canvas实现图片。参考文章:https://www.cnblogs.com/007sx/p/7583202.html
本文将其改为插件形式,适合单文件压缩,多文件可以采用生成多个二进制文件的方法,然后一并上传。具体后面研究。
说说原理,压缩涉及三个关键点:
1,一个图片前端可被加载,基于file:协议的路径是不能产生onload事件,所以需要借助浏览器的接口将图片转为可加载文件,一种是通过FileReader,另一种是
通过URL.createObjectURL。
2,利用canvas,获取图片的高度和宽度之后,利用drawImage输出图片,再利用canvas的toDataURL输出base64的图片。
3,将base64转为二进制文件。
案例代码:
1 <!DOCTYPE html> 2 <html> 3 4 <head> 5 <meta charset="UTF-8"> 6 <title>XMLHttpRequest上传文件压缩上传图片文件</title> 7 </head> 8 9 <body> 10 <input type="file" id="file" name="myfile" accept="image/x-png, image/jpg, image/jpeg, image/gif" /> 11 <input type="button" onclick="UpladFile()" value="上传" /> 12 <script type="text/javascript"> 13 (function() { 14 function compress(opts, fileObj) { 15 this.defaults = { 16 id: "#file", 17 quality: 0.4, 18 url: "", 19 callback: function(bl) { 20 console.log(bl); 21 } 22 }; 23 24 if (typeof opts === "object") { 25 this.options = Object.assign({}, this.defaults, opts) 26 } else { 27 this.options = this.defaults; 28 } 29 fileObj = fileObj || document.querySelector(this.options.id).files[0]; 30 this.init(fileObj); 31 } 32 compress.prototype = { 33 version: "1.0.1", 34 init: function(fileObj) { 35 _this = this; 36 //promise处理异步 37 this.photoCompress(fileObj).then(function(res) { 38 return _this.canvasDataUrl.call(_this, res); 39 }).catch(function(err) { 40 console.log(err); 41 }).then(function(res) { 42 var bl = _this.convertBase64UrlToBlob(res); 43 _this.options.callback(bl); 44 }).catch(function(err) { 45 console.log(err); 46 }) 47 48 }, 49 photoCompress: function(file) { 50 var ready = new FileReader(); 51 ready.readAsDataURL(file); 52 return new Promise(function(resolve, reject) { 53 ready.onload = function() { 54 var re = this.result; 55 resolve(re); 56 } 57 ready.onerror = function(err) { 58 reject(err) 59 } 60 }) 61 62 }, 63 canvasDataUrl: function(res) { 64 65 var img = new Image(); 66 img.src = res; 67 _this = this; 68 return new Promise(function(resolve, reject) { 69 img.onload = function() { 70 // 默认按比例压缩 71 var w = this.width, 72 h = this.height; 73 //生成canvas 74 var canvas = document.createElement('canvas'); 75 var ctx = canvas.getContext('2d'); 76 // 创建属性节点 77 var anw = document.createAttribute("width"); 78 anw.nodeValue = w; 79 var anh = document.createAttribute("height"); 80 anh.nodeValue = h; 81 canvas.setAttributeNode(anw); 82 canvas.setAttributeNode(anh); 83 ctx.drawImage(this, 0, 0, w, h); 84 85 // quality值越小,所绘制出的图像越模糊 86 var base64 = canvas.toDataURL('image/jpeg', _this.options.quality); 87 // 回调函数返回base64的值 88 resolve(base64) 89 } 90 img.onerror = function(err) { 91 reject(err) 92 } 93 }) 94 }, 95 96 //base64转为二进制数据,后端可直接利用 97 convertBase64UrlToBlob: function(urlData) { 98 var arr = urlData.split(','), 99 mime = arr[0].match(/:(.*?);/)[1], 100 bstr = atob(arr[1]), 101 n = bstr.length, 102 u8arr = new Uint8Array(n); 103 while (n--) { 104 u8arr[n] = bstr.charCodeAt(n); 105 } 106 return new Blob([u8arr], { type: mime }); 107 } 108 } 109 window.compress = compress; 110 111 })(); 112 113 //上传文件方法 114 function UpladFile() { 115 116 var url = "./upload"; // 接收上传文件的后台地址 117 new compress({ 118 quality: 0.4, 119 url: url, 120 callback: function(bl) { 121 var form = new FormData(); 122 form.append("file", bl, "file_" + Date.parse(new Date()) + ".jpg"); // 文件对象 123 var xhr = new XMLHttpRequest(); 124 xhr.open("post", url, true); 125 xhr.onreadystatechange = function(evt) { 126 if (xhr.readyState === 4 && xhr.status === 200) { 127 uploadComplete(evt); 128 } 129 } 130 131 xhr.send(form); //开始上传,发送form数据 132 } 133 }) 134 } 135 136 //上传成功响应 137 function uploadComplete(evt) { 138 //服务断接收完文件返回的结果 139 var data = JSON.parse(evt.target.responseText); 140 if (data.success) { 141 alert("上传成功!"); 142 } else { 143 alert("上传失败!"); 144 } 145 146 } 147 </script> 148 </body> 149 150 </html>