技术实践
JS图片质量压缩上传
最近网站需要上传图片,之前一直是后端上传图片,图片可以控制,由于目前有写作文章以及其他发图功能,图片需要控制质量大小,太大容易造成宽带浪费,

这个图片上传压缩功能,就是写的目前这个编辑的图片上传功能,考虑到压缩情况,根据插件提供的API自定义处理上传图片,自定义压缩比列、宽度、高度、压缩最大值、压缩最小值

整个过程如下
-
用户使用file上传图片的时候,用FileReader读取用户上传的图片数据(base64格式)
-
把图片数据传入img对象,然后将img绘制到canvas上,再用canvas.toDataURL对图片进行压缩
-
获取到压缩后的base64格式图片数据,然后在把base64转成Blob,再通过axios提交formdata至服务器
注意:上传图片服务器需要把base64转成Blob,**Content-Type **需要指定为 multipart/form-data;charset=UTF-8
整体代码代码如下 compress.js
JavaScript
class Compress {
/**
* quality:0.8 默认压缩质量
* width 输出图片宽,不指定,原图输出
* height 输出图片高,不指定,原图输出
* file 文件对象
* maxSize 压缩后的最大值 kb
* minSize 最小压缩值 kb,当图片低于该值时不压缩
* @param {*} options
*/
constructor(options={}){
this.options = { quality: 0.85, width:'',height:'',file:'',maxSize:500,minSize:60}
Object.assign(this.options,options);
}
// 图片压缩
photoCompress(){
let ready = new FileReader();
/*开始读取指定的Blob对象或File对象中的内容. 当读取操作完成时,readyState属性的值会成为DONE,如果设置了onloadend事件处理程序,
则调用之.同时,result属性中将包含一个data: URL格式的字符串以表示所读取文件的内容.*/
ready.readAsDataURL(this.options.file);
let that = this;
return new Promise((resolve,reject)=>{
ready.onload=function(){
that.canvasDataURL(this.result)
.then((res)=>{
resolve(res)
})
}
ready.onerror = function(){
reject()
}
})
}
// canvas 压缩图片
canvasDataURL(path){
let img = new Image();
img.src = path;
let that = this;
return new Promise((resolve,reject)=>{
img.onload = function(){
// 默认按比例压缩
let w = this.width,
h = this.height,
scale = w / h;
w = that.options.width || w;
h = that.options.height || (w / scale);
let quality = 0.7; // 默认图片质量为0.8
//生成canvas
let canvas = document.createElement('canvas');
let ctx = canvas.getContext('2d');
// 创建属性节点
let anw = document.createAttribute("width");
anw.nodeValue = w;
let anh = document.createAttribute("height");
anh.nodeValue = h;
canvas.setAttributeNode(anw);
canvas.setAttributeNode(anh);
ctx.drawImage(this, 0, 0, w, h);
// 图像质量
if(that.options.quality && that.options.quality <= 1 && that.options.quality > 0){
quality = that.options.quality;
}
// quality值越小,所绘制出的图像越模糊
let base64 = canvas.toDataURL('image/jpeg', quality);
// 回调函数返回base64的值
resolve(base64)
}
img.onerror = function(err){
reject(err)
}
})
}
/**
* 将以base64的图片url数据转换为Blob
* @param urlData
* 用url方式表示的base64图片数据
*/
convertBase64UrlToBlob(urlData){
var arr = urlData.split(','), mime = arr[0].match(/:(.*?);/)[1],
bstr = atob(arr[1]), n = bstr.length, u8arr = new Uint8Array(n);
while(n--){
u8arr[n] = bstr.charCodeAt(n);
}
return new Blob([u8arr], {type:mime});
}
// 打开图片压缩
openPhoto(){
return new Promise((resolve,reject)=>{
let size = this.options.file.size / 1024;
// 当图片小于设置值,不用压缩
if( size <= this.options.minSize ){
let formdata = new FormData();
formdata.append('file',this.options.file,this.options.file.name);
resolve(formdata)
}else{
console.log(`压缩前:${size}kb`);
this.photoCompress()
.then((base64Codes)=>{
// 转成文件对象 方可上传服务器
var bl = this.convertBase64UrlToBlob(base64Codes);
console.log(`压缩后:${bl.size / 1024}kb`);
var formdata = new FormData();
formdata.append("file",bl,Date.parse(new Date())+".jpg");
// 判断图片是否符合要求大小
if( bl.size / 1000 > this.options.maxSize){
reject(formdata)
}else{
resolve(formdata)
}
})
.catch((err)=>{
reject(err)
})
}
})
}
}
export default Compress;
utils文件
JavaScript
/**
* 图片压缩
*/
import Compress from '@extend/compress.js'
utils.compress = function(options={}){
return new Compress(options)
}
vue组件markdown编辑器
JavaScript
<mavon-editor
:toolbarsFlag="isView"
:subfield="isView"
:boxShadow="isView"
v-model="content.content"
@change="change"
codeStyle="monokai-sublime"
placeholder="写你知道的"
ref="md"
@imgAdd="$imgAdd"
/>
本项目使用如下
JavaScript
//在我的项目使用如下
let formdata = new FormData();
formdata.append('file',file,file.name);
let compress = this.utils.compress({file,maxSize:500});
compress.openPhoto()
.then((form)=>{
// 上传图片接口我已封装
upimage(form)
.then((res)=>{
// md是该编辑器
this.$refs.md.$img2Url(pos, this.utils.imgsrc(res.path));
})
.catch((err)=>{
// 挂在到原型的提示框
this.$Message.warning(err);
})
})
.catch((err)=>{
this.$Message.warning('原文件过大,不超过500kb');
})
其他同学如若使用
html
<input type="file" id="file" name="myfile" accept="image/x-png, image/jpg, image/jpeg, image/gif"/>
JavaScript
import Compress from '@extend/compress.js'
// files[0] 拿到上传完成之后的文件对象,然后在调用图片压缩
(new Compress({file:document.getElementById("file").files[0]})).openPhoto()
.then((form)=>{
// 压缩完成后的文件对象
})
.catch((err)=>{
//处理压缩失败
})
总结:
以前觉的上传压缩特麻烦,其实现在看来很简单,理清思路即可,
其他还有直接form表单提交文件等方式,可能不太方便,有兴趣同学可以看看
参考文章
前端图片压缩上传(纯js的质量压缩,非长宽压缩)
HTML5 file API加canvas实现图片前端JS压缩并上传