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

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

本文是前端利用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. Xilinx与modelsim的仿真联调

    关于Xilinx与modelsim的仿真联调,尤其是仿真环境的搭建,网上的信息都比较零散,我当初在联调的时候遇到比较多的问题,也是折腾了两天才弄好,下面的步骤我总结得非常详细,可以帮助大家少走弯路. ...

  2. 20155215 2006-2007-2 《Java程序设计》第2周学习总结

    20155215 2006-2007-2 <Java程序设计>第2周学习总结 教材学习内容总结 第三章主要讲述了JAVA程序编写中的一些基本语法.其实看了第三章之后我就感觉到,C语言不愧是 ...

  3. 20155232 2016-2017-2 《Java程序设计》第2周学习总结

    20155232 2016-2017-2 <Java程序设计>第2周学习总结 教材学习内容总结 类型 基本类型 整数(short.int.long) 字节(byte) -128~127 字 ...

  4. 20155234 实验三 敏捷开发与XP实践

    20155234 实验三 敏捷开发与XP实践 实验内容 1.XP基础 2.XP核心实践 3.相关工具 实验步骤 (一)敏捷开发与XP 敏捷开发(Agile Development)是一种以人为核心.迭 ...

  5. 20155333 2016-2017-2《Java程序设计》第二周学习总结

    20155333 2016-2017-2<Java程序设计>第二周学习总结 教材学习内容总结 1. Java 类型系统:基本类型和类类型(参考类型) 2. 基本类型: 整数:short整数 ...

  6. 20155334 实验四:Android程序设计

    20155334实验四:Android程序设计 实验内容 基于Android Studio开发简单的Android应用并部署测试; 了解Android组件.布局管理器的使用: 掌握Android中事件 ...

  7. Zabbix学习之路(九)之低级自动发现以及MySQL多实例

    1.概述 Zabbix的网络发现是指zabbix server通过配置好的规则,自动添加host,group,template Zabbix的主动注册刚好和网络发现是相反的,功能基本一致.zabbix ...

  8. Nginx入门篇(一)之Nginx介绍

    1.简介 Nginx ("engine x") 是一个高性能的 HTTP 和反向代理服务器,也是一个 IMAP/POP3/SMTP 服务器. Nginx 是由 Igor Sysoe ...

  9. [bzoj1500][luogu2042][cogs339][codevs1758]维修数列(维护数列)

    先给自己立一个flag 我希望上午能写完 再立一个flag 我希望下午能写完. 再立一个flag 我希望晚上能写完... 我终于A了... 6700+ms...(6728) 我成功地立了3个flag. ...

  10. Mac OS 上 VIM 8.0 安装体验

    VIM 8.0 赶在中秋前发布 The best way to install Vim on Unix is to use the sources. This requires a compiler ...