Canvas实现图片压缩上传

接到产品需求,问能不能将前端上传的图片压缩?像移动端上传图片,一般都是超清、高清图片,大小也有10M,甚至一张图片大小有15M左右,这样大的图片上传到腾讯云或者阿里云(没使用服务器上传图片)一方面上传速度慢,影响体验,另一方面体积太大占空间,图片压缩避免了,网上搜到了很多这方面介绍的网址,大多数都是用canvas来实现(不说了,马上开干)!。

实现过程 (10M => 200k左右)

1. 图片裁剪

大体的思路是将图片抽样显示在canvas上,然后用通过canvas.toDataURL方法得到base64字符串来实现压缩。上代码!!!

const file: {} = e.target.files[0]; // 通过input元素触发的change事件
const reader = new FileReader(),
img = new Image();
// 缩放图片需要的canvas
const canvas = document.createElement('canvas');
const context = canvas.getContext('2d');
reader.readAsDataURL(file);
// base64地址图片加载完毕后
img.onload = function () {
// 图片原始尺寸
const originWidth = this['width'];
const originHeight = this['height'];
// 最大尺寸限制
const maxWidth = 750, maxHeight = 400;
// 目标尺寸
let targetWidth = originWidth, targetHeight = originHeight;
// 图片尺寸超过750x400的限制
if (originWidth > maxWidth || originHeight > maxHeight) {
if (originWidth / originHeight > maxWidth / maxHeight) {
// 更宽,按照宽度限定尺寸
targetWidth = maxWidth;
targetHeight = Math.round(maxWidth * (originHeight / originWidth));
} else {
targetHeight = maxHeight;
targetWidth = Math.round(maxHeight * (originWidth / originHeight));
}
}

// canvas对图片进行缩放
canvas.width = targetWidth;
canvas.height = targetHeight;
// 清除画布
context.clearRect(0, 0, targetWidth, targetHeight);
// 图片压缩
context.drawImage(img, 0, 0, targetWidth, targetHeight);
// canvas转为blob并上传
// * 很多PC、手机浏览器不支持toBlob方法,如Safari*
// 不推荐使用toBlob方法
// canvas.toBlob(function($Blob) {
// })
const dataUrl = canvas.toDataURL('image/jpeg');
updateImgForBase64(dataUrl);
}
reader.onload = function (e) {
img.src = e.target['result'];
};

2. 上传到腾讯云

项目中图片是保存在腾讯云中,这里就需要用到腾讯JavaScript SDK,按照SDK文档去新建存储桶获取Bucket、Region,直接上代码:

updateImgForBase64(img: string, type: string = 'jpeg'): Promise<any> {
const vm = this;
const storeAs = `avatar/${new Date().getTime()}-${this.guid()}.${type}`;
const dataURLtoFile: Function = (dataurl, filename) => {
const arr = dataurl.split(','), mime = arr[0].match(/:(.*?);/)[1];
const bstr = atob(arr[1]);
let n = bstr.length;
const u8arr = new Uint8Array(n);
while (n--) {
u8arr[n] = bstr.charCodeAt(n);
}
return new File([u8arr], filename, {type: mime});
};
const file = dataURLtoFile(img, type);

// function getBlobBydataURI(dataURI, type) {
// var binary = atob(dataURI.split(',')[1]);
// var array = [];
// for (var i = 0; i < binary.length; i++) {
// array.push(binary.charCodeAt(i));
// }
// return new Blob([new Uint8Array(array)], {type: type});
// }
//
// /**
// * 上传 formData.append("files", $Blob, storeAs);对iOS系统不支持
// */
// //base64 转 blob
// let $Blob = getBlobBydataURI(img, 'image/jpeg');
// let formData = new FormData();
// let storeAs = `documents/${new Date().getTime()}-${this.guid()}.${type}`;
// formData.append("files", $Blob, storeAs);
//组建XMLHttpRequest 上传文件
return new Promise((resolve, reject) => {
this.cos.sliceUploadFile({
Bucket: 'your bucket',
Region: 'your region',
Key: storeAs,
Body: file
}, function (err, data) {
if (err) {
reject(JSON.stringify(err));
} else {
resolve(url);
}
});
})
}