uniapp --- 实现图片压缩(兼容H5)

发布于:2024-04-20 ⋅ 阅读:(15) ⋅ 点赞:(0)

目录

创建组件

在 template 中添加组件

方法说明:

compress() 方法参数:

progress 方法回调对象属性详细说明:

源码示例: 

 thank


Canvas 是 HTML5 提供的一个用于在网页上绘制图形的元素,它可以实现图片压缩的功能。而结和UnoApp是一种基于Canvas的图形编辑工具库,它提供了丰富的API和功能,可以帮助开发者在网页上实现各种图形编辑和处理操作。

实现图片压缩的原理在结和UnoApp中也是类似的,主要是通过Canvas的绘图功能来重新绘制图片并调整尺寸和质量。下面将详细介绍结和UnoApp实现图片压缩的步骤:

创建组件
<template>
	<view class="compress" v-if="canvasId">
		<canvas :canvas-id="canvasId" :style="{ width: canvasSize.width, height: canvasSize.height }"></canvas>
	</view>
</template>

<script>
export default {
	data() {
		return {
			pic: '',
			canvasSize: {
				width: 0,
				height: 0
			},
			canvasId: ''
		};
	},
	mounted() {
		// 创建 canvasId
		if (!uni || !uni._helang_compress_canvas) {
			uni._helang_compress_canvas = 1;
		} else {
			uni._helang_compress_canvas++;
		}
		this.canvasId = `compress-canvas${uni._helang_compress_canvas}`;
	},
	methods: {
		// 压缩
		compressFun(params) {
			return new Promise(async (resolve, reject) => {
				// 等待图片信息
				let info = await this.getImageInfo(params.src)
					.then((info) => info)
					.catch(() => null);

				if (!info) {
					reject('获取图片信息异常');
					return;
				}

				// 设置最大 & 最小 尺寸
				const maxSize = params.maxSize || 1080;
				const minSize = params.minSize || 640;

				// 当前图片尺寸
				let { width, height } = info;

				// 非 H5 平台进行最小尺寸校验
				// #ifndef H5
				if (width <= minSize && height <= minSize) {
					resolve(params.src);
					return;
				}
				// #endif

				// 最大尺寸计算
				//(图像的宽度和高度是否超过最大尺寸。如果其中任一维度超过最大尺寸,代码将对图像进行调整,以使其适应最大尺寸并保持其宽高比。)
				// 这样可以确保图像在调整大小后仍保持原始比例,并且不会超过指定的最大尺寸

				if (width > maxSize || height > maxSize) {
					if (width > height) {
						height = Math.floor(height / (width / maxSize));
						width = maxSize;
					} else {
						width = Math.floor(width / (height / maxSize));
						height = maxSize;
					}
				}

				// 设置画布尺寸
				this.$set(this, 'canvasSize', {
					width: `${width}px`,
					height: `${height}px`
				});

				// Vue.nextTick 回调在 App 有异常,则使用 setTimeout 等待DOM更新
				setTimeout(() => {
					// 创建 canvas 绘图上下文(指定 canvasId)。在自定义组件下,第二个参数传入组件实例this,以操作组件内 <canvas/> 组件
					// Tip: 需要指定 canvasId,该绘图上下文只作用于对应的 <canvas/>
					const ctx = uni.createCanvasContext(this.canvasId, this);
					// 清除画布上在该矩形区域内的内容。(x,y,宽,高)
					ctx.clearRect(0, 0, width, height);
					// 绘制图像到画布。(所要绘制的图片资源,x,y,宽,高)
					ctx.drawImage(info.path, 0, 0, width, height);
					// 将之前在绘图上下文中的描述(路径、变形、样式)画到 canvas 中。
					// 本次绘制是否接着上一次绘制,即reserve参数为false,则在本次调用drawCanvas绘制之前native层应先清空画布再继续绘制;若reserver参数为true,则保留当前画布上的内容,本次调用drawCanvas绘制的内容覆盖在上面,默认 false
					// 绘制完成后回调
					ctx.draw(false, () => {
						// 把当前画布指定区域的内容导出生成指定大小的图片,并返回文件路径。在自定义组件下,第二个参数传入自定义组件实例,以操作组件内 <canvas> 组件。
						uni.canvasToTempFilePath(
							{
								x: 0, //画布x轴起点(默认0)
								y: 0, //画布y轴起点(默认0)
								width: width, //画布宽度(默认为canvas宽度-x)
								height: height, //画布高度(默认为canvas高度-y
								destWidth: width, //图片宽度(默认为 width * 屏幕像素密度)
								destHeight: height, //输出图片高度(默认为 height * 屏幕像素密度)
								canvasId: this.canvasId, //画布标识,传入 <canvas/> 的 canvas-id(支付宝小程序是id、其他平台是canvas-id)
								fileType: params.fileType || 'png', //目标文件的类型,只支持 'jpg' 或 'png'。默认为 'png'
								quality: params.quality || 0.9, //图片的质量,取值范围为 (0, 1],不在范围内时当作1.0处理
								success: (res) => {
									// 在H5平台下,tempFilePath 为 base64
									resolve(res.tempFilePath);
								},
								fail: (err) => {
									reject(null);
								}
							},
							this
						);
					});
				}, 300);
			});
		},
		// 获取图片信息
		getImageInfo(src) {
			return new Promise((resolve, reject) => {
				uni.getImageInfo({
					src,
					success: (info) => {
						resolve(info);
					},
					fail: (err) => {
						console.log(err, 'err===获取图片信息');
						reject(null);
					}
				});
			});
		},
		// 批量压缩
		async compress(params) {
			// 初始化状态变量
			let [index, done, fail] = [0, 0, 0];
			let paths = [];

			// 处理待压缩图片列表
			let waitList = Array.isArray(params.src) ? params.src : [params.src];

			// 批量压缩方法
			let batch = async () => {
				while (index < waitList.length) {
					try {
						const path = await next();
						done++;
						paths.push(path);
						params.progress?.({ done, fail, count: waitList.length });
					} catch (error) {
						fail++;
						params.progress?.({ done, fail, count: waitList.length });
					}
					index++;
				}
			};

			// 单个图片压缩方法
			let next = () => {
				const currentSrc = waitList[index];
				return this.compressFun({
					src: currentSrc,
					maxSize: params.maxSize,
					fileType: params.fileType,
					quality: params.quality,
					minSize: params.minSize
				});
			};
			// 返回Promise并处理结果
			return new Promise((resolve, reject) => {
				try {
					batch()
						.then(() => {
							if (typeof params.src === 'string') {
								resolve(paths[0]);
							} else {
								resolve(paths);
							}
						})
						.catch((error) => {
							reject(error);
						});
				} catch (error) {
					reject(error);
				}
			});
		}
	}
};
</script>

<style lang="scss" scoped>
.compress {
	position: fixed;
	width: 12px;
	height: 12px;
	overflow: hidden;
	top: -99999px;
	left: 0;
}
</style>

在 script 中引用组件

import helangCompress from '../../components/helang-compress/helang-compress';

export default {
    components: {
        helangCompress
    }
}
在 template 中添加组件
<helang-compress ref="helangCompress"></helang-compress>
方法说明:
方法名 可传参数 必填 说明
compress() Object 【单张压缩】设置压缩的图片及压缩尺寸和压缩质量,参数详情请阅读下方 compress()方法参数
compress() 方法参数:
参数名 类型 必填 默认值 说明
src String / Array - 待压缩的图片地址,由相册选择或拍照获取。注意:若src的值为String压缩成功后则返回String,若为Array,压缩成功后则返回Array
maxSize Number 1080 压缩后的最大尺寸
fileType String 'png' 压缩后的文件类型,可选值 jpg、png
quality Number 0.9 压缩后的质量(仅jpg类型有效,原因可自行阅读官方canvas文档),可选值 0 ~ 1,值越大越清晰(图片也越大)
minSize Number 640 最小压缩尺寸,图片尺寸小于该时值不压缩,非H5平台有效。若想忽略该设置可以将该值设置为一个极小的值,比如一个负数(不能是0)

为使插件在 H5 平台统一返回 base64 数据,则故意取消 H5 平台对 minSize 的设置。H5平台压缩后的图片路径是 base64 格式,有跨平台需求须注意

progress 方法回调对象属性详细说明:
参数名 类型 说明
done Number 已完成压缩的数量
fail Number 压缩失败的数量
count Number 总共需要压缩的数量
源码示例: 

// 单张压缩
this.$refs.helangCompress.compressFun({
    src:this.paths[0],
    maxSize:800,
    fileType:'jpg',
    quality:0.85,
    minSize:640 //最小压缩尺寸,图片尺寸小于该时值不压缩,非H5平台有效。若需要忽略该设置,可设置为一个极小的值,比如负数。
}).then((res)=>{
    // 压缩成功回调
}).catch((err)=>{
    // 压缩失败回调
})

// 批量压缩
this.$refs.helangCompress.compress({
    src:this.paths,
    maxSize:800,
    fileType:'jpg',
    quality:0.85,
    progress:(res)=>{
        console.log('压缩进度');
        console.log(res);
    }
}).then((res)=>{
    // 压缩成功回调
}).catch((err)=>{
    // 压缩成功回调
})
 thank

图片压缩 - 可以自定义压缩尺寸和压缩质量 - DCloud 插件市场