原理大概就是:
1、先将图片的file文件转成baseURL
2、创建一个image标签去接收文件获取图片的宽高和比例。
3、创建canvas画布设置画布的大小。
4、将图片绘制到canvas上面。
5、对canvas进行压缩处理,获得新的baseURL
6、将baseURL转化回文件。
创建compress.js文件
import { Message } from 'element-ui'
class Compress {
constructor(file,width = -1,quality = 0.92,targetSize = 3){
this.file = file//文件
this.width = width//不传初始赋值-1,等比缩放不用传高度
this.quality = quality//不传初始赋值0.92。值范围0~1
this.targetSize = targetSize//目标大小,控制上传图片大小 传值方式:targetSize:1 * 1024 * 1024的值默认3m
}
// 压缩
compressUpload(){
const rawImage = this.file//获取文件
if(!rawImage) return false
if(!this.isImage(rawImage)){
Message.error('图片只支持.jpg, .png, .bmp, .jpeg, .webp格式!')
return false
}
return new Promise(async (resolve,reject) => {
if(!this.isLimitSize(rawImage)){
// 需压缩
let imageFile = await this.readImage(rawImage)
console.log('imageFile',imageFile)
resolve({
file:imageFile.file
})
console.log('压缩后上传')
}else{
// 无需压缩
resolve({
file:rawImage
})
console.log('原图上传')
}
})
}
/**
* @desc 图片压缩
* @param image 被压缩的img对象
* @param type 压缩后转换的文件类型
**/
// 对图片进行处理
readImage(file){
return new Promise((resolve,reject) => {
let data = ""//保存地址
const reader = new FileReader()
// 读取文件并将文件以URL的形式保存在resulr属性中 base64格式
reader.readAsDataURL(file)
// 文件读取完成时触发
reader.onload = async e => {
const image = new Image()
if(typeof e.target.result === 'object'){
// 把Array Buffer转化为blob 如果是base64不需要
data = window.URL.createObjectURL(new Blob([e.target.result]))
}else{
data = e.target.result//base64格式图片地址
}
image.src = data
image.onload = async e => {
const canvas = document.createElement('canvas')
const context = canvas.getContext('2d')
const { width: originWidth, height: originHeight } = image
// 目标尺寸
let targetWidth = originWidth
let targetHeight = originHeight
// 获得长宽比例
const scale = targetWidth / targetHeight;
//获取压缩后的图片宽度,如果width为-1,默认原图宽度
targetWidth = this.width == -1 ? targetWidth : this.width;
//获取压缩后的图片高度,如果width为-1,默认原图高度
targetHeight = this.width == -1 ? targetHeight : parseInt(this.width / scale);
canvas.width = targetWidth
canvas.height = targetHeight
context.clearRect(0, 0, targetWidth, targetHeight)
context.fillStyle = '#fff'
// 图片绘制
context.drawImage(image, 0, 0, targetWidth, targetHeight)
let dataUrl = canvas.toDataURL(file.type, this.quality || 0.92)//0.92为压缩比,可根据需要设置,设置过小会影响图片质量
let fileObj = await this.dataURItoBlob(dataUrl,file.type,file)
resolve(fileObj)
}
}
reader.onerror = e => {
Message.error('图片读取出错!')
}
})
}
// base64转为Blob
async dataURItoBlob(dataurl,type = "image/png",file){
return new Promise((resolve,reject) => {
const filename = 'file'
let arr = dataurl.split(',')
let mime = arr[0].match(/:(.*?);/)[1]
let suffix = mime.split('/')[1]
let bstr = atob(arr[1])
let n = bstr.length
let u8arr = new Uint8Array(n)
while (n--) {
u8arr[n] = bstr.charCodeAt(n)
}
const miniFile = new File([u8arr], `${filename}.${suffix}`, {type: mime})
console.log({
file:miniFile,
origin:file,
beforeKB:Number((file.size / 1024).toFixed(2)),
afterKB:Number((miniFile.size / 1024).toFixed(2)),
})
resolve({
file:miniFile,
origin:file,
beforeKB:Number((file.size / 1024).toFixed(2)),
afterKB:Number((miniFile.size / 1024).toFixed(2))
})
})
}
// 判断上传的图片格式是否符合要求
isImage(image){
return /\.(jpg|png|bmp|jpeg|webp|gif)$/.test(image.name)
}
// 判断图片是否过大
isLimitSize(image){
const isLimitSize = this.targetSize < (image.size / 1024 / 1024)
// console.log('size',image.size)
// console.log('isLimitSize',isLimitSize)
// console.log('targetSize',this.targetSize)
// console.log(image)
if(!isLimitSize){
return true
}else{
return false
}
}
}
export default Compress
使用
import Compress from '@/utils/compress'
let imgfile = new Compress(file,600,this.ratio)
imgfile.compressUpload().then(res => {
//请求
})