js等比压缩上传
一、js文件,这个是封装过的,借用了网络上的代码然后修改的
(function(window,undefined){ var upload = function(){ this.init(); }; upload.prototype={ init:function(){ var inputDom = document.createElement("input"); inputDom.type = "file"; inputDom.setAttribute("accept","image/*"); inputDom.setAttribute("multiple","multiple"); this.inputDom = inputDom; this.bindChange(); }, start:function(o){ this.opt = this.setOpt(o); this.inputDom.value = ""; this.canvasBefore(); this.inputDom.click(); }, bindChange:function(){ var dom = this.inputDom; var that = this; dom.onchange = function() { try{ if (!this.files.length) return; var files = Array.prototype.slice.call(this.files); if (files.length > 1) { alert("最多只可上传1张图片"); return; } _shade_layer.show("上传中,请稍后..."); files.forEach(function(file, i) { if (!/\/(?:jpeg|png|gif)/i.test(file.type)) return; var reader = new FileReader(); //获取图片大小 var size = file.size / 1024 > 1024 ? (~~ (10 * file.size / 1024 / 1024)) / 10 + "MB": ~~ (file.size / 1024) + "KB"; reader.onload = function() { var result = this.result; var img = new Image(); img.src = result; //超出大小 if(result.length > that.opt.maxSize){ alert("图片大小不能超过5M"); _shade_layer.hide(); return; } //如果图片大小小于100kb,则直接上传 if (result.length <= that.opt.minSize) { img = null; that.upload(result, file.type); return; } //图片加载完毕之后进行压缩,然后上传 if (img.complete) { callback(); } else { img.onload = callback; } function callback() { var data = that.compress(img); that.upload(data, file.type); img = null; } }; reader.readAsDataURL(file); }) }catch(e){ _shade_layer.hide(); alert("上传出现错误"); return ; } }; }, /** * 绘制压缩图片的canvas */ canvasBefore:function(){ var canvasDom = document.getElementById("canvas_id"); if(canvasDom){canvasDom.parent().remove();} var tCanvasDom = document.getElementById("tCanvas_id"); if(tCanvasDom){tCanvasDom.parent().remove();} //用于压缩图片的canvas var canvas = document.createElement("canvas"); canvas.id = "canvas_id"; this.canvas = canvas; this.ctx = canvas.getContext('2d'); //瓦片canvas var tCanvas = document.createElement("canvas"); tCanvas.id = "tCanvas_id"; this.tCanvas = tCanvas; this.tctx = tCanvas.getContext("2d"); }, /** * 使用canvas对大图片进行压缩 * @param {} img 图片对象 * @return {} */ compress:function(img) { var canvas = this.canvas; var tCanvas = this.tCanvas; var tctx = this.tctx; var ctx = this.ctx; 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', this.opt.proportion); /* console.log('压缩前:' + initSize); console.log('压缩后:' + ndata.length); console.log('压缩率:' + ~~ (100 * (initSize - ndata.length) / initSize) + "%"); */ tCanvas.width = tCanvas.height = canvas.width = canvas.height = 0; this.canvas = canvas; this.tCanvas = tCanvas; this.tctx = tctx; this.ctx = ctx; return ndata; }, /** * 获取blob对象的兼容性写法 * @param buffer * @param format * @returns {*} */ getBlob:function(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 * @return {} */ getFormData:function() { var isNeedShim = ~navigator.userAgent.indexOf('Android') && ~navigator.vendor.indexOf('Google') && !~navigator.userAgent.indexOf('Chrome') && navigator.userAgent.match(/AppleWebKit\/(\d+)/).pop() <= 534; return isNeedShim ? new this.FormDataShim() : new FormData(); }, /** * formdata 补丁, 给不支持formdata上传blob的android机打补丁 */ FormDataShim:function() { var o = this, parts = [], boundary = Array(21).join('-') + ( + new Date() * (1e16 * Math.random())).toString(36), oldSend = XMLHttpRequest.prototype.send; this.append = function(name, value, filename) { parts.push('--' + boundary + '\r\nContent-Disposition: form-data; name="' + name + '"'); if (value instanceof Blob) { parts.push('; filename="' + (filename || 'blob') + '"\r\nContent-Type: ' + value.type + '\r\n\r\n'); parts.push(value); } else { parts.push('\r\n\r\n' + value); } parts.push('\r\n'); }; // Override XHR send() XMLHttpRequest.prototype.send = function(val) { var fr, data, oXHR = this; if (val === o) { // Append the final boundary string parts.push('--' + boundary + '--\r\n'); // Create the blob data = getBlob(parts); // Set up and read the blob into an array to be sent fr = new FileReader(); fr.onload = function() { oldSend.call(oXHR, fr.result); }; fr.onerror = function(err) { throw err; }; fr.readAsArrayBuffer(data); // Set the multipart content type and boudary this.setRequestHeader('Content-Type', 'multipart/form-data; boundary=' + boundary); XMLHttpRequest.prototype.send = oldSend; } else { oldSend.call(this, val); } }; }, /** * 图片上传,将base64的图片转成二进制对象,塞进formdata上传 * @param {} basestr * @param {} type * @param {} $li */ upload:function(basestr, type) { var that = this; 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 = this.getBlob([buffer], type); var xhr = new XMLHttpRequest(); var formdata = this.getFormData(); formdata.append('imagefile', blob); xhr.open('post', this.opt.uploadURL); xhr.onreadystatechange = function() { this.canvas = null; this.tCanvas = null; this.tctx = null; this.ctx = null; var func = that.opt.callBackFunc; var id = that.opt.id; var oDataObj = that.opt.oDataObj; var nType = that.opt.nType; var frameCallBackFunc = that.opt.frameCallBackFunc; var strCallbackFunc = that.opt.strCallbackFunc; oDataObj["strCallbackFunc"] = strCallbackFunc; oDataObj["nType"] = nType; if (xhr.readyState == 4 && xhr.status == 200) { var url = xhr.responseText || ""; console.log(url); var nState = url.length == 0 ? -1 : 0; var strMsg = url.length == 0 ? "上传失败" : url; oDataObj["nState"] = nState; oDataObj["strMsg"] = strMsg; oDataObj = JSON.stringify(oDataObj); eval(frameCallBackFunc+"('"+oDataObj+"')"); _shade_layer.hide(); } if(xhr.status != 200){ oDataObj["nState"] = -1; oDataObj["strMsg"] = "上传失败"; oDataObj = JSON.stringify(oDataObj); eval(frameCallBackFunc+"('"+oDataObj+"')"); _shade_layer.hide(); } }; xhr.send(formdata); },setOpt:function(o){ var defaultOptions={ nType:'', //回调的不同类型,通过这个类型来改_plus.callbackuploadPicture里面对于回调的具体方法,其实主要就是控制最终回调函数的参数 minSize:100 * 1024, //最小为100kb,也就是说100kb以下的不压缩直接上传 maxSize:1024 * 1024 * 5, //最大为10M,也就是说100kb以下的不压缩直接上传 proportion:0.3, //压缩比例:从0-1之间 strCallbackFunc:'', frameCallBackFunc:'', oDataObj:{}, uploadURL:'http://pocketwap.xxx.com/Servlet/fileUpload.svl' }; if(o && Object.prototype.toString.call(o)=='[object Object]') { for(var k in o) { defaultOptions[k]= typeof o[k]==='undefined' ? defaultOptions[k] : o[k]; } } return defaultOptions; } } window.upload=upload; })(window,undefined) var _upload = new upload();
二、js页面使用如下:
_upload.start({ id:Id, callBackFunc:strCallbackFunc //回调地址 });
三、服务端接收,这边因为是要统一上传到文件服务器,所以这里中转了一下,如果不需要中转,直接就可以在这里面处理就行
package com.xxx.businesscenter.web; import java.io.BufferedInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.io.InputStream; import java.net.HttpURLConnection; import java.net.URL; import java.util.List; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.commons.fileupload.FileItem; import org.apache.commons.fileupload.FileUploadException; import org.apache.commons.fileupload.disk.DiskFileItemFactory; import org.apache.commons.fileupload.servlet.ServletFileUpload; import org.apache.log4j.Logger; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import com.cdoframework.cdolib.base.UUidGenerator; /** * Servlet implementation class FileUploadServlet */ public class FileUploadServlet extends HttpServlet { private static final long serialVersionUID = 1L; private Logger log=Logger.getLogger(ApplicationListener.class); /** * @see HttpServlet#HttpServlet() */ public FileUploadServlet() { super(); // TODO Auto-generated constructor stub } /** * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response) */ protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // TODO Auto-generated method stub this.doPost(request, response); } /** * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response) */ protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // TODO Auto-generated method stub String strResult = ""; DiskFileItemFactory factory = new DiskFileItemFactory(); ServletFileUpload upload = new ServletFileUpload(factory); try { List<FileItem> items = upload.parseRequest(request); if(items.size() > 0 ){ FileItem item = items.get(0); if(!item.isFormField()){ strResult = uploadFile(item); } } } catch (FileUploadException e) { log.info(e); } response.getWriter().print(strResult); } private String uploadFile(FileItem item) { String contentType = item.getContentType(); String postfix = contentType.split("/")[1]; String result = ""; String end = "\r\n"; String twoHyphens = "--"; String boundary = "*****"; String newName = UUidGenerator.genenator() + "."+postfix; String actionUrl = "http://file.xxx.com.cn/Servlet/fileUpload.svl"; BufferedInputStream bufin = null; InputStream is = null; try { URL url = new URL(actionUrl); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setConnectTimeout(10000); //超时时间为10秒 conn.setDoInput(true); conn.setDoOutput(true); conn.setUseCaches(false); conn.setRequestMethod("POST"); conn.setRequestProperty("Connection", "Keep-Alive"); conn.setRequestProperty("Charset", "UTF-8"); conn.setRequestProperty("Content-Type","multipart/form-data;boundary=" + boundary); DataOutputStream ds = new DataOutputStream(conn.getOutputStream()); ds.writeBytes(twoHyphens + boundary + end); ds.writeBytes("Content-Disposition: form-data; " + "name=\"file1\";filename=\"" + newName + "\"" + end); ds.writeBytes("Content-Type:" + contentType + "\r\n\r\n"); bufin = new BufferedInputStream(item.getInputStream()); int bufferSize = 2048; byte[] buffer = new byte[bufferSize]; int length = -1; while ((length = bufin.read(buffer)) != -1) { ds.write(buffer, 0, length); } ds.writeBytes(end); ds.writeBytes(twoHyphens + boundary + twoHyphens + end); bufin.close(); ds.flush(); //获取上传返回结果 int code = conn.getResponseCode(); is = conn.getInputStream(); int ch; StringBuffer b = new StringBuffer(); while ((ch = is.read()) != -1) { b.append((char) ch); } String str = b.toString(); log.info("-------------------------"+str); if (conn.getResponseCode() == 200) { if(str.length() > 0 ){ JSONObject jObject = JSON.parseObject(str); String strFilePath = (String) jObject.get("strFilePath"); String strFileName = (String) jObject.get("strFileName"); result = strFilePath+strFileName; log.info("-------------------------图片上传地址="+result); } }else{ log.info("-------------------------上传失败code="+code); } } catch (Exception e) { log.info(e); return result; }finally{ try { if(bufin!=null){ bufin.close(); } if(is!=null){ is.close(); } } catch (IOException e) { log.info("-------------------------流关闭失败-------------------------"); e.printStackTrace(); } } return result; } }