图片压缩上传示例
原创 1024649179 随笔工作经验 13 阅读 5 小时前
前戏
插件: bootstrap-fileinput
不了解的可以看看我的上一篇文章. 很简单.
兼容安卓端的 H5 手机图片上传插件
[核心代码来自于 github 链接, 只做小部分修改适应自己的项目] localResizeIMG https://github.com/whxaxes/node-test/blob/master/server/upload/index_2.html
完成目标
多文件上传并压缩 [问题: gif 可以压缩 但是压缩完之后就不动了... 算了 暂不解决]
引入文件
- bootstrap.min.CSS
- fileinput.min.css
给个 CND 自己去搜 http://www.bootcdn.cn/ http://www.bootcdn.cn/
html
使用 form 表单提交我们的图片 注意: enctype="multipart/form-data" 因为我们是使用 formdata 提交所以别忘记写
- <form enctype="multipart/form-data">
- <input id="file-select" type="file" multiple>
- <input type="button" id="subTaskBtn" class="button button-fill button-big" value="提交" />
- </form>
JS 主要功能
我们需要在页面中加入这些 JS 代码 自行修改适合自己项目的代码
先压缩图片
用一个全局变量把压缩过的图片保存下来
用户点击提交表单的时候 把图片也上传过去
- var compressData;// 保存图片的变量
- var fileInput = document.querySelector('#file-select');
- var formData = new FormData(document.querySelector('form'));
- // 用于压缩图片的 canvas
- var canvas = document.createElement("canvas");
- var ctx = canvas.getContext('2d');
- // 瓦片 canvas
- var tCanvas = document.createElement("canvas");
- var tctx = tCanvas.getContext("2d");
- var maxsize = 100 * 1024;
- fileInput.addEventListener('change', function (e) {
- 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(!/\/(?: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;
- // 如果图片大小小于 100kb, 则直接上传
- if(result.length <= maxsize) {
- img = null;
- compressData = compress(img);
- return;
- }
- // 图片加载完毕之后进行压缩, 然后上传
- if(img.complete) {
- callback();
- } else {
- img.onload = callback;
- }
- function callback() {
- compressData = compress(img);
- img = null;
- }
- };
- reader.readAsDataURL(file);
- })
- });
上传图片
- $('#subTaskBtn').on('click',function(e){
- formData = new FormData(document.querySelector('form'));
- var text = window.atob(compressData.split(",")[1]);
- var buffer = new Uint8Array(text.length);
- for(var i = 0; i <text.length; i++) {
- buffer[i] = text.charCodeAt(i);
- }
- var blob = getBlob([buffer], 'image/jpeg');
- // 把后台需要的参数名和保存的图片放到 formData 中
- formData.append('task.issueImageOneFile', blob);
- $.ajax({
- async: false,
- cache: false,
- type: "post",
- data: formData,
- url: '你提交的地址',
- dataType: 'json',
- contentType: false, // 必须
- processData: false, // 必须
- success: function(e) {
- // 提交成功后的提示
- },
- error: function(arg1, arg2, arg3) {
- $.alert(arg1 + "--" + arg2 + "--" + arg3);
- }
- });
- })
JS 封装方法
对于很懒的朋友可以不用看这个 记得保存到文件 或者直接放入页面引入就可以了
- // 压缩的方法
- 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;
- }
- /**
- * 获取 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()
- }
- /**
- * formdata 补丁, 给不支持 formdata 上传 blob 的 android 机打补丁
- * @constructor
- */
- function FormDataShim() {
- console.warn('using formdata shim');
- 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);
- }
- };
- }
来源: http://www.qdfuns.com/article/24547/72d7330d01b037d56f927b060affeb0c.html