利用谷歌调式工具发现,图片大小直接影响着首屏加载时间。

且考虑到后期服务端压力,图片压缩特别必要。

本文是前端利用canvas实现图片。参考文章:https://www.cnblogs.com/007sx/p/7583202.html

本文将其改为插件形式,适合单文件压缩,多文件可以采用生成多个二进制文件的方法,然后一并上传。具体后面研究。

说说原理,压缩涉及三个关键点:

1,一个图片前端可被加载,基于file:协议的路径是不能产生onload事件,所以需要借助浏览器的接口将图片转为可加载文件,一种是通过FileReader,另一种是

通过URL.createObjectURL。

2,利用canvas,获取图片的高度和宽度之后,利用drawImage输出图片,再利用canvas的toDataURL输出base64的图片。

3,将base64转为二进制文件。

案例代码:

 <!DOCTYPE html>
<html> <head>
<meta charset="UTF-8">
<title>XMLHttpRequest上传文件压缩上传图片文件</title>
</head> <body>
<input type="file" id="file" name="myfile" accept="image/x-png, image/jpg, image/jpeg, image/gif" />
<input type="button" onclick="UpladFile()" value="上传" />
<script type="text/javascript">
(function() {
function compress(opts, fileObj) {
this.defaults = {
id: "#file",
quality: 0.4,
url: "",
callback: function(bl) {
console.log(bl);
}
}; if (typeof opts === "object") {
this.options = Object.assign({}, this.defaults, opts)
} else {
this.options = this.defaults;
}
fileObj = fileObj || document.querySelector(this.options.id).files[];
this.init(fileObj);
}
compress.prototype = {
version: "1.0.1",
init: function(fileObj) {
_this = this;
//promise处理异步
this.photoCompress(fileObj).then(function(res) {
return _this.canvasDataUrl.call(_this, res);
}).catch(function(err) {
console.log(err);
}).then(function(res) {
var bl = _this.convertBase64UrlToBlob(res);
_this.options.callback(bl);
}).catch(function(err) {
console.log(err);
}) },
photoCompress: function(file) {
var ready = new FileReader();
ready.readAsDataURL(file);
return new Promise(function(resolve, reject) {
ready.onload = function() {
var re = this.result;
resolve(re);
}
ready.onerror = function(err) {
reject(err)
}
}) },
canvasDataUrl: function(res) { var img = new Image();
img.src = res;
_this = this;
return new Promise(function(resolve, reject) {
img.onload = function() {
// 默认按比例压缩
var w = this.width,
h = this.height;
//生成canvas
var canvas = document.createElement('canvas');
var ctx = canvas.getContext('2d');
// 创建属性节点
var anw = document.createAttribute("width");
anw.nodeValue = w;
var anh = document.createAttribute("height");
anh.nodeValue = h;
canvas.setAttributeNode(anw);
canvas.setAttributeNode(anh);
ctx.drawImage(this, , , w, h); // quality值越小,所绘制出的图像越模糊
var base64 = canvas.toDataURL('image/jpeg', _this.options.quality);
// 回调函数返回base64的值
resolve(base64)
}
img.onerror = function(err) {
reject(err)
}
})
}, //base64转为二进制数据,后端可直接利用
convertBase64UrlToBlob: function(urlData) {
var arr = urlData.split(','),
mime = arr[].match(/:(.*?);/)[],
bstr = atob(arr[]),
n = bstr.length,
u8arr = new Uint8Array(n);
while (n--) {
u8arr[n] = bstr.charCodeAt(n);
}
return new Blob([u8arr], { type: mime });
}
}
window.compress = compress; })(); //上传文件方法
function UpladFile() { var url = "./upload"; // 接收上传文件的后台地址
new compress({
quality: 0.4,
url: url,
callback: function(bl) {
var form = new FormData();
form.append("file", bl, "file_" + Date.parse(new Date()) + ".jpg"); // 文件对象
var xhr = new XMLHttpRequest();
xhr.open("post", url, true);
xhr.onreadystatechange = function(evt) {
if (xhr.readyState === && xhr.status === ) {
uploadComplete(evt);
}
} xhr.send(form); //开始上传,发送form数据
}
})
} //上传成功响应
function uploadComplete(evt) {
//服务断接收完文件返回的结果
var data = JSON.parse(evt.target.responseText);
if (data.success) {
alert("上传成功!");
} else {
alert("上传失败!");
} }
</script>
</body> </html>

后端采用thinkphp5,代码index控制器下,方法

    public function upload(){

          // 获取表单上传文件 例如上传了001.jpg
$file = request()->file('file');
$arr=array("code"=>,"success"=>true);
// 移动到框架应用根目录/public/uploads/ 目录下
if($file){
$info = $file->move(ROOT_PATH . 'public' . DS . 'uploads');
if($info){ echo json_encode($arr); }else{ return "error";
// 上传失败获取错误信息
echo $file->getError();
}
};
}

多张图片上传前压缩

 <!DOCTYPE html>
<html> <head>
<meta charset="UTF-8">
<title>XMLHttpRequest上传文件压缩上传图片文件多</title>
</head> <body>
<input type="file" id="files" name="myfile" multiple accept="image/x-png, image/jpg, image/jpeg, image/gif" />
<input type="button" onclick="UpladFile()" value="上传" />
<script type="text/javascript">
/*
三个参数
file:一个是文件(类型是图片格式),
w:一个是文件压缩的后宽度,宽度越小,字节越小
objDiv:一个是容器或者回调函数
photoCompress()
*/
function photoCompress(file, w, objDiv) {
var ready = new FileReader();
/*开始读取指定的Blob对象或File对象中的内容. 当读取操作完成时,readyState属性的值会成为DONE,如果设置了onloadend事件处理程序,则调用之.同时,result属性中将包含一个data: URL格式的字符串以表示所读取文件的内容.*/
ready.readAsDataURL(file);
ready.onload = function() {
var re = this.result;
canvasDataURL(re, w, objDiv)
}
} function canvasDataURL(path, obj, callback) {
var img = new Image();
img.src = path;
img.onload = function() {
var that = this;
// 默认按比例压缩
var w = that.width,
h = that.height,
scale = w / h;
w = obj.width || w;
h = obj.height || (w / scale);
var quality = 0.7; // 默认图片质量为0.7
//生成canvas
var canvas = document.createElement('canvas');
var ctx = canvas.getContext('2d');
// 创建属性节点
var anw = document.createAttribute("width");
anw.nodeValue = w;
var anh = document.createAttribute("height");
anh.nodeValue = h;
canvas.setAttributeNode(anw);
canvas.setAttributeNode(anh);
ctx.drawImage(that, , , w, h);
// 图像质量
if (obj.quality && obj.quality <= && obj.quality > ) {
quality = obj.quality;
}
// quality值越小,所绘制出的图像越模糊
var base64 = canvas.toDataURL('image/jpeg', quality);
// 回调函数返回base64的值
callback(base64);
}
}
/**
* 将以base64的图片url数据转换为Blob
* @param urlData
* 用url方式表示的base64图片数据
*/
function convertBase64UrlToBlob(urlData) {
var arr = urlData.split(','),
mime = arr[].match(/:(.*?);/)[],
bstr = atob(arr[]),
n = bstr.length,
u8arr = new Uint8Array(n);
while (n--) {
u8arr[n] = bstr.charCodeAt(n);
}
return new Blob([u8arr], { type: mime });
} //上传文件方法
function UpladFile() { var url = "./upload"; // 接收上传文件的后台地址
var form = new FormData();
var files = document.querySelector("#files").files;
files = Array.prototype.slice.call(files);
files.forEach(function(val, index) {
photoCompress(val, {
quality: 0.2
}, function(base64Codes) {
console.log(index);
//console.log("压缩后:" + base.length / 1024 + " " + base);
var bl = convertBase64UrlToBlob(base64Codes);
form.append("file" + index, bl, "file_" + Date.parse(new Date()) + ".jpg"); // 文件对象
if (index + === files.length) {
xhr = new XMLHttpRequest(); // XMLHttpRequest 对象
xhr.open("post", url, true); //post方式,url为服务器请求地址,true 该参数规定请求是否异步处理。
xhr.onload = uploadComplete; //请求完成
xhr.send(form); //开始上传,发送form数据
}
});
})
} //上传成功响应
function uploadComplete(evt) {
//服务断接收完文件返回的结果
var data = JSON.parse(evt.target.responseText);
if (data.success) {
alert("上传成功!");
} else {
alert("上传失败!");
} }
</script>
</body> </html>

利用canvas对上传图片进行上传前压缩的更多相关文章

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

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

  2. hTML5实现表单内的上传文件框,上传前预览图片,针刷新预览images

    hTML5实现表单内的上传文件框,上传前预览图片,针刷新预览images, 本例子主要是使用HTML5 的File API,建立一個可存取到该file的url, 一个空的img标签,ID为img0,把 ...

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

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

  4. 【转】HTML5 jQuery图片上传前预览

    hTML5实现表单内的上传文件框,上传前预览图片,针刷新预览images,本例子主要是使用HTML5 的File API,建立一個可存取到该 file的url,一个空的img标签,ID为img0,把选 ...

  5. HTML5 jQuery图片上传前预览

    hTML5实现表单内的上传文件框,上传前预览图片,针刷新预览images,本例子主要是使用HTML5 的File API,建立一個可存取到该file的url,一个空的img标签,ID为img0,把选择 ...

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

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

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

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

  8. ASP利用xhEditor编辑器实现图片上传的功能。

    本人这几天在做一个软件,无意中用到xhEditor在线编辑器,这个编辑器虽然看着比较简单,但功能非常强大,大家可以去官网上查看,废话不说了. 这篇文件主要是实现在ASP环境中利用xhEditor编辑器 ...

  9. 利用Selenium实现图片文件上传的两种方式介绍

    在实现UI自动化测试过程中,有一类需求是实现图片上传,这种需求根据开发的实现方式,UI的实现方式也会不同. 一.直接利用Selenium实现 这种方式是最简单的一种实现方式,但是依赖于开发的实现. 当 ...

随机推荐

  1. U盘,移动硬盘显示显示需要格式化怎么修复

    冷静别怕,用windows系统自带磁盘修复CHKDSK命令即可解决此问题. 首先,在开始菜单栏站到“运行”窗口,也就是c:\(命令提示符),win7可直接在开始菜单的搜索窗口中输入“cmd”. 其次, ...

  2. 安装xml2js出现npm ERR! code E404 npm ERR! 404 Not Found: event-stream@3.3.6

    原因是npm源指向的问题 执行: npm config set registry https://registry.npmjs.org/

  3. node.js(二)

    今天我们学习如何运行起来一个项目,我还不会新建项目,所以我们打开一个小伙伴创建的项目,我用的开发工具是vscode 选择项目所在文件夹就好了. 打开后是这样子的 我们还要安装一下npm, 在这里安装, ...

  4. Typescript函数

    编程都是需要函数的,因为有了函数就能复用很多东西了.不仅仅能够复用代码,还能保持代码的简洁性和提高编程的逻辑性. 在原生的JavaScript中,函数的定义有三种, function foo() {} ...

  5. electron安装与使用

    系统 WIN10 X64 1. python-2.7.15.amd64.msi 2. node-v10.4.1-x64.msi 3. VS2015 community(社区版) 4. npm conf ...

  6. 20155211 2016-2017-2 《Java程序设计》第十周学习总结

    20155211 2016-2017-2 <Java程序设计>第十周学习总结 教材学习内容总结 网络编程的实质就是两个(或多个)设备(例如计算机)之间的数据传输 在实际传输数据以前需要将域 ...

  7. C#基础之委托

    委托常常和事件在一起使用,可以理解委托是方法的容器,事件则是委托的另一种表现形式.委托和事件虽然写得还比较多,不过也只是用的熟练而已,趁周末没课好好巩固下基础,一点一点积累吧. 1.一个简单的小例子 ...

  8. Oracle下建立dblink时的权限问题

    如果用普通用户,如果没授权,是无法建立dblink的: [oracle@oracle000 ~]$ sqlplus gao/gao lines) SQL Production :: Copyright ...

  9. PowerDesigner 15学习笔记:十大模型及五大分类

    个人认为PowerDesigner 最大的特点和优势就是1)提供了一整套的解决方案,面向了不同的人员提供不同的模型工具,比如有针对企业架构师的模型,有针对需求分析师的模型,有针对系统分析师和软件架构师 ...

  10. Android 测试 之adb shell

    一.发送键盘事件: 命令格式1:adb shell input keyevent "value" 其中value以及对应的key code如下表所列: KeyEvent Value ...