uniapp实现小程序打开相册或拍照上传图片附赠兼容H5方法

文章目录

  • 前言
  • 一、支持相册选择和拍照
  • 二、删除图片
  • 三、效果图
  • 存在问题

    前言

    小程序上传图片,或者拍照上传图片,并附带兼容H5上传图片方法,压缩图片。


    一、支持相册选择和拍照

    支持选择相册和拍照,可以使用uniapp提供的api,当然也可以自己去封装自己想要的样式,我这里直接是使用了uni的方法。uni.chooseImage配置sourceType: ['album', 'camera']

    openSelectImage() {let tempList = []
    	uni.chooseImage({sizeType: ['compressed'],
    		sourceType: ['album', 'camera'],
    		success: (res) => {if (res.tempFilePaths?.length > 0) {tempList = res.tempFilePaths
    				// #ifdef MP
    				this.recursionCompressMP(tempList, (e) => {console.log('压缩后结果-----', e)
    				})
    				// #endif
    				// #ifdef H5
    				this.recursionCompressH5(tempList, (e) => {console.log('压缩后结果-----', e)
    				})
    				// #endif
    			}
    		},
    		fail: (err) => {console.log("err: ------", err);
    		}
    	})
    }
    
    // 微信
    async recursionCompressMP(urlList, callback) {let imgCompressList = []
    	let imageSize = 0
    	for (let itemUrl of urlList) {const result = await this.jumpImageCompress(itemUrl)
    		if (result?.size < 150000) {this.tempImageList.push(itemUrl)
    			continue
    		}
    		await this.getUserImageCompress(itemUrl, callback, result?.size)
    	}
    },
    

    压缩图片主要用canvas提供的api

    1、uni.createCanvasContext 创建 canvas 绘图上下文。

    2、CanvasContext.drawImage 绘制图像到画布。

    3、CanvasContext.draw将之前在绘图上下文中的描述(路径、变形、样式)画到 canvas 中。

    4、当canvas绘制完成后,将canvas导出成为图片,把当前画布指定区域的内容导出生成指定大小的图片,并返回文件路径。uni.canvasToTempFilePath

    //微信压缩图片
    getUserImageCompress(itemUrl, callback, size){let that = this;
    	return new Promise ((resolve, reject)=>{uni.getImageInfo({src: itemUrl,
    			success: (res) => {//获取设备像素比,不获取最后图片展示有问题
    				uni.getSystemInfo({success: function(info) {let ratio = 2;
    						let canvasWidth = res.width //图片原始长宽
    						let canvasHeight = res.height
    						let compressWidth = res.width
    						let quality = 0.1
    						compressWidth = res.width - 120
    						canvasHeight = res.height - 120
    						while (canvasWidth > compressWidth || canvasHeight > canvasHeight) { // 保证宽高在400以内
    							canvasWidth = Math.trunc(res.width / ratio)
    							canvasHeight = Math.trunc(res.height / ratio)
    							ratio++;
    						}
    						that.canvasWidth = canvasWidth
    						that.canvasHeight = canvasHeight
    						let ctx = uni.createCanvasContext('mycanvas')
    						ctx.drawImage(res.path, 0, 0, canvasWidth, canvasHeight)
    						ctx.draw(false, setTimeout(() => {uni.canvasToTempFilePath({canvasId: 'mycanvas',
    								destWidth: canvasWidth,
    								destHeight: canvasHeight,
    								fileType: 'jpg',
    								quality: quality,
    								success: function(res1) {callback && callback(res1.tempFilePath) //拿到图片压缩后的临时路径
    									uni.getFileInfo({filePath: res1.tempFilePath,
    										success: (ress) => {console.log('压缩之后----',ress) //返回图片尺寸
    											callback && callback(res1.tempFilePath)
    											console.log('添加数据----', that.tempImageList)
    											
    											resolve(res1.tempFilePath)
    											that.tempImageList.push(res1.tempFilePath)
    										}
    									})
    								},
    								fail: function(res) {console.log('canvas错误---',res.errMsg)
    								}
    							})
    						}, 100)) //留一定的时间绘制canvas
    					}
    				})
    			},
    			fail: (e) => {console.log('错误----', e)
    			}
    		})
    	})
    },
    

    利用返回的图片大小去控制压缩的比例,重复执行压缩函数。

    //返回图片大小
    jumpImageCompress (itemUrl) {return new Promise((resolve, reject)=>{uni.getFileInfo({filePath: itemUrl,
    			success: (res) => {console.log('压缩之前图片大小----',res) //返回图片尺寸
    				resolve(res)
    			},
    			fail: (err) =>{reject(err)
    			}
    		})
    	})
    },
    
    //h5
    recursionCompressH5(url, callback) {if (typeof url === 'string') {this.getUserImageCompressH5(url,callback)
    	} else if (typeof url === 'object') {for (let itemImg of url) {this.getUserImageCompressH5(itemImg,callback)
    		}
    	}
    },
    

    Tips:因为H5端 Canvas 内绘制的图像需要支持跨域访问才能成功。所以h5端uni.canvasToTempFilePath会返回为空,所以需要使用toBlob转为文件,再利用createObjectURL转为url,这样就可以获取到图片信息。控制压缩比例。

    // h5压缩图片
    getUserImageCompressH5 (imgUrl,callback) {let that = this;
    	return new Promise((resolve, reject)=>{uni.getImageInfo({src: imgUrl,
    			success(res) {let canvasWidth = res.width; //图片原始长宽
    				let canvasHeight = res.height;
    				let img = new Image();
    				img.src = res.path;
    				console.log(5435435353)
    				let canvas = document.createElement("canvas");
    				let ctx = canvas.getContext("2d");
    				canvas.width = canvasWidth / 2;
    				canvas.height = canvasHeight / 2;
    				ctx.drawImage(img, 0, 0, canvasWidth / 2, canvasHeight / 2);
    				canvas.toBlob(function(fileSrc) {let imgSrc = window.URL.createObjectURL(fileSrc);
    					uni.getFileInfo({filePath: imgSrc,
    						success: (resFileInfo) => {if (resFileInfo.size > 150000) {//压缩后大于1M就继续压缩
    								that.recursionCompressH5(imgSrc, callback);
    								return;
    							} else {callback && callback(imgSrc)
    								resolve(imgSrc)
    								that.tempImageList.push(imgSrc)
    							}
    						},
    					});
    				});
    			}
    		});
    	})
    },
    

    二、删除图片

    删除功能很简单,直接使用数组方的删除方法splice就可以了。

    deleteSelectImg(index) {this.tempImageList.splice(index, 1)
    },
    

    三、效果图

    至于页面ui结构,这里就不粘贴了,可以根据自己实际需求去实现。


    存在问题

    在控制压缩比例的地方,还有一些缺陷,并没有很完美的解决压缩指定大小图片问题。

    如有问题欢迎指出…