移动端图片上传问题
现在大家都用手机拍照片上网上传,但手机照片太大的话,用流量上传可真是浪费!你看iPhone 6,一张照片往往几兆或者更多,这么大的体积,在上网和存照片上都有点吃力。所以,怎么把照片做个瘦身,让它既不失真又能快速上传?这个问题可难倒了不少程序员。
H5技术的应用
随着我们对HTML5越来越了解,前端开发人员都喜欢用它来帮助解决手机上传照片的问题。今天我给大家科普一下怎么利用HTML5里的几个重要东西——比如FileReader, Canvas以及FormData这种工具,再加上一些压缩算法,搞定手机上的扫描上传功能。这个功能现在可是很多手机软件中的必需!
基本流程概述
如何在手机上轻松搞定图片压缩和上传?其实就三步曲!第一,咱得从cf87657e09ac8ed6e400342ae8ea05d0那里接收到用户选好的图片;接着,用 FileReader 把文件弄明白,再让 Canvas 帮咱们压缩一下;最后,FormData 带着这些压缩好的数据去见后台服务器。
获取图片数据
用户选好了想要上传的图,手机就会自动触发input file元素的change事件,这时就能拿到选中的文件,也就是files这个东西。然后,把这堆文件按顺序排个队,用FileReader对象挨个儿读一遍,看看每份文件是不是超过了200KB。如果超了就用compress方法给它压缩下,不超的话就直接传上去。
filechooser.onchange = function () { if (!this.files.length) return; var files = Array.prototype.slice.call(this.files); if (files.length > 9) { alert("最多同时只可上传9张图片"); return; } files.forEach(function (file, i) { if (!//(?:jpegpnggif)/i.test(file.type)) return; var reader = new FileReader(); var li = document.createElement("li"); li.innerHTML = ""; $(".img-list").append($(li)); reader.onload = function () { var result = this.result; var img = new Image(); img.src = result; //如果图片大小小于200kb,则直接上传 if (result.length <= maxsize) { $(li).css("background-image", "url(" + result + ")"); img = null; upload(result, file.type, $(li)); return; } // 图片加载完毕之后进行压缩,然后上传 if (img.complete) { callback(); } else { img.onload = callback; } function callback() { var data = compress(img); $(li).css("background-image", "url(" + data + ")"); upload(data, file.type, $(li)); img = null; } }; reader.readAsDataURL(file); }) };
压缩图片处理
要用iPhone画图?有些限制,比如200万像素以上的照片就画不了了。解决这个问题,我们可以把大图切成几片小图再拼起来放上去,这样就能避免这个限制。而且,如果有超400万像素的照片,为了能顺利画出来,我们需要调整一下大小进行压缩处理!
处理特殊情况
之前说的那些限制以外,还要注意这两点特别的事儿!先是Canvas的toDataURL方法只能压jpg图,所以记得把png全变成jpg处理才行哦;然后就是,png转jpg时可能会出现透明地方变黑底儿这种现象,得想办法处理好透明像素让背影别变。
转换与上传
压缩了图片数据后,我们把它变成base64格式的字符编码。接着,用这个文本再创建一个新的ArrayBuffer对象。然后,8位整型的字符串就会被放进ArrayBuffer里,接着通过BlobBuilder或者Blob对象,把它们转成二进制的blob object。搞定之后,我们就可以把这个blob对象放进FormData里面,然后用Ajax方式发去服务器上,这样就能成功上传!
总结与展望
咱们今天就来详细聊聊怎么用H5这项牛逼的技术,实现移动端的图片压缩上传功能。这个功能好用得很,能大幅降低上传大图给我们带来的流量费和压力山大的服务器储存问题,同时还提高了用户体验度和网页效果。而且,随着移动设备越来越强大和web技术越发熟练,我觉得将来肯定会出现更多新的创新方法。
function compress(img) { var initSize = img.src.length; var width = img.width; var height = img.height; //如果图片大于四百万像素,计算压缩比并将大小压至400万以下 var ratio; if ((ratio = width * height / 4000000)>1) { ratio = Math.sqrt(ratio); width /= ratio; height /= ratio; }else { ratio = 1; } canvas.width = width; canvas.height = height; // 铺底色 ctx.fillStyle = "#fff"; ctx.fillRect(0, 0, canvas.width, canvas.height); //如果图片像素大于100万则使用瓦片绘制 var count; if ((count = width * height / 1000000) > 1) { count = ~~(Math.sqrt(count)+1); //计算要分成多少块瓦片 // 计算每块瓦片的宽和高 var nw = ~~(width / count); var nh = ~~(height / count); tCanvas.width = nw; tCanvas.height = nh; for (var i = 0; i < count; i++) { for (var j = 0; j < count; j++) { tctx.drawImage(img, i * nw * ratio, j * nh * ratio, nw * ratio, nh * ratio, 0, 0, nw, nh); ctx.drawImage(tCanvas, i * nw, j * nh, nw, nh); } } } else { ctx.drawImage(img, 0, 0, width, height); } //进行最小压缩 var ndata = canvas.toDataURL("image/jpeg", 0.1); console.log("压缩前:" + initSize); console.log("压缩后:" + ndata.length); console.log("压缩率:" + ~~(100 * (initSize - ndata.length) / initSize) + "%"); tCanvas.width = tCanvas.height = canvas.width = canvas.height = 0; return ndata; }
。
评论0