图片压缩上传
不管是前端还是后端的开发人员,基本上都会使用到过图片上传,为了衡量网络传输性能,我们会对上传的图片进行压缩。
前端进行压缩是为了用户使用体验更优和网络传输压力更小,后端进行压缩是为了图片存储更优。
这里我是用vant.js的uploader组件,进行图片压缩和上传。
先描述一下我的需求: 是表单页面的数据一次提交给后端(包括表单数据和图片数据)
遇到的问题: 点击提交按钮无反应,上传图片的预览显示不出上传图片的缩略图。
解决思路:
(1)首先提交按钮无反应,原因是表单数据和图片数据一次性提供给接口的时候,前后端通信时间长,用户可能没耐心以为未点击成功,出现重复点击情况,调起多起数据访问请求。
(2)上传图片的缩略图不显示问题可能是由于图片未进行压缩,相机拍摄出的照片像素过大,手机网络信号差及内存小等综合性原因。
解决方法:
(1)给提交按钮加一个进度条,方便用户看到进度条提示,不进行重复点击操作,另外给按钮添加限制,一个交互过程未结束的情况下不重复发起交互通信。
// 进度条这里暂用vant.js中的
import Vue from 'vue';
import { Progress } from 'vant';
Vue.use(Progress);
// 可自行设计进度条样式
<van-progress :percentage="50" />
(2)图片过大,前后端传输过程中所需时间长,成本高,效率低,在网速慢的情况下更容易出现问题。所以在前后端通信交互前,前端进行本地压缩。
这里可以使用beforeRead和afterRead函数选择压缩,beforeRead是选择文件是压缩并把文件数据存在页面上,afterRead是选择文件上传在页面后再进行图片压缩。
afterRead方式可能存在图片过大手机端出现缩略图不显示的问题,建议使用beforeRead方式,缩略图显示正常,减少性能损耗。
// 这里限制只上传一张展品,可设置多张,加下multiple,max-count可以设置多
<van-uploader v-model="fileList" :max-count="1" :after-read="afterRead" :before-read="beforeRead" />
import Vue from 'vue';
import { Uploader } from 'vant';
Vue.use(Uploader);
beforeRead(file) {
// 上传之前检测图片类似返回true和false会影响到onRead函数
let _this = this;
let regex = /(.jpg|.jpeg|.png|.bmp)$/
if (!regex.test(file.type)) {
Toast('图片格式不支持上传')
return false
} else {
//自己定义的文件大小,超过多少M就开始压缩(现在是1M)
let maxSize = 1 * 1024 * 1024;
let fileObj = file; // 当前的图片
if(file.size > maxSize){
//实例化文件读取对象
var reader = new FileReader();
//将文件读取为 DataURL,也就是base64编码
reader.readAsDataURL(file);
//文件读取成功完成时触发
reader.onload = function(ev) {
//获得文件读取成功后的DataURL,也就是base64编码
var dataURL = ev.target.result;
var files = {content:dataURL,file:fileObj}
_this.imgcompress(fileObj, files);
}
}
}
},
afterRead(file) {
console.log(file)
},
imgcompress(file, files) {
const img = document.createElement("img");
// 读取文件资源实例
const reader = new FileReader();
//读取图片资源
reader.readAsDataURL(file);
reader.onload = (e) => {
//读取成功
let _this = this;
img.src = e.target.result;
img.onload = function () {
//上传的图片的宽高
const { width: originWidth, height: originHeight } = img;
//设置一个canvas 的最大宽高
const maxWidth = 1024, maxHight = 1024;
if (originWidth > maxWidth || originHeight > maxHight) {
//计算出图片的缩放比例
if (originWidth > originHeight) {
//宽 大于 高
const Proportion = Math.ceil(originWidth / maxWidth);
//目标的宽度
let targetWidht = parseInt(originWidth / Proportion);
//目标的高度
let targetHeight = parseInt(originHeight / Proportion);
_this.createCanvasCompress(targetWidht, targetHeight, img, files, 1);
} else {
//高大于宽
const Proportion = Math.ceil(originHeight / maxHight);
//目标的宽度
let targetWidht = parseInt(originWidth / Proportion);
//目标的高度
let targetHeight = parseInt(originHeight / Proportion);
let bold = _this.createCanvasCompress(targetWidht, targetHeight, img, files, 1);
}
} else {
let quality = 0.8;
_this.createCanvasCompress(originWidth, originHeight, img, files, quality);
}
}
};
},
createCanvasCompress(targetWidth, targetHeight, img, files, quality) {
let _this = this;
return new Promise((resolve, reject) => {
const canvas = document.createElement("canvas");
const context = canvas.getContext("2d");
// 设置宽高度为等同于要压缩图片的尺寸
canvas.width = targetWidth;
canvas.height = targetHeight;
context.clearRect(0, 0, targetWidth, targetHeight);
//将img绘制到画布上
console.log(targetWidth, targetHeight);
context.drawImage(img, 0, 0, targetWidth, targetHeight);
files.content = canvas.toDataURL(files.file.type, quality); // 0.92为默认压缩质量
const newFile = this.dataURLtoFile(files.content, files.file.name);
let obj = {content: files.content, file: newFile}
let commonImg = []
commonImg.push(obj)
this.fileList = commonImg;
return true
});
},
(3) 这里有几个图片格式转换的方法如下:
1.文件转化为base64格式
// 文件转化为base64格式
filetoBase(file) {
//实例化文件读取对象
var reader = new FileReader();
//将文件读取为 DataURL,也就是base64编码
reader.readAsDataURL(file);
//文件读取成功完成时触发
reader.onload = function (ev) {
//获得文件读取成功后的DataURL,也就是base64编码
var dataURL = ev.target.result;
console.log(dataURL);
return dataURL
}
},
2.将base64转换为file文件
// 将base64转换为file文件
dataURLtoFile (dataurl, filename) {
let arr = dataurl.split(',')
let mime = arr[0].match(/:(.*?);/)[1]
let bstr = atob(arr[1])
let n = bstr.length
let u8arr = new Uint8Array(n)
while (n--) {
u8arr[n] = bstr.charCodeAt(n)
}
return new File([u8arr], filename, {type: mime})
},
3.网络链接图片转base64
// 网络链接图片转base64
imgToBase64(url,cb){
var canvas = document.createElement('canvas'),
ctx = canvas.getContext('2d'),
img = new Image;
img.crossOrigin = 'Anonymous';
img.onload = function () {
canvas.height = img.height;
canvas.width = img.width;
ctx.drawImage(img, 0, 0);
var dataURL = canvas.toDataURL('image/png');
cb && cb(dataURL);
canvas = null;
};
img.src = url;
},
4.base64转文件格式
// base64转文件格式
base64toFile(base, filename){
var arr = base.split(',');
var mime = arr[0].match(/:(.*?);/)[1];
var bstr = atob(arr[1]);
var n = bstr.length;
var u8arr = new Uint8Array(n);
while (n--) {
u8arr[n] = bstr.charCodeAt(n);
}
//转换成file对象
return new File([u8arr], filename, { type: mime });
}