前段时间公司要弄一个uniapp的H5拍照上传的功能,看这位博主 常德_威少 的博客完成,于是想把我写的和补充记录一下
首先调用uni.chooseImage(具体看官网),因为手机拍照像素尺寸很大,官方图片压缩不支持H5,于是参考了 常德_威少 的博客。
话不多说,基本思路是:
1、先将图片的file文件转成baseURL
2、创建一个image标签去接收文件获取图片的宽高和比例。
3、创建canvas画布设置画布的大小。
4、将图片绘制到canvas上面。
5、对canvas进行压缩处理,获得新的baseURL
6、将图片的baseURL转化回file格式。
最后我们调用这个方法可以拿到图片的file格式
根据接口所需要的格式再继续转换,我最后转换为blob
我们在utils写一个方法 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//获取文件
// console.log(111);
if(!rawImage) return false
// console.log(222);
if(!this.isImage(rawImage)){
// console.log(333);
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 '../../common/utils/Compress';
通过调用方法得到图片的file格式
// 文件(res.tempFiles[0]是uniapp中chooseImage方法得到的) 宽度 质量 图片尺寸(1是1024 * 1024)
let imgfile = new Compress(res.tempFiles[0], 600, 0.8, 1);
let res2 = await imgfile.compressUpload(); // 记得配合 async 使用
console.log('res2', res2.file); // 得到图片的file格式
根据接口的需要,我将file转换为blob格式,如下
// res2.file就是上面我们得到的file图片 res.tempFiles[0].type是uniapp中chooseImage方法的图片类型
let blob = new Blob([res2.file], {type: res.tempFiles[0].type})
let reader = new FileReader()
reader.readAsDataURL(blob)
reader.onload = (e)=> {
// console.log('e', e);
// 其中e.currentTarget.result就是我们需要的图片格式blob
// 调用uniapp中的图片文件上传方法
uni.uploadFile({
url: , // 接口地址
fileType: 'image', // 图片类型
filePath: e.currentTarget.result, // blob图片格式
name: 'file',
formData: {
TOKEN: '',
},
success(res1) {
},
});
}
}
希望能帮到你们,求个点赞
完整代码如下:
// 调用手机相机(使用了uniapp) pictureClick() { let that = this; uni.chooseImage({ count: 1, sourceType: ['camera'], // camera拍照,album相册 success: async res => { this.tempFilePaths = res.tempFilePaths; this.Imgs = res.tempFilePaths[0]; let imgfile = new Compress(res.tempFiles[0], 600, 0.8, 1); let res2 = await imgfile.compressUpload(); let blob = new Blob([res2.file], {type: res.tempFiles[0].type}) let reader = new FileReader() reader.readAsDataURL(blob) reader.onload = (e)=> { uni.uploadFile({ url: '', // 接口地址 fileType: 'image', filePath: e.currentTarget.result, name: 'file', formData: { type: 10, TOKEN: '', }, success(res1) { // 后端人脸识别接口 } else if (res.status === 1) { uni.showToast({ title: res.msg, icon: 'none', duration: 2000, }); } else { alert(res.msg); } }); }, }); } }, }); },