前些天公司要求在微信移动端做上传图片并预览的功能,要求能够调用摄像头拍照并立即预览。
在网上搜了一些方法,开始自己写了个简单的功能实现代码。结果发现移动端拍照出来的图片动不动就2M+,又因为要批量上传,为用户的流量和上传速度考虑,我决定做一下优化,看能不能在预览前就压缩一下图片尺寸。
结果又是一阵百度,发现一个靠谱的封装好的base64图片预览及压缩的方法。
直接上下载地址吧:
http://www.imwinlion.com/wp-content/uploads/2016/05/localresizeimg.rar
源码和用法都很简单,稍微看下源码就懂了,为了兼容移动端,请一定将/path/mobileBUGFix.mini.js加入到页面中。反正我是加了的,没加会有什么后果,大家有空可以测一下。
这个插件还是比较好用的,问题是我要批量上传,怎么搞?这个插件只能单个图片上传!
所以我后来改良了一下插件,在插件内部指向文件时,做了一个循环,话不多说,代码也很简单,直接上代码
1 /** 2 * 获得base64 3 * @param {Object} obj 4 * @param {Number} [obj.width] 图片需要压缩的宽度,高度会跟随调整 5 * @param {Number} [obj.quality=0.8] 压缩质量,不压缩为1 6 * @param {Function} [obj.before(this, blob, file)] 处理前函数,this指向的是input:file 7 * @param {Function} obj.success(obj) 处理后函数 8 * @example 9 * 10 */ 11 $.fn.localResizeIMG = function(obj) { 12 this.on('change', function() { 13 //批量预览压缩 14 var file,blob; 15 var _this=this; 16 if(this.files.length>1){ 17 for(var i = 0, len=_this.files.length;i<len;i++){ 18 file=_this.files[i]; 19 if (window.createObjectURL!=undefined) { // basic 20 blob = window.createObjectURL(file) ; 21 } else if (window.URL!=undefined) { // mozilla(firefox) 22 blob = window.URL.createObjectURL(file) ; 23 } else if (window.webkitURL!=undefined) { // webkit or chrome 24 blob = window.webkitURL.createObjectURL(file) ; 25 } 26 if ($.isFunction(obj.before)) { 27 obj.before(_this, blob, file) 28 } 29 if(file.size/1024>300){ 30 obj.quality=300/(file.size/1024) 31 }else{ 32 obj.quality=1 33 } 34 _create(blob,obj.quality, file); 35 } 36 }else{ 37 //单张预览压缩图片 38 file = this.files[0]; 39 if (window.createObjectURL!=undefined) { // basic 40 blob = window.createObjectURL(file) ; 41 } else if (window.URL!=undefined) { // mozilla(firefox) 42 blob = window.URL.createObjectURL(file) ; 43 } else if (window.webkitURL!=undefined) { // webkit or chrome 44 blob = window.webkitURL.createObjectURL(file) ; 45 } 46 // 执行前函数 47 if ($.isFunction(obj.before)) { 48 obj.before(this, blob, file) 49 }; 50 if(file.size/1024>300){ 51 obj.quality=300/(file.size/1024) 52 }else{ 53 obj.quality=1 54 } 55 _create(blob,obj.quality, file); 56 } 57 this.value = ''; // 清空临时数据 58 }); 59 60 /** 61 * 生成base64 62 * @param blob 通过file获得的二进制 63 */ 64 function _create(blob,quality) { 65 console.log(quality); 66 var img = new Image(); 67 img.src = blob; 68 img.onload = function() { 69 var that = this; 70 //生成比例 71 var w = that.width, 72 h = that.height, 73 quality = w / h; 74 w = obj.width || w; 75 h = w / quality; 76 77 //生成canvas 78 var canvas = document.createElement('canvas'); 79 var ctx = canvas.getContext('2d'); 80 $(canvas).attr({ 81 width: w, 82 height: h 83 }); 84 ctx.drawImage(that, 0, 0, w, h); 85 86 /** 87 * 生成base64 88 * 兼容修复移动设备需要引入mobileBUGFix.js 89 */ 90 var base64 = canvas.toDataURL('image/png', quality || 0.8); 91 92 // 修复IOS 93 if (navigator.userAgent.match(/iphone/i)) { 94 var mpImg = new MegaPixImage(img); 95 mpImg.render(canvas, { 96 maxWidth: w, 97 maxHeight: h, 98 quality: quality || 0.8 99 }); 100 base64 = canvas.toDataURL('image/png', quality || 0.8); 101 } 102 103 // 修复android 104 if (navigator.userAgent.match(/Android/i)) { 105 var encoder = new JPEGEncoder(); 106 base64 = encoder.encode(ctx.getImageData(0, 0, w, h), parseFloat(quality).toFixed(1) * 100 || 80); 107 } 108 109 // 生成结果 110 var result = { 111 base64: base64, 112 clearBase64: base64.substr(base64.indexOf(',') + 1) 113 }; 114 115 // 执行后函数 116 obj.success(result); 117 }; 118 } 119 }; 120 121 122 // 例子 123 /* 124 $('input:file').localResizeIMG({ 125 width: 100, 126 quality: 0.1, 127 //before: function (that, blob) {}, 128 success: function (result) { 129 var img = new Image(); 130 img.src = result.base64; 131 132 $('body').append(img); 133 console.log(result); 134 } 135 }); 136 */
改良之后,我判断了input[type=files].files的长度,如果是批量上传的话,长度应该是大于1的,这个逻辑应该很好理解;然后循环每一个files,获取每个图片的size(图片大小),我这里的图片尺寸判断是写死了的300kb,如果这张图片>300kb,就压缩尺寸,如果相反,则按原尺寸预览。如果你用我改良后的代码,调用方法后的quality属性就不用赋值了。
with属性:你压缩后图片的宽度,不宜太小,我是设置的400,太小会失真。
before方法:开始压缩前执行函数
success方法:压缩成功后的回调函数,一般就是写预览代码,如果你要异步上传,这里也可以写ajax
说了这么多,再来说一下移动端的照相机调用,文件格式限制吧
很简单,一行搞定
1 <input id="images-multiple" class="weui-uploader__input" type="file" accept="image/*" multiple="multiple">
accept:接收文件的类型
multiple:可多选(android手机设置此项后,不能调用相机,只能从相册中选择;IOS手机体验还是很溜的)
id和calss自行制定就OK了。
目前的我页面在微信内跑,尚未发现问题,如有疑问欢迎探讨!!
提供一个GITHUB的类似解决方案:内容还没来得及看,有兴趣可以去看看