之前就看到H5使用canvas就可以在前端使用JS压缩图片,这次接到任务要把这个功能嵌入到ueditor里面去,以节省流量,减轻服务器压力。

H5使用canvas进行压缩的代码有很多,核心原理就是创建Image对象,导入canvas,限制canvas大小,然后导出为base64,生成二进制对象,最后将二进制对象进行上传。

我们要修改的文件在ueditor.all.js里,第24352行:

UE.plugin.register('simpleupload', function (){
var me = this,
isLoaded = false,
containerBtn;

function initUploadBtn(){
var timestrap = (+new Date()).toString(36),
doc = containerBtn.ownerDocument,
wrapper = document.createElement('div');

wrapper.innerHTML = '<form id="edui_form_' + timestrap + '" target="edui_iframe_' + timestrap + '" method="POST" enctype="multipart/form-data" action="' + me.getOpt('serverUrl') + '" ' +
'style="display:block;width:100%;height:100%;border:0;margin:0;padding:0;position:absolute;">' +
'<input id="edui_input_' + timestrap + '" type="file" accept="image/*" name="' + me.options.imageFieldName + '" ' +
'style="background:red;display:block;width:100%;height:100%;border:0;margin:0;padding:0;position:absolute;filter:alpha(opacity=0);-moz-opacity:0;-khtml-opacity: 0;opacity: 0;">' +
'</form>' +
'<iframe id="edui_iframe_' + timestrap + '" name="edui_iframe_' + timestrap + '" ' +
'style="display:none;width:0;height:0;border:0;margin:0;padding:0;position:absolute;"></iframe>';

wrapper.className = 'edui-' + me.options.theme;
wrapper.id = me.ui.id + '_iframeupload';
containerBtn.appendChild(wrapper);

var form = doc.getElementById('edui_form_' + timestrap);
var input = doc.getElementById('edui_input_' + timestrap);
var iframe = doc.getElementById('edui_iframe_' + timestrap);

domUtils.on(input, 'change', function(){
if(!input.value) return;
var loadingId = 'loading_' + (+new Date()).toString(36);
var params = utils.serializeParam(me.queryCommandValue('serverparam')) || '';

var imageActionUrl = me.getActionUrl(me.getOpt('imageActionName'));
var allowFiles = me.getOpt('imageAllowFiles');

me.focus();
me.execCommand('inserthtml', '<img class="loadingclass" id="' + loadingId + '" src="' + me.options.themePath + me.options.theme +'/images/spacer.gif" title="' + (me.getLang('simpleupload.loading') || '') + '" >');

function callback(){
try{
var link, json, loader,
body = (iframe.contentDocument || iframe.contentWindow.document).body,
result = body.innerText || body.textContent || '';
json = (new Function("return " + result))();
link = me.options.imageUrlPrefix + json.url;
if(json.state == 'SUCCESS' && json.url) {
loader = me.document.getElementById(loadingId);
loader.setAttribute('src', link);
loader.setAttribute('_src', link);
loader.setAttribute('title', json.title || '');
loader.setAttribute('alt', json.original || '');
loader.removeAttribute('id');
domUtils.removeClasses(loader, 'loadingclass');
} else {
showErrorLoader && showErrorLoader(json.state);
}
}catch(er){
showErrorLoader && showErrorLoader(me.getLang('simpleupload.loadError'));
}
form.reset();
domUtils.un(iframe, 'load', callback);
}
function showErrorLoader(title){
if(loadingId) {
var loader = me.document.getElementById(loadingId);
domUtils.removeClasses(loader, 'loadingclass');
domUtils.addClass(loader, 'loaderrorclass');
loader.setAttribute('title', title || '');
}
}

// 判断文件格式是否错误
var filename = input.value,
fileext = filename ? filename.substr(filename.lastIndexOf('.')):'';
if (!fileext || (allowFiles && (allowFiles.join('') + '.').indexOf(fileext.toLowerCase() + '.') == -1)) {
showErrorLoader(me.getLang('simpleupload.exceedTypeError'));
return;
}

domUtils.on(iframe, 'load', callback);
form.action = utils.formatUrl(imageActionUrl + (imageActionUrl.indexOf('?') == -1 ? '?':'&') + params);
form.submit();
});

var stateTimer;
me.addListener('selectionchange', function () {
clearTimeout(stateTimer);
stateTimer = setTimeout(function() {
var state = me.queryCommandState('simpleupload');
if (state == -1) {
input.disabled = 'disabled';
} else {
input.disabled = false;
}
}, 400);
});
isLoaded = true;
}

return {
bindEvents:{
'ready': function() {
//设置loading的样式
utils.cssRule('loading',
'.loadingclass{display:inline-block;cursor:default;background: url(\''
+ this.options.themePath
+ this.options.theme +'/images/loading.gif\') no-repeat center center transparent;border:1px solid #cccccc;margin-right:1px;height: 22px;width: 22px;}\n' +
'.loaderrorclass{display:inline-block;cursor:default;background: url(\''
+ this.options.themePath
+ this.options.theme +'/images/loaderror.png\') no-repeat center center transparent;border:1px solid #cccccc;margin-right:1px;height: 22px;width: 22px;' +
'}',
this.document);
},
/* 初始化简单上传按钮 */
'simpleuploadbtnready': function(type, container) {
containerBtn = container;
me.afterConfigReady(initUploadBtn);
}
},
outputRule: function(root){
utils.each(root.getNodesByTagName('img'),function(n){
if (/\b(loaderrorclass)|(bloaderrorclass)\b/.test(n.getAttr('class'))) {
n.parentNode.removeChild(n);
}
});
},
commands: {
'simpleupload': {
queryCommandState: function () {
return isLoaded ? 0:-1;
}
}
}
}
});

这段代码是创建一个form表单包裹原先的input file图片上传文件,然后上传至服务器,上传完成后进行相应的更改。

我们需要修改的地方在文件上传之前,即修改  form.submit();删除这段代码,添加如下代码:

w.files[0] = function () {
//这里开始进行图片压缩

/**
* 获取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);
}
};
}

/**
* 获取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);
}
}

var blob = URL.createObjectURL(w.files[0]);
var img = new Image();
img.src = blob;
var obj = w.files[0];

img.onload = function () {

var _this = img;

//生成比例
var _w = _this.width,
h = _this.height;
if (_w > 1024) {
var rate = _w / 1024;
_w = 1024;
h = h / rate;
}
//生成canvas
var canvas = document.createElement('canvas');
var ctx = canvas.getContext('2d');
canvas.setAttribute('width', _w);
canvas.setAttribute('height', h);
ctx.drawImage(_this, 0, 0, _w, h);

/**
* 生成base64
* 兼容修复移动设备需要引入mobileBUGFix.js
*/
var base64 = canvas.toDataURL('image/jpeg', obj.quality || 0.8);

// 修复IOS
if (navigator.userAgent.match(/iphone/i)) {
var mpImg = new MegaPixImage(img);
mpImg.render(canvas, { maxWidth: _w, maxHeight: h, quality: obj.quality || 0.8, orientation: 6 });
base64 = canvas.toDataURL('image/jpeg', obj.quality || 0.8);
}

// 修复android
if (navigator.userAgent.match(/Android/i)) {
var encoder = new JPEGEncoder();
base64 = encoder.encode(ctx.getImageData(0, 0, _w, h), obj.quality * 100 || 80);
}

// 生成结果
var result = {
blob: blob,
base64: base64,
clearBase64: base64.substr(base64.indexOf(',') + 1)
};
// 执行后函数
//开始通过XHR发送
var xhr = new XMLHttpRequest();
var formdata = getFormData();

//base64转二进制
var text = window.atob(base64.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], "image/jpeg");
///
formdata.append('upfile', _blob, 'upfile.jpg');

xhr.onreadystatechange = function () {
if (xhr.readyState == 4 && xhr.status == 200) {
clearInterval(loop);
try {
var d, g, k, h = (r.contentDocument || r.contentWindow.document).body;
g = JSON.parse(xhr.responseText);
d = c.options.imageUrlPrefix + g.url;
"SUCCESS" == g.state && g.url ? (k = c.document.getElementById(e),
k.setAttribute("src", d),
k.setAttribute("_src", d),
k.setAttribute("title", g.title || ""),
k.setAttribute("alt", g.original || ""),
k.removeAttribute("id"),
f.removeClasses(k, "loadingclass")) : b && b(g.state)
} catch (n) {
b && b(c.getLang("simpleupload.loadError"))
}
t.reset();
f.un(r, "load", a)
}

};

xhr.open('post', 'ueditor/php/controller.php?action=uploadimage');//这里写你之前在ueditor里设置的地址
xhr.send(formdata);

//发送结束;
var _image = new Image();
_image.src = base64;
return _image;
}
//图片压缩结束
}();

图片压缩算法可以再网上换成相关其他算法。

ueditor使用canvas在图片上传前进行压缩的更多相关文章

  1. html之file标签 --- 图片上传前预览 -- FileReader

    记得以前做网站时,曾经需要实现一个图片上传到服务器前,先预览的功能.当时用html的<input type="file"/>标签一直实现不了,最后舍弃了这个标签,使用了 ...

  2. file标签 - 图片上传前预览 - FileReader & 网络图片转base64和文件流

    记得以前做网站时,曾经需要实现一个图片上传到服务器前,先预览的功能.当时用html的<input type="file"/>标签一直实现不了,最后舍弃了这个标签,使用了 ...

  3. 前端的图片压缩image-compressor(可在图片上传前实现图片压缩)

    https://www.imooc.com/article/40038 https://www.jianshu.com/p/3ce3e3865ae2 前端的图片压缩image-compressor(可 ...

  4. ASP.NET MVC图片上传前预览

    回老家过春节,大半个月,在家的日子里,吃好睡好,人也长了3.5Kg.没有电脑,没有网络,无需写代码,工作上相关的完全放下......开心与父母妻儿过个年,那样的生活令Insus.NET现在还在留恋.. ...

  5. HTML5 FileReader实现图片上传前预览

    如果你的浏览器支持Html5的FileReader的话,实现图片上传前进行预览是一件非常容易之事情. 在控制器,创建一个视图Action: jQuery代码: 实时演示一下: 下面内容于2014-11 ...

  6. input file实现多选,限制文件上传类型,图片上传前预览功能

    限制上传类型 & 多选:① accept 属性只能与 <input type="file" /> 配合使用.它规定能够通过文件上传进行提交的文件类型. ② mu ...

  7. 【转】html之file标签 --- 图片上传前预览 -- FileReader

    记得以前做网站时,曾经需要实现一个图片上传到服务器前,先预览的功能.当时用html的<input type="file"/>标签一直实现不了,最后舍弃了这个标签,使用了 ...

  8. 图片上传前 压缩,base64图片压缩 Exif.js处理ios拍照倒置等问题

    曾写过在前端把图片按比例压缩不失真上传服务器的前端和后台,可惜没有及时做总结保留代码,只记得js利用了base64位压缩和Exif.js进行图片处理,还有其中让我头疼的ios拍照上传后会倒置等诸多问题 ...

  9. 图片上传前预览、压缩、转blob、转formData等操作

    直接上代码吧: <template> <div> <div class="header">添加淘宝买号</div> <div ...

随机推荐

  1. Unity关于获取游戏对象

    我觉得Unity里面的Transform 和 GameObject就像两个双胞胎兄弟一样,这俩哥们很要好,我能直接找到你,你也能直接找到我.我看很多人喜欢在类里面去保存GameObject对象.解决G ...

  2. 在阿里云主机上基于CentOS用vsftpd搭建FTP服务器

    最近需要在一台阿里云的云服务器上搭建FTP服务器,在这篇博文中分享一下我们根据实际需求进行的一些配置. ftp软件用的是vsftpd. vsftpd是一款在Linux发行版中最受推崇的FTP服务器程序 ...

  3. win7下 安装 Flask

    参考: http://my.oschina.net/935572630/blog/375758 一 环境版本: os: win7 x64 python: 2.7.10 x64 二 安装步骤: 由于fl ...

  4. [REP]AWS Regions and Availability Zones: the simplest explanation you will ever find around

    When it comes to Amazon Web Services, there are two concepts that are extremely important and spanni ...

  5. 【转】MySQL数据丢失讨论

    原文http://blog.sae.sina.com.cn/archives/4091 1.   概述 很多企业选择 MySQL都会担心它的数据丢失问题,从而选择Oracle,但是其实并不十分清楚什么 ...

  6. web app开发之rem

    CSS3新增了一个相对单位rem,官方的解释为“font size of the root element”,相对于根元素(html)的font size. rem,em,px单位的区别: rem单位 ...

  7. Spring注解学习

    参考链接 http://blog.csdn.net/xyh820/article/details/7303330/

  8. tomcat6配置jndi连接数据库的方式

    eworkflow工作流+eform表单+ebiao报表集成在一起,用tomcat6发布,并用jndi连接数据库,数据库是sqlserver2005,配置如下: 1.在tomcat6\conf\con ...

  9. 使用xpath的轴(Axis)进行元素定位

    使用Xpath轴方式可依据在文档数中的元素的相对位置来进行定位,先找到一个相对好定位的元素,在根据与它相对位置来定位其他元素,可以解决一些元素难以定位的问题.今天学习了,写下笔记加深下印象 如家HTM ...

  10. JAVA 多线程和并发学习笔记(三)

    Java并发编程中使用Executors类创建和管理线程的用法 1.类 Executors Executors类可以看做一个“工具类”.援引JDK1.6 API中的介绍: 此包中所定义的 Execut ...