vue/H5图片压缩/压缩后上传
图片压缩:通过canvas进行图片压缩
// 图片压缩
/**
* imgSrc 地址
* scale 压缩质量 0-1
* type 文件类型
*/
const compressImg =function(imgSrc, scale, type, callback) {
// uni.$u.toast('压缩中')
var img = new Image();
img.src = imgSrc;
img.onload = function() {
var that = this;
var h = (img.height * scale).toFixed(0); // 默认按质量比例压缩
var w = (img.width * scale).toFixed(0);
var canvas = document.createElement('canvas');
var ctx = canvas.getContext('2d');
var width = document.createAttribute("width");
width.nodeValue = w;
var height = document.createAttribute("height");
height.nodeValue = h;
canvas.setAttributeNode(width);
canvas.setAttributeNode(height);
ctx.drawImage(that, 0, 0, w, h);
var base64 = canvas.toDataURL('image/jpeg', scale); //压缩比例
canvas = null;
if (type == 'base64') {
let data = {
size: getBase64Size(base64),
type: type,
source: base64
}
callback(base64);
} else {
let blob = base64ToBlob(base64);
// console.log('压缩后的大小', blob, blob.size, blob.type)
const blobUrl = window.URL.createObjectURL(blob); //blob地址
blob.source = blobUrl
callback(blob);
}
}
}
// base转Blob
function base64ToBlob(base64) {
var arr = base64.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
});
}
// 获取base64的文件大小
function getBase64Size(base64Str) {
let size = 0;
if (base64Str) { // 获取base64图片byte大小
const equalIndex = base64Str.indexOf('='); // 获取=号下标
if (equalIndex > 0) {
const str = base64Str.substring(0, equalIndex); // 去除=号
const strLength = str.length;
const fileLength = strLength - (strLength / 8) * 2; // 真实的图片byte大小
size = Math.floor(fileLength); // 向下取整
} else {
const strLength = base64Str.length;
const fileLength = strLength - (strLength / 8) * 2;
size = Math.floor(fileLength); // 向下取整
}
} else {
size = null;
}
return size
}
因为目前使用的H5,只写了uniapp+Uview插件进行压缩上传
如果使用vue只需要复制以上代码就可以,H5代码进行参考使用
1.需要先把上方代码进行封装,在utils创建js文件,我的命名为(common.js),将上方代码复制到js文件内,然后把封装的方法给抛出暴漏出来进行调用
如果有其他方式也可以抛出也可以,或者直接写在vue文件内,因为项目中使用比较多,所以进行了封装
export default {
compressImg
}
2.使用Uview上传组件
<u-upload :fileList="fileList1" :capture="['camera']" :maxCount="3" :auto-upload="true"
@afterRead="afterRead" @delete="deletePic" name="1" multiple
:previewFullImage="true"></u-upload>
3.在vue文件中进行调用
import minix from "@/util/common.js";
4.在data中定义压缩大小限制
data(){
return{
fileMaxSize: 1 * 1024 * 1024, // 默认最大为1M
fileMinSize: 50 * 1024 // 最小为50KB
}
}
5.上传和压缩代码调用
// 删除图片
deletePic(event) {
this[`fileList${event.name}`].splice(event.index, 1)
this.btnfilelist()
},
// 新增图片
async afterRead(event) {
// 当设置 multiple 为 true 时, file 为数组格式,否则为对象格式
let lists = [].concat(event.file)
let fileListLen = this[`fileList${event.name}`].length
for (let index in lists) {
const item = lists[index]
const fileSize = item.size
const fileName = item.name ?? ''
if (fileSize > this.fileMaxSize) {
const compressionRatio = this.getCompressionRatio(fileSize)
if (compressionRatio > 1) {
uni.$u.toast('文件' + fileName + '大于10M')
return false
}
// 自动压缩图片'
await this.compressImg(item, compressionRatio)
if (item.size > this.fileMaxSize) {
uni.$u.toast('文件' + fileName + '压缩后超出1M')
return false
}
}
if (item.size < this.fileMinSize) {
uni.$u.toast('文件' + fileName + '不能小于50KB')
return false
}
this[`fileList${event.name}`].push({
...item,
status: 'uploading',
message: '上传中'
})
}
for (let i = 0; i < lists.length; i++) {
const result = await this.uploadFilePromise(lists[i].url)
// 垃圾回收
window.URL.revokeObjectURL(lists[i].url)
let item = this[`fileList${event.name}`][fileListLen]
if (result.code === 200) {
this[`fileList${event.name}`].splice(fileListLen, 1, Object.assign(item, {
status: "success",
message: "成功",
type: this.index,
url: this.imgUrl + result.fileName,
urlText: result.fileName
}))
fileListLen++
} else {
this[`fileList${event.name}`].splice(fileListLen, 1)
uni.$u.toast('上传失败')
}
this.btnfilelist()
}
},
uploadFilePromise(url) {
//formData如需要传其他参数在此处填写
return new Promise((resolve, reject) => {
let a = uni.uploadFile({
url: this.imgUrl + '/common/upload', // 仅为示例,非真实的接口地址
filePath: url,
name: 'file',
formData: {
},
header: {
Authorization: uni.getStorageSync('tokens')
},
success: (res) => {
setTimeout(() => {
resolve(JSON.parse(res.data))
}, 1000)
},
fail(err) {}
});
})
},
getCompressionRatio(fileSize) {
const multiple = (fileSize / this.fileMaxSize).toFixed(2) // 获取文件大小倍数,生成质量比
let compressionRatio = 1
if (multiple > 5) {
compressionRatio = 0.5
} else if (multiple > 4) {
compressionRatio = 0.6
} else if (multiple > 3) {
compressionRatio = 0.7
} else if (multiple > 2) {
compressionRatio = 0.8
} else if (multiple > 1) {
compressionRatio = 0.9
} else {
compressionRatio = 2
}
return compressionRatio;
},
compressImg(source, compressionRatio) {
return new Promise((resolve, reject) => {
minix.compressImg(source.url, compressionRatio, source.type, compressRes => {
resolve(compressRes);
})
}).then((res) => {
source.size = res.size
// window.URL.revokeObjectURL(source.url) // 删除被压缩的缓存文件,这里注意,如果是相册选择上传,可能会删除相册的图片
source.url = res.source
source.thumb = res.source
return source
}).catch(err => {
console.log('图片压缩失败', err)
})
},
btnfilelist() {
console.log(this.fileList1);
},