上传图片前要进行压缩,因为图片过大,服务器会崩。
在uniapp中有uni.compressImage()压缩图片方法
但是用了这个方法报错:compressImage
is not yet implemented
原因很简单,不支持h5,心态炸裂,只好换种方法了,试好好会把好用的方法发布出来的。
通过canvas可以压缩,和参考的不同的是只需要beforeImageUpload就行了。
代码如下:
<el-upload list-type="picture-card" :action="action" :show-file-list="false"
:on-success="handleSucess" :before-upload="beforeImageUpload">
<img v-if="imageUrl" :src="imageUrl" class="avatar" width="148" height="148"/>
<i v-else class="el-icon-plus avatar-uploader-icon" />
</el-upload>
js代码如下:
beforeImageUpload (file, fileList) {
return new Promise(async (resolve, reject) => {
if (!file.type.includes('image')) {
this.$message.warning('请上传图片')
reject(new Error('请上传图片'))
return
}
this.isShowSpinning = true//上传之前弹框-或者成功函数中打开裁剪图片弹框
const newFile = await this.compressImg(file)
console.log(newFile.size,newFile,'压缩后图片大小---------------')
resolve(newFile)
})
},
// 图片压缩函数
compressImg (file) {
const that = this
var files
var fileSize = parseFloat(parseInt(file['size']) / 1024 / 1024).toFixed(2)
var read = new FileReader()
read.readAsDataURL(file)
return new Promise(function (resolve, reject) {
read.onload = function (e) {
var img = new Image()
img.src = e.target.result
img.onload = function () {
// 默认按比例压缩
var w = this.width
var h = this.height
// 生成canvas
var canvas = document.createElement('canvas')
var ctx = canvas.getContext('2d')
var base64
// 创建属性节点
canvas.setAttribute('width', w)
canvas.setAttribute('height', h)
ctx.drawImage(this, 0, 0, w, h)
if (fileSize < 1) {
// 如果图片小于一兆 那么压缩0.5
base64 = canvas.toDataURL(file['type'], 0.5)
} else if (fileSize > 1 && fileSize < 2) {
// 如果图片大于1M并且小于2M 那么压缩0.5
base64 = canvas.toDataURL(file['type'], 0.5)
} else {
// 如果图片超过2m 那么压缩0.2
base64 = canvas.toDataURL(file['type'], 0.2)
}
// 回调函数返回file的值(将base64编码转成file)
files = that.dataURLtoFile(base64, file.name) // 如果后台接收类型为base64的话这一步可以省略
resolve(files)
}
}
})
},
// base64转码(压缩完成后的图片为base64编码,这个方法可以将base64编码转回file文件)
dataURLtoFile (dataurl, filename) {
var arr = dataurl.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)
}
return new File([u8arr], filename, { type: mime })
},
handleSucess(res, file) {//这里上传已是走完:beforeImageUpload函数压缩后的图片
console.log(file.size,file,'这里打印还是压缩之前的大小----');
this.$nextTick(() => {//取dom更新之后的值
this.option.img = URL.createObjectURL(file.raw);
// this.option.img = URL.createObjectURL(this.newFile);//取到的值已是压缩后的图片,不需要从beforeImageUpload重新赋值给一个字段
console.log(this.option.img,'打印出来的地址在浏览器下载看大小:是压缩之前的图片,但是上传成功后---后台返回url浏览器下载看大小-已经是压缩后的了,证明成功了-----------------')
})
},
方法2:手码压缩 和 compressorjs 压缩图片插件,
(自己参考:mobile2/pages/touristCard/myCard/faceApprove.vue)
npm install compressorjs --save
首先页面中引入:
import Compressor from 'compressorjs';
简单示例:
//场景uniapp写的h5。 图片压缩 res.tempFiles[0]是图片的Blod流
uni.chooseImage({
count: 1,
success: (chooseImageRes) => {
//const tempFilePaths = chooseImageRes.tempFilePaths;//不需要压缩接口直接取值
const tempFile = chooseImageRes.tempFiles[0];
if (tempFile.size > 1048576) { // 1MB = 1048576字节
new Compressor(tempFile, {
quality: 0.7, // 压缩质量
convertSize:false,
success: (result) => {
//url :接口传参为blob文件时:blob:http://192.168.3.141:8080/321c5ea6-7167-440e-9082-9a972660534a
const url = URL.createObjectURL(result);
//这里是Bold流转化为新的File
const fileA = new File([result], result.name, { type: result.type })
//这里取值,压缩后的处理
},
error: (error) => {
console.error('图片压缩失败', error);
},
});
} else {
console.log('图片大小合适,进行上传:', tempFilePaths[0]);
}
}
})
完整示例
//1.自己封装压缩图片方法
compressImage(file, maxWidthOrHeight, quality = 0.8) {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = function (e) {
const img = new Image();
img.src = e.target.result;
img.onload = function () {
let canvas = document.createElement('canvas');
let ctx = canvas.getContext('2d');
// 计算等比例缩放后的尺寸
let width = img.width;
let height = img.height;
if (width > height) {
if (width > maxWidthOrHeight) {
height *= maxWidthOrHeight / width;
width = maxWidthOrHeight;
}
} else {
if (height > maxWidthOrHeight) {
width *= maxWidthOrHeight / height;
height = maxWidthOrHeight;
}
}
// 设置canvas尺寸
canvas.width = width;
canvas.height = height;
// 绘制图片到canvas
ctx.drawImage(img, 0, 0, width, height);
// 将canvas内容转换为base64编码的图片
canvas.toBlob(function (blob) {
// 检查图片大小,如果仍然大于1M,则继续降低质量进行压缩
if (blob.size > 1048576) {
this.compressImage(file, maxWidthOrHeight, quality - 0.1).then(resolve).catch(reject);
} else {
// 创建一个新的File对象,用于后续上传
const newFile = new File([blob], file.name, {
type: file.type,
lastModified: Date.now()
});
// // 创建一个URL对象,用于显示或者调试
const url = URL.createObjectURL(blob);
resolve({ file: newFile, url: url });
}
},file.type, quality);
};
};
reader.onerror = function (error) {
reject(error);
};
});
},
//<view class="btn" @click="upLoadImg()">上传照片</view>
//上传照片点击事件
upLoadImg() {
uni.chooseImage({
count: 1,
success: (chooseImageRes) => {
const tempFilePaths = chooseImageRes.tempFilePaths;
const tempFile = chooseImageRes.tempFiles[0];
console.log(tempFile,'原图片----')
// 方法1
// let lastFile = '';
// if (tempFile.size > 1048576) {// 1MB = 1048576字节
// // 读取文件并进行压缩
// const compressFilePromise = this.compressImage(tempFile, 800); // 假设最大宽度或高度为800
// compressFilePromise.then((compressedFile) => {
// lastFile = compressedFile.url
// console.log('压缩后的图片:', lastFile,compressedFile);
// this.uploadFile(lastFile);
// }).catch((error) => {
// console.error('图片压缩失败:', error);
// });
// } else {//不压缩
// this.uploadFile(tempFilePaths[0]);
// }
// 方法2插件
let lastFile = '';
if (tempFile.size > 1048576) { // 1MB = 1048576字节
new Compressor(tempFile, {
quality: 0.6,
convertSize:false,
success: (result) => {
//这里是Bold流转化为新的File
const url = URL.createObjectURL(result);
lastFile = new File([result], result.name, { type: result.type })
console.log('压缩后的图片:',result,url);
this.uploadFile(url);
},
error: (error) => {
console.error('图片压缩失败', error);
},
});
} else {
this.uploadFile(tempFilePaths[0]);
}
}
})
},
//上传接口
uploadFile(val){
let _this = this;
let file = null;
let UploadUrl = ''
uni.uploadFile({
url: UploadUrl,
filePath: val,//传参blob
name: 'file',
formData: {
timestamp:new Date().getTime(),//当前时间
token:'',
},
success: (uploadFileRes) => {
uni.hideLoading();
let newData = uploadFileRes.data.replace(/[\\]/g, '')
let imgData = JSON.parse(newData)
//上传失败处理
if(imgData.errno!=0 || !imgData.data){
let decodedStr = this.decodeUnicode(imgData.message)
uni.showToast({
icon: 'none',
title:decodedStr
})
}else{//上传图片接口成功-走上传人脸接口
}
}
});
},