当前位置: 首页 > news >正文

vue/H5图片压缩/压缩后上传

图片压缩:通过canvas进行图片压缩

// 图片压缩
/**
 * imgSrc 地址
 * scale 压缩质量 0-1
 * type 文件类型
 */
const compressImg =function(imgSrc, scale, type, callback) {
	// uni.$u.toast('压缩中')
	var img = new Image();
	img.src = imgSrc;
	img.onload = function() {
		var that = this;
		var h = (img.height * scale).toFixed(0); // 默认按质量比例压缩
		var w = (img.width * scale).toFixed(0);
		var canvas = document.createElement('canvas');
		var ctx = canvas.getContext('2d');
		var width = document.createAttribute("width");
		width.nodeValue = w;
		var height = document.createAttribute("height");
		height.nodeValue = h;
		canvas.setAttributeNode(width);
		canvas.setAttributeNode(height);
		ctx.drawImage(that, 0, 0, w, h);
		var base64 = canvas.toDataURL('image/jpeg', scale); //压缩比例
		canvas = null;
		if (type == 'base64') {
			let data = {
				size: getBase64Size(base64),
				type: type,
				source: base64
			}
			callback(base64);
		} else {
			let blob = base64ToBlob(base64);
			// console.log('压缩后的大小', blob, blob.size, blob.type)
			const blobUrl = window.URL.createObjectURL(blob); //blob地址
			blob.source = blobUrl
			callback(blob);
		}
	}
}

// base转Blob
function base64ToBlob(base64) { 
	var arr = base64.split(','),
		mime = arr[0].match(/:(.*?);/)[1],
		bstr = atob(arr[1]),
		n = bstr.length,
		u8arr = new Uint8Array(n);
	while (n--) {
		u8arr[n] = bstr.charCodeAt(n);
	}
	return new Blob([u8arr], {
		type: mime
	});
}

// 获取base64的文件大小
function getBase64Size(base64Str) {
	let size = 0;
	if (base64Str) { // 获取base64图片byte大小
		const equalIndex = base64Str.indexOf('='); // 获取=号下标
		if (equalIndex > 0) {
			const str = base64Str.substring(0, equalIndex); // 去除=号
			const strLength = str.length;
			const fileLength = strLength - (strLength / 8) * 2; // 真实的图片byte大小
			size = Math.floor(fileLength); // 向下取整
		} else {
			const strLength = base64Str.length;
			const fileLength = strLength - (strLength / 8) * 2;
			size = Math.floor(fileLength); // 向下取整
		}
	} else {
		size = null;
	}
	return size
}

因为目前使用的H5,只写了uniapp+Uview插件进行压缩上传

如果使用vue只需要复制以上代码就可以,H5代码进行参考使用

1.需要先把上方代码进行封装,在utils创建js文件,我的命名为(common.js),将上方代码复制到js文件内,然后把封装的方法给抛出暴漏出来进行调用

如果有其他方式也可以抛出也可以,或者直接写在vue文件内,因为项目中使用比较多,所以进行了封装

export default {
	compressImg
}
2.使用Uview上传组件
<u-upload :fileList="fileList1" :capture="['camera']" :maxCount="3" :auto-upload="true"
						@afterRead="afterRead" @delete="deletePic" name="1" multiple
						:previewFullImage="true"></u-upload>
3.在vue文件中进行调用
import minix from "@/util/common.js";
4.在data中定义压缩大小限制
data(){
    return{
        fileMaxSize: 1 * 1024 * 1024, // 默认最大为1M
		fileMinSize: 50 * 1024 // 最小为50KB
    }
}
5.上传和压缩代码调用
// 删除图片
			deletePic(event) {
				this[`fileList${event.name}`].splice(event.index, 1)
				this.btnfilelist()
			},
			// 新增图片
			async afterRead(event) {
				// 当设置 multiple 为 true 时, file 为数组格式,否则为对象格式
				let lists = [].concat(event.file)
				let fileListLen = this[`fileList${event.name}`].length
				for (let index in lists) {
					const item = lists[index]
					const fileSize = item.size
					const fileName = item.name ?? ''
					if (fileSize > this.fileMaxSize) {
						const compressionRatio = this.getCompressionRatio(fileSize)
						if (compressionRatio > 1) {
							uni.$u.toast('文件' + fileName + '大于10M')
							return false
						}
						// 自动压缩图片'
						await this.compressImg(item, compressionRatio)
						if (item.size > this.fileMaxSize) {
							uni.$u.toast('文件' + fileName + '压缩后超出1M')
							return false
						}
					}
					if (item.size < this.fileMinSize) {
						uni.$u.toast('文件' + fileName + '不能小于50KB')
						return false
					}

					this[`fileList${event.name}`].push({
						...item,
						status: 'uploading',
						message: '上传中'
					})
				}

				for (let i = 0; i < lists.length; i++) {
					const result = await this.uploadFilePromise(lists[i].url)
					// 垃圾回收
					window.URL.revokeObjectURL(lists[i].url)
					let item = this[`fileList${event.name}`][fileListLen]
					if (result.code === 200) {
						this[`fileList${event.name}`].splice(fileListLen, 1, Object.assign(item, {
							status: "success",
							message: "成功",
							type: this.index,
							url: this.imgUrl + result.fileName,
							urlText: result.fileName
						}))
						fileListLen++
					} else {
						this[`fileList${event.name}`].splice(fileListLen, 1)
						uni.$u.toast('上传失败')
					}
					this.btnfilelist()
				}
			},
			uploadFilePromise(url) {
                //formData如需要传其他参数在此处填写
				return new Promise((resolve, reject) => {
					let a = uni.uploadFile({
						url: this.imgUrl + '/common/upload', // 仅为示例,非真实的接口地址
						filePath: url,
						name: 'file',
						formData: {
							
						},
						header: {
							Authorization: uni.getStorageSync('tokens')
						},
						success: (res) => {
							setTimeout(() => {
								resolve(JSON.parse(res.data))
							}, 1000)
						},
						fail(err) {}
					});
				})
			},
			getCompressionRatio(fileSize) {
				const multiple = (fileSize / this.fileMaxSize).toFixed(2) // 获取文件大小倍数,生成质量比
				let compressionRatio = 1
				if (multiple > 5) {
					compressionRatio = 0.5
				} else if (multiple > 4) {
					compressionRatio = 0.6
				} else if (multiple > 3) {
					compressionRatio = 0.7
				} else if (multiple > 2) {
					compressionRatio = 0.8
				} else if (multiple > 1) {
					compressionRatio = 0.9
				} else {
					compressionRatio = 2
				}
				return compressionRatio;
			},
			compressImg(source, compressionRatio) {
				return new Promise((resolve, reject) => {
					minix.compressImg(source.url, compressionRatio, source.type, compressRes => {
						resolve(compressRes);
					})
				}).then((res) => {
					source.size = res.size
					// window.URL.revokeObjectURL(source.url) // 删除被压缩的缓存文件,这里注意,如果是相册选择上传,可能会删除相册的图片
					source.url = res.source
					source.thumb = res.source
					return source
				}).catch(err => {
					console.log('图片压缩失败', err)
				})
			},
            btnfilelist() {
				console.log(this.fileList1);
			},

相关文章:

  • Java集合框架深度剖析:从数据结构到实战应用
  • 【计算机网络】网络简介
  • AI 生成 PPT 网站介绍与优缺点分析
  • 天地图InfoWindow插入React自定义组件
  • OpenHarmony子系统开发 - 电源管理(一)
  • 可视化图解算法:链表相加( 两数相加)
  • LabVIEW软件长时间运行导致蓝屏问题排查与优化
  • SpringCache小记
  • CentOS 7 设置 Nginx 开机自启(使用 Systemd)
  • 【Hbase】列族版本问题
  • sqli-labs学习记录6
  • 使用 Fetch API 实现流式读取
  • 单片机学习笔记——入门51单片机
  • 在windows下通过wsl工具管理Linux子系统
  • UDS诊断、ECU刷写、自动化测试、车联网测试、DTC故障注入测试、坏境测试、可靠性测试、压力测试、性能测试等
  • 计算机四级 - 数据库原理(操作系统部分)- 第5章「内存管理」
  • QT Quick(C++)跨平台应用程序项目实战教程 3 — 项目基本设置(窗体尺寸、中文标题、窗体图标、可执行程序图标)
  • C++:类和对象(含各编译器对编译过程的优化解释)详解[后篇]
  • Neo Gamma 机器人在 GTC 2025 上的突破性进展与表现分析
  • JVM运行时数据区内部结构难记?一个例子优化记忆
  • 教育部基础教育教指委:稳步推进中小学人工智能通识教育
  • 民企老板被错羁212天续:申请国赔千万余元,要求恢复名誉赔礼道歉
  • 全球医药股普跌,A股创新药板块下挫
  • 中美经贸高层会谈在日内瓦结束,中国代表团将举行发布会
  • “80后”李灿已任重庆市南川区领导,此前获公示拟提名为副区长人选
  • 1至4月全国铁路完成固定资产投资1947亿元,同比增长5.3%