uniapp 上传压缩图片 兼容h5和小程序的方法

时间:2024-03-02 21:31:10

项目是用uniapp开发的,当时只是做App端,后来项目扩展到H5端, uniapp框架可以跨平台所以移动端和H5使用的是一套代码
上传头像的时候要求图片的大小在2MB一下,所以要压缩图片,App端当时使用的是uni.compressImage(OBJECT)压缩的(详情见:https://uniapp.dcloud.net.cn/api/media/image.html#compressimage 但是H5不兼容;
先搞定H5的压缩吧!网上一搜一大把


/** 
 * H5压缩 二分查找算法来找到一个合适的图像质量系数,使得压缩后的图片文件大小接近于目标大小
 * @param {Object} imgSrc 图片url 
 * @param {Object} callback 回调设置返回值 
 * */
 export function compressH5(fileItem, targetSizeKB, initialQuality = 1.0) {
     const maxQuality = 1.0;
     const minQuality = 0.0;
     const tolerance = 0.01; // 根据需要调整公差
     return new Promise((resolve, reject) => {
         const binarySearch = (min, max) => {
             const midQuality = (min + max) / 2;
 
             const reader = new FileReader();
             reader.readAsDataURL(fileItem);
             reader.onload = function () {
                 const img = new Image();
                 img.src = this.result;
                 img.onload = function () {
                     const canvas = document.createElement('canvas');
                     const ctx = canvas.getContext('2d');
 
                     canvas.width = img.width;
                     canvas.height = img.height;
 
                     ctx.clearRect(0, 0, canvas.width, canvas.height);
                     ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
 
                     // 使用异步的 toBlob 方法
                     canvas.toBlob(async (blob) => {
                         const fileSizeKB = blob.size / 1024;
 
                         if (Math.abs(fileSizeKB - targetSizeKB) < tolerance || max - min < tolerance) {
                             // 当前质量足够接近目标大小,使用当前质量解析
                             resolve(URL.createObjectURL(blob));
                         } else if (fileSizeKB > targetSizeKB) {
                             // 如果文件大小太大,降低质量,继续二分查找
                             binarySearch(min, midQuality);
                         } else {
                             // 如果文件大小太小,增加质量,继续二分查找
                             binarySearch(midQuality, max);
                         }
                     }, 'image/jpeg', midQuality);
                 };
             };
             reader.onerror = function (error) {
                 reject(error);
             };
         };
 
         // 开始二分查找
         binarySearch(minQuality, maxQuality);
     });
 }


调用方法

			chooseImg1() {
			    uni.chooseImage({
					count: 1, //默认9
					sizeType:['compressed'],
			        success: (chooseImageRes) => {
			            const tempFilePaths = chooseImageRes.tempFilePaths;
			            const filePath = tempFilePaths[0];
			            // 获取图片文件大小
			            uni.getFileInfo({
			                filePath: filePath,
			                success: (fileInfo) => {
			                    const fileSize = fileInfo.size; // 图片文件大小,单位为B
			                    // 判断图片大小是否超过200KB
			                    if (fileSize > 200 * 1024) {
									//#ifdef H5
									 //h5压缩图片
																		 const targetSizeKB = 150; // 设置目标文件大小,单位为KB,根据需求调整
compressH5(chooseImageRes.tempFiles[0],targetSizeKB).then(file => {
											console.log('file 222 = ', file)
											this.uploadCompressedImage(file);
											}).catch(err => {
												console.log('catch', err)
									 })
									//#endif
									//#ifdef APP-PLUS || MP-WEIXIN
			                        // 如果超过200KB,进行压缩
			                        uni.compressImage({
			                            src: filePath,
			                            quality: 10, // 设置压缩质量(0-100)- 根据需求进行调整
			                            success: (compressRes) => {
			                                // 压缩成功后的逻辑
			                                this.uploadCompressedImage(compressRes.tempFilePath);
			                            },
			                            fail: (err) => {
			                                console.error('压缩图片失败:', err);
			                                uni.showToast({
			                                    title: '压缩图片失败,请重试',
			                                    icon: 'none'
			                                });
			                            }
			                        });
									//#endif
			                    } else {
			                        // 如果未超过200KB,直接上传原图
			                        this.uploadCompressedImage(filePath);
			                    }
			                },
			                fail: (err) => {
			                    console.error('获取文件信息失败:', err);
			                    uni.showToast({
			                        title: '获取文件信息失败,请重试',
			                        icon: 'none'
			                    });
			                }
			            });
			        },
			        fail: (err) => {
			            console.error('选择图片失败:', err);
			            uni.showToast({
			                title: '选择图片失败,请重试',
			                icon: 'none'
			            });
			        }
			    });
			},
	uploadCompressedImage(filePath) {
			        uni.uploadFile({
			            url: `${this.$VUE_APP_API_URL}/common/image/image/upload/faceImg`,
						filePath: filePath,
			            name: 'file',
			            header: {
			                'Authorization': uni.getStorageSync('X-Token'), // 修改为你的访问令牌
			            },
						success: (res) => {
							uni.hideLoading(); // 隐藏 loading
							if (res.statusCode === 200) {
								console.log('上传成功:', res.data);
								const responseData = JSON.parse(res.data); // 解析返回的数据
								console.log(responseData,'responseData')
								// 处理上传成功后的逻辑
								if(responseData.code==200){
									this.contractImage1 = responseData.data
									uni.setStorageSync('faceUrl',this.contractImage1)
								}else{
									uni.$u.toast(responseData.msg);
								}
							} else {
								console.error('上传失败', res.statusCode);
								uni.showToast({
									title: res.msg, // 自定义错误信息
									icon: 'none'
								});
							}
						},
			            fail: (err) => {
			                console.error('上传失败:', err);
			                uni.showToast({
			                    title: '上传失败,请重试',
			                    icon: 'none'
			                });
			            }
			        });
			    },

即能兼容h5也能兼容微信小程序和各个app

微信小程序图片压缩再次用二分查找压缩质量





// 压缩图片
export function compressImage(filePath, quality, successCallback, errorCallback) {
    uni.compressImage({
        src: filePath,
        quality: quality,
        success: (res) => {
            successCallback(res.tempFilePath);
        },
        fail: (err) => {
            errorCallback(err);
        }
    });
}

// 二分查找压缩质量
export function binarySearchCompress(filePath, targetSize, low, high, successCallback, errorCallback) {
    if (low > high) {
        errorCallback("无法达到目标大小");
        return;
    }

    const mid = Math.floor((low + high) / 2);

    compressImage(filePath, mid, (tempFilePath) => {
        uni.getFileInfo({
            filePath: tempFilePath,
            success: (res) => {
                const currentSize = res.size;

                if (currentSize <= targetSize) {
                    successCallback(tempFilePath);
                } else {
                    // 递归调整压缩质量
                    binarySearchCompress(filePath, targetSize, low, mid - 1, successCallback, errorCallback);
                }
            },
            fail: (err) => {
                errorCallback(err);
            }
        });
    }, (err) => {
        errorCallback(err);
    });
}

vue文件引用

//#ifdef APP-PLUS || MP-WEIXIN
			                        // 如果超过200KB,进行压缩
												
									  const tempFilePath = chooseImageRes.tempFilePaths[0];
									  const targetSizeKB = 200;
									  // 将目标大小转换为字节数
									  const targetSize = targetSizeKB * 1024;
									  // 初始压缩质量范围
									  const lowQuality = 1;
									  const highQuality = 100;
									  binarySearchCompress(tempFilePath, targetSize, lowQuality, highQuality, (compressedFilePath) => {
									      console.log("压缩成功,压缩后图片路径:", compressedFilePath);
										     this.uploadCompressedImage(compressedFilePath);
										  
									  }, (err) => {
									      console.error("压缩失败:", err);
									  })

									//#endif