+
83
-

回答

我写了一个基础的图片预览画笔涂改局部区域形成蒙版的组件,蒙版图片尺寸与原图一致,效果如下:

800_auto

800_auto

实现的uniapp组件代码如下:

点击查看代码

<template>
	<view class="image-mask-editor">
		<view v-if="!imagePath" class="upload-container">
			<button @tap="chooseImage">上传图片</button>
		</view>

		<view v-else class="canvas-container"
			style="position: fixed; top: 0;bottom: 0;left:0;right:0; width: 100%;z-index:3;background-color: black;">

			<view style="position: relative;">
				<!-- <canvas style="display: none;" canvas-id="myCanvas" :style="canvasStyleexport" ></canvas> -->


				<image :src="imagePath" mode="widthFix" class="background-image" :style="imgStyle"></image>
				<canvas canvas-id="maskCanvas" class="maskCanvas" :style="canvasStyle" @touchstart="touchstartmask"
					@touchmove="touchmovemask" @touchend="touchendmask"></canvas>
				<view class="controls">
					<button @tap="clearMask">清除遮罩</button>
					<button @tap="getMaskImage">预览遮罩图</button>
				</view>
			</view>

		</view>
	</view>
</template>

<script>
	export default {
		data() {
			return {
				ctx: null,
				scaleratio: 0,
				imgrealWidth: 0,
				imgrealHeight: 0,
				screenWidth: 0,
				screenHeight: 0,
				canvasStyle: '',
				soureimgPath: "", //原图压缩后与蒙版图尺寸一致
				imgStyle: '',
				imagePath: '',
				points: [], //路径点集合
				isDrawing: false,
				lastX: 0,
				lastY: 0,
			}
		},
		onReady() {
			// 获取屏幕宽度
			uni.getSystemInfo({
				success: (res) => {
					this.screenWidth = res.windowWidth
					this.screenHeight = res.windowHeight
				}
			})
		},
		methods: {
			chooseImage() {
				uni.chooseImage({
					count: 1,
					success: (res) => {
						this.soureimgPath =  res.tempFilePaths[0]
						this.imagePath = res.tempFilePaths[0]
						this.$nextTick(() => {
							this.initCanvas()
						})
					}
				})
			},
			initCanvas() {
				// 获取图片尺寸以设置画布大小
				uni.getImageInfo({
					src: this.imagePath,
					success: (imageInfo) => {
						// 设置 canvas 的实际尺寸为图片尺寸
						this.imgrealWidth = imageInfo.width;
						this.imgrealHeight = imageInfo.height;




						//this.setCanvasStyle();

						// 创建 canvas 上下文
						this.ctx = uni.createCanvasContext('maskCanvas', this);



						const scale = this.screenWidth / this.imgrealWidth;
						this.scaleratio = scale;
						// 根据原始宽高比计算正确的高度
						const height = this.imgrealHeight * scale;

						const top = (this.screenHeight / 2) - (height / 2);
						this.imgStyle = `top:${top}px;`;
						this.canvasStyle =
							`width: ${this.screenWidth}px; height: ${height}px;top:${top}px; `
						// this.canvasStyleexport =
						// 	`width: ${this.imgrealWidth}px; height: ${this.imgrealHeight}px; `
						// // 设置 canvas 的绘图尺寸
						this.ctx.width = this.screenWidth;
						this.ctx.height = height;

						// 将图片绘制到画布上作为尺寸压缩后的原图
						// this.ctx.drawImage(this.imagePath, 0, 0, this.screenWidth, height);
						// this.ctx.draw();
						// this.$nextTick(() => {
						// 	uni.canvasToTempFilePath({
						// 		canvasId: 'maskCanvas',
						// 		success: (res) => {
						// 			console.log('原图压缩后图片路径:', res.tempFilePath);
									
						// 			this.soureimgPath = res.tempFilePath;
						// 			this.clearMask();
						// 	// 		uni.previewImage({
						// 	// 			urls: [res.tempFilePath]
						// 	// 		})
							
						// 			// uni.saveFile({
						// 			// 	tempFilePath: res.tempFilePath,
						// 			// 	success: function(res) {
						// 			// 		var savedFilePath = res.savedFilePath;
						// 			// 	}
						// 			//})
						// 			// 这里可以进行后续操作,比如上传或显示遮罩图
						// 		},
						// 		fail: (err) => {
						// 			console.error('获取遮罩图片失败:', err);
						// 		}
						// 	});
							
						// })

						

					},
				});
			},
			setCanvasStyle() {
				// 计算缩放比例
				const scale = this.screenWidth / this.imgrealWidth;
				this.scaleratio = scale;
				// 根据原始宽高比计算正确的高度
				const height = this.canvasHeight * scale;
				this.canvasStyle =
					`width: ${this.screenWidth}px; height: ${height}px; transform: scale(1); transform-origin: left top;`
			},
			touchstartmask(e) {
				this.isDrawing = true;
				this.lastX = e.changedTouches[0].x;
				this.lastY = e.changedTouches[0].y;
				this.drawCircle(this.lastX, this.lastY);
			},
			touchmovemask(e) {
				if (!this.isDrawing) return;
				const currentX = e.changedTouches[0].x;
				const currentY = e.changedTouches[0].y;
				this.drawCircle(currentX, currentY);
				this.lastX = currentX;
				this.lastY = currentY;
			},
			touchendmask() {
				this.isDrawing = false;
			},

			drawCircle(x, y) {

				const scaledX = x;
				const scaledY = y;
				const radius =30;

				this.ctx.beginPath();
				this.ctx.arc(scaledX, scaledY, radius, 0, Math.PI * 2);
				this.ctx.fillStyle = 'rgba(255, 255,255, 1)';
				this.ctx.fill();
				this.ctx.draw(true);
			},
			clearMask() {

				this.ctx.clearRect(0, 0, this.screenWidth, this.screenWidth * this.scaleratio);
				this.ctx.draw();
			},
			getMaskImage() {
				uni.canvasToTempFilePath({
					canvasId: 'maskCanvas',
					
					              destWidth: this.imgrealWidth,
					              destHeight: this.imgrealHeight,
					success: (res) => {
						console.log('遮罩图片路径:', res.tempFilePath);
						uni.previewImage({
							urls: [res.tempFilePath]
						})

						// uni.saveFile({
						// 	tempFilePath: res.tempFilePath,
						// 	success: function(res) {
						// 		var savedFilePath = res.savedFilePath;
						// 	}
						//})
						// 这里可以进行后续操作,比如上传或显示遮罩图
					},
					fail: (err) => {
						console.error('获取遮罩图片失败:', err);
					}
				});
			}
		}
	}
</script>
<style>
	.maskCanvas {
		position: absolute;
		opacity: 0.4;
		z-index: 2;
		left: 0;
		top: 0;
	}

	.controls {
		display: flex;
		padding-top: 20px;
	}

	.background-image {
		position: absolute;
		left: 0;
		z-index: 1;
		width: 100%;
		right: 0;
	}
</style>

网友回复

我知道答案,我要回答