图片上传功能是个比较常用的功能。现代手机图片像素较大,一张图片都有好几M,在服务器带宽较小的情况下(本人苦逼小站只有1Mbps)对用户的耐心是个很大的挑战,此时在浏览器端压缩再上传就很有必要了。
[一]环境:jdk8+tomcat8
[二]框架:springmvc
[三]代码:
maven:核心包,其他的我就不贴了
<dependency> <groupId>commons-fileupload</groupId> <artifactId>commons-fileupload</artifactId> <version>1.3.1</version> </dependency>
html,引入了bootstrap和jquery,不贴了
<input type="file" accept="image/*" value="${pageContext.request.contextPath}/upload" multiple style="display: none"/> <button id="upload" class="btn btn-success btn-md">上传图片</button> 预览:<div></div><hr> <div class="progress"><span></span></div> <canvas id="canvans" style="max-width: 400px;"> </canvas>
javascript
<script> //初始化 var maxFileSize=150*1024; var canvas = document.getElementById("canvans"); var ctx = canvas.getContext("2d"); // // var fileChoose = $("input"); //触发隐藏的上传按钮 $("#upload").on("click",function () { $("input[type='file']").click(); }).on("touchstart",function () { $(this).addClass("touch"); }).on("touchend",function () { $(this).removeClass("touch"); }); // $("input").on("change",chg); function chg() { if(!this.files.length){ return; } var files = Array.prototype.slice.call(this.files); console.info("files==="+files); if(files.length>3){ alert("最多只能上传3张图片"); return; } files.forEach(function (file, i) { if(!/jpeg|jpg|png/.test(file.type)){ alert("仅支持上传jpg、jpeg、png格式的图片"); return; } var fileReader = new FileReader(); //获取图片大小 var fileSize = file.size/1024>1024?(file.size/1024/1024).toFixed(2)+"MB":~~(file.size/1024)+"KB"; $(".progress").text(fileSize); //FILE API读取文件 fileReader.onload=function () { var result = this.result; var image = new Image(); image.src=result; //超出大小,压缩 if(result.length>maxFileSize){ if(image.complete){ callback(); }else{ image.onload = callback; compress(image); } }else{ image = null; upload(result,file.type); return; } function callback(){ var data = compress(image); upload(data,file.type); } } fileReader.readAsDataURL(file); }); //canvas对图片压缩 function compress(image){ var initImgSize = image.src.length; var width = image.width; var height = image.height; console.info(initImgSize+"/"+width+"/"+height); //如果图片大于200Kb,将图片压缩至200Kb以下 var ration;//压缩比 if(width*height>2000000){ ration = Math.sqrt(width*height/2000000); width/=ration; height/=ration; }else{ ration = 1; } canvas.width = width; canvas.height = height; // 铺底色 // ctx.fillStyle = "#fff"; // ctx.fillRect(0, 0, canvas.width, canvas.height); //图片过大需要进行瓦片绘制,暂不做处理 ctx.drawImage(image,0,0,canvas.width,canvas.height); //进行压缩 var newdata = canvas.toDataURL("image/jpeg",0.3); console.info("before"+initImgSize); console.info("after"+newdata.length); console.info("rate"+(100*(initImgSize-newdata.length)/initImgSize)+"%"); return newdata; } } // 图片上传,将base64的图片转成二进制对象,塞进formdata上传 function upload(basestr,type){ var text = window.atob(basestr.split(",")[1]); var buffer = new Uint8Array(text.length); var pecent = 0, loop = null; for (var i = 0; i < text.length; i++) { buffer[i] = text.charCodeAt(i); } var blob = getBlob([buffer], type); var xhr = new XMLHttpRequest(); var formdata = getFormData(); console.info(blob); formdata.append('data', blob); // formdata.append("filename","abc.jpg"); xhr.open('post', 'http://localhost:8090/upload/'); xhr.onreadystatechange = function() { if (xhr.readyState == 4 && xhr.status == 200) { var jsonData = JSON.parse(xhr.responseText); var text = jsonData.path ? '上传成功' : '上传失败'; console.log(text + ':' + jsonData.path); $("#abc").attr("src","http://localhost:8090/"+jsonData.path); clearInterval(loop); //当收到该消息时上传完毕 $(".progress span").animate({'width': "100%"}, pecent < 95 ? 200 : 0, function() { $(this).html(text); }); // if (!imagedata.path) return; // alert("imagePath="+imagedata.path); // $(".pic-list").append('<a href="' + imagedata.path + '">' + imagedata.name + '(' + imagedata.size + ')<img src="' + imagedata.path + '" /></a>'); } }; //数据发送进度,前50%展示该进度 xhr.upload.addEventListener('progress', function(e) { if (loop) return; pecent = ~~(100 * e.loaded / e.total); // $li.find(".progress span").css('width', pecent + "%"); $(".progress span").text(pecent+"%"); // console.info("progress"+pecent); // if (pecent == 50) { // mockProgress(); // } }, false); //数据后50%用模拟进度 function mockProgress() { if (loop) return; loop = setInterval(function() { pecent++; console.info(pecent); if (pecent == 99) { clearInterval(loop); } }, 100) } xhr.send(formdata); } /** * 获取blob对象的兼容性写法 * @param buffer * @param format * @returns {*} */ function getBlob(buffer, format) { try { return new Blob(buffer, {type: format}); } catch (e) { var bb = new (window.BlobBuilder || window.WebKitBlobBuilder || window.MSBlobBuilder); buffer.forEach(function(buf) { bb.append(buf); }); return bb.getBlob(format); } } /** * 获取formdata */ function getFormData() { var isNeedShim = ~navigator.userAgent.indexOf('Android') && ~navigator.vendor.indexOf('Google') && !~navigator.userAgent.indexOf('Chrome') && navigator.userAgent.match(/AppleWebKit\/(\d+)/).pop() <= 534; return isNeedShim ? new FormDataShim() : new FormData() } </script>
java
/** * 上传前压缩 * * @return */ @ResponseBody @RequestMapping("/upload") public Map<String, Object> upload(HttpServletRequest request, @RequestParam("data") MultipartFile file, String filename) throws IOException { Map<String, Object> result = new HashMap<String, Object>(); //基本属性打印 System.out.print("OriginalFilename="+file.getOriginalFilename()+"\n ContentType="+file.getContentType()+"\n Name="+file.getName()+"\n Bytes="+file.getBytes()+"\n Size="+file.getSize()); String n_dp = new SimpleDateFormat("yyyyMMdd").format(new Date()); String uploadDir = request.getSession().getServletContext().getRealPath("/attached/image/" + n_dp+"/"); File f = new File(uploadDir); if (!f.exists()) { if (f.mkdirs()) { System.out.println("创建文件夹成功!" + uploadDir); } else { System.out.println("创建文件失败"); } } String n_fn = new SimpleDateFormat("HHmmss").format(new Date()) + "_" + randomString() + ".jpg"; File targetFile = new File(uploadDir, n_fn); file.transferTo(targetFile); result.put("path", "/attached/image/" + n_dp+"/"+ n_fn); return result; } private String randomString() { long t = System.nanoTime(); String str = String.valueOf(t); return str.substring(str.length() - 7); }