利用canvas对上传图片进行上传前压缩
利用谷歌调式工具发现,图片大小直接影响着首屏加载时间。
且考虑到后期服务端压力,图片压缩特别必要。
本文是前端利用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对上传图片进行上传前压缩的更多相关文章
- 图片上传前 压缩,base64图片压缩 Exif.js处理ios拍照倒置等问题
曾写过在前端把图片按比例压缩不失真上传服务器的前端和后台,可惜没有及时做总结保留代码,只记得js利用了base64位压缩和Exif.js进行图片处理,还有其中让我头疼的ios拍照上传后会倒置等诸多问题 ...
- hTML5实现表单内的上传文件框,上传前预览图片,针刷新预览images
hTML5实现表单内的上传文件框,上传前预览图片,针刷新预览images, 本例子主要是使用HTML5 的File API,建立一個可存取到该file的url, 一个空的img标签,ID为img0,把 ...
- html之file标签 --- 图片上传前预览 -- FileReader
记得以前做网站时,曾经需要实现一个图片上传到服务器前,先预览的功能.当时用html的<input type="file"/>标签一直实现不了,最后舍弃了这个标签,使用了 ...
- 【转】HTML5 jQuery图片上传前预览
hTML5实现表单内的上传文件框,上传前预览图片,针刷新预览images,本例子主要是使用HTML5 的File API,建立一個可存取到该 file的url,一个空的img标签,ID为img0,把选 ...
- HTML5 jQuery图片上传前预览
hTML5实现表单内的上传文件框,上传前预览图片,针刷新预览images,本例子主要是使用HTML5 的File API,建立一個可存取到该file的url,一个空的img标签,ID为img0,把选择 ...
- file标签 - 图片上传前预览 - FileReader & 网络图片转base64和文件流
记得以前做网站时,曾经需要实现一个图片上传到服务器前,先预览的功能.当时用html的<input type="file"/>标签一直实现不了,最后舍弃了这个标签,使用了 ...
- 前端的图片压缩image-compressor(可在图片上传前实现图片压缩)
https://www.imooc.com/article/40038 https://www.jianshu.com/p/3ce3e3865ae2 前端的图片压缩image-compressor(可 ...
- ASP利用xhEditor编辑器实现图片上传的功能。
本人这几天在做一个软件,无意中用到xhEditor在线编辑器,这个编辑器虽然看着比较简单,但功能非常强大,大家可以去官网上查看,废话不说了. 这篇文件主要是实现在ASP环境中利用xhEditor编辑器 ...
- 利用Selenium实现图片文件上传的两种方式介绍
在实现UI自动化测试过程中,有一类需求是实现图片上传,这种需求根据开发的实现方式,UI的实现方式也会不同. 一.直接利用Selenium实现 这种方式是最简单的一种实现方式,但是依赖于开发的实现. 当 ...
随机推荐
- CVE-2018-8174 EXP 0day python
usage: CVE-2018-8174.py [-h] -u URL -o OUTPUT [-i IP] [-p PORT] Exploit for CVE-2018-8174 optional a ...
- Git最常用的命令 总结
stage/unstage git add xxx.xx 和 git reset HEAD xxx.xx 前者将本地的修改提交到index(此操作成为stage,参考备注1),后者将已提交到inde ...
- Using Angular 1.x With ES6 and Webpack
http://angular-tips.com/blog/2015/06/using-angular-1-dot-x-with-es6-and-webpack/
- 20155224 2016-2017-2 《Java程序设计》第9周学习总结
20155224 2016-2017-2 <Java程序设计>第9周学习总结 教材学习内容总结 第十六章 JDBC入门 驱动的四种类型 JDBC-ODBC Bridge Driver Na ...
- js获取IE版本,while代码很特别
<!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content ...
- spring源码-aop动态代理-5.3
一.动态代理,这是一个很强大的东西哦.研发过程中我们会常用很多业务类,但是存在一个问题.如何在不修改源码逻辑的情况下,加入自己的相关逻辑.比如异常处理,日志记录等! 二.Java动态代理的两种方式JD ...
- git在windows7下面使用
1. 首选安装. 2. 打开Git Bash 3. 输入,就是配置一下用户名啥的 $ git config --global user.name "Jack Liao" $ git ...
- Android线程管理(一)——线程通信
线程通信.ActivityThread及Thread类是理解Android线程管理的关键. 线程,作为CPU调度资源的基本单位,在Android等针对嵌入式设备的操作系统中,有着非常重要和基础的作用. ...
- avaweb(三十二)——JDBC学习入门
一.JDBC相关概念介绍 1.1.数据库驱动 这里的驱动的概念和平时听到的那种驱动的概念是一样的,比如平时购买的声卡,网卡直接插到计算机上面是不能用的,必须要安装相应的驱动程序之后才能够使用声卡和网卡 ...
- [.NET] 使用HttpClient操作HFS (HTTP File Server)
前言 本篇文章介绍如何使用HttpClient操作HFS (HTTP File Server),为自己留个纪录也希望能帮助到有需要的开发人员.关于HTTP File Server的介绍.安装.设定,可 ...