uniapp 上传压缩图片

3,406 阅读2分钟

uniapp 上传压缩图片

项目是用uniapp开发的,当时只是做App端,后来项目扩展到H5端, uniapp框架可以跨平台所以移动端和H5使用的是一套代码

上传头像的时候要求图片的大小在2MB一下,所以要压缩图片,App端当时使用的是uni.compressImage(OBJECT)压缩的(详情见: uniapp.dcloud.io/api/media/i… 但是H5不兼容;

先搞定H5的压缩吧!网上一搜一大把

/** 
 * H5压缩 
 * @param {Object} imgSrc 图片url 
 * @param {Object} callback 回调设置返回值 
 * */
export function compressH5(fileItem) {
	return new Promise((resolve, reject) => {
		let file_size = fileItem.size
		let file_path = fileItem.path
		let file_name = fileItem.name
		let max_size = 1020 * 1020 * 1 // 2MB的图片
		if (max_size > file_size) { // 判断是否需要压缩, 没有超过限制
			resolve(fileItem)
		} else {
			let img = new Image();
			img.src = file_path;
			img.onload = function() {
				var quality = max_size / file_size
				console.log('quality=', quality)
				var that = this;
				var h = that.height * (quality / 1); // 默认按比例压缩		
				var w = that.width * (quality / 1);
				var canvas = document.createElement('canvas');
				var ctx = canvas.getContext('2d');
				var anw = document.createAttribute("width");
				anw.nodeValue = w;
				var anh = document.createAttribute("height");
				anh.nodeValue = h;
				canvas.setAttributeNode(anw);
				canvas.setAttributeNode(anh);
				ctx.drawImage(that, 0, 0, w, h); //压缩比例		
				// base64
				var base64 = canvas.toDataURL('image/jpeg', quality);
				canvas = null;
				// file对象
				var file = base64ToFile(base64, "file_" + Date.parse(new Date()) + ".jpg");
				resolve(file)
			}
		}
	})
}
/**
 * base转File对象 
 * @param {Object} base64 base64地址 
 * */
export function base64ToFile(base64, filename) {
	let arr = base64.split(',');
	console.log(arr)
	let mime = arr[0].match(/:(.*?);/)[1];
	let bstr = atob(arr[1]);
	let n = bstr.length;
	let u8arr = new Uint8Array(n);
	while (n--) {
		u8arr[n] = bstr.charCodeAt(n);
	}
	return new File([u8arr], filename, {
		type: mime
	});
}

通过压缩获取到File的对象,如果直接使用之前上传图片的uni.uploadFile(OBJECT)(详情见:uniapp.dcloud.io/api/request… 会上传不成功,具体的问题不太清楚好像是file的path的问题,后端的同事不想动他的代码,只能自己动手了,直接写原生的ajax上传

function fileUpload(i) {
			console.log('fileUpload ---->', requestInfo)
			let item = requestInfo.files[i];
			let fileData = {
				fileIndex: i,
				files: requestInfo.files,
				...item
			};
			var formdata = new FormData();
			formdata.append("file", item);
			var xhr = new XMLHttpRequest();
			xhr.upload.addEventListener("progress", function(e) {
				var percentComplete = Math.round(e.loaded * 100 / e.total);
				requestInfo.onProgressUpdate && requestInfo.onProgressUpdate(Object.assign({},
					fileData, percentComplete.toString() + '%'));
			});
			xhr.addEventListener("load", function(e) {
				requestInfo.uploadComplete && requestInfo.uploadComplete(Object.assign({}, fileData,
					xhr.responseText));
			});
			xhr.addEventListener("error", function(e) {
				requestInfo.uploadError && requestInfo.uploadError(Object.assign({}, fileData, e));
			});
			xhr.onreadystatechange = function() {				
				if (xhr.readyState === 4 && xhr.status === 200) {					
					requestInfo.onEachUpdate && requestInfo.onEachUpdate({
						data: xhr.responseText,
						...fileData
					});
					fileList.push(xhr.responseText);
					if (len <= i) {
						resolve(fileList);					
					} else {
						fileUpload(i + 1);
					}
				} else if (xhr.readyState === 4) {
					reject('err');
				}
			}
			xhr.open("post", requestInfo.url, true);
			xhr.setRequestHeader('platform', requestInfo.header.platform);
			xhr.setRequestHeader('Access-Token', requestInfo.header['Access-Token']);
			xhr.send(formdata);
		}

问题解决

当拿到回调图片是,区分平台,App端的走app处理,H5端的走h5的处理方式

// 选择图片
onAvatarChange() {
	const app = this
	// 选择图片
	uni.chooseImage({
		count: 1,
		sizeType: ['compressed'],//可以指定是原图还是压缩图,默认二者都有['original','compressed'], 
		sourceType: ['album', 'camera'], //可以指定来源是相册还是相机['album', 'camera'],默认二者都有
		success({
			tempFiles // bol tempFiles tempFilePaths
		}) {
			app.imageList = []
			// #ifdef APP-PLUS		
			compressImg(tempFiles[0]).then(file => {
				app.imageList.push(file)
				app.uploadFile() // 上传图片
			}).catch(err => {
				console.log('catch', err)
			})
			// #endif
			// #ifdef H5
			compressH5(tempFiles[0]).then(file => {
				console.log('file 222 = ', file)
				app.imageList.push(file)
				app.uploadFileH5() // 上传图片
			}).catch(err => {
				console.log('catch', err)
			})
			// #endif
			}
	});
}

其他的问题

批量上传可以递归,或者队列。
最好不要for循环同时处理,很多是异步处理,for循环等于是一起发送处理操作,对本机或者服务器产生压力。
多使用Promise控制。

其他思路

可以将压缩后的base64数据通过uni.uploadFile(OBJECT)的附加参数上传给服务端,可能需要服务端的同事配合了