uniapp图像裁剪

第一步:拿到图片信息

第二步:计算基准框大小,设置预览图片基准值

第三步:预览图片宽高处理

第四步:获取屏幕宽高,绘制蒙层

第五步:图片预览

第六步:预览图拖拽处理

第七步:图像裁剪

<template>
	<view class="settingHeadImage" @touchstart="onTouchstart" @touchmove.stop.prevent="onTouchmove" @touchend="touchE">
		<!-- 蒙层 -->
		<canvas class="pre-canvas" canvas-id="firstCanvas" :style="{ width: 100 + 'vw', height: 100 + 'vh' }"></canvas>
		<!-- img预览 -->
		<view class="preImage" :style="{ width: preImgW + 'px' }">
			<canvas canvas-id="mycanvas" class="pre-i"
				:style="{ width: preImgW + 'px', height: preImgH + 'px', transform: `translate(${x}px,${y}px)` }"></canvas>
		</view>
		<!-- 工具 -->
		<view class="setting-btns"><text @click="onCrop">确定</text></view>
	</view>
</template>

<script>
	export default {
		data() {
			return {
				maxW: 250, // 最大宽度
				maxH: 250,
				screenWidth: '', // 屏幕宽
				screenHeight: '',
				xToTop: 0, // x方向距离顶部距离
				scale: 1, // 缩放
				preSrc: '',
				preImgW: '',
				preImgH: '',
				x: 0,
				y: 0,
				oldx: 0,
				oldy: 0,
				isMove: false,
				start: {
					left: 0,
					top: 0
				}
			};
		},
		computed: {},
		onLoad(option) {
			// 选择照片信息
			let data = JSON.parse(decodeURIComponent(option.item));
			const query = uni.createSelectorQuery();
			query.select('.settingHeadImage').boundingClientRect();
			query.exec(res => {
				// 设置屏幕大小
				this.screenWidth = res[0].width;
				this.screenHeight = res[0].height;
				// 设置图像基准值,图像基准值按屏幕宽度设置,两边留白各40
				this.maxH = res[0].width - 80;
				this.maxW = res[0].width - 80;
				// 设置X轴值,算式:屏幕高度的一半减去基准框高度的一半
				this.xToTop = this.screenHeight / 2 - this.maxH / 2;
				this.setImageSize(data);
			});
		},
		methods: {
			// 宽高处理
			setImageSize(data) {
				const {
					tempFilePath
				} = data;
				const {
					maxH,
					maxW
				} = this;
				uni.getImageInfo({
					src: tempFilePath,
					success: res => {
						const {
							errMsg,
							path,
							width,
							height
						} = res;
						let w = '';
						let h = '';
						if (errMsg === 'getImageInfo:ok') {
							w = width;
							h = height;
							// 宽大与高大于最大宽度
							if (width > height && width > maxW) {
								w = Math.floor((width / height) * maxW);
								h = maxH;
							}
							// 高大于宽大于最大高度
							if (height > width && height > maxH) {
								h = Math.floor((height / width) * maxH);
								w = maxW;
							}
							// 宽高相等或者宽高小于最大值
							if (width === height || (width < maxW && height < maxH)) {
								h = maxH;
								w = maxW;
							}
							this.preSrc = path;
							this.preImgH = h;
							this.preImgW = w;
							// 设置蒙层
							this.setBgBox();
							// 图像预览
							this.previewCanvas({
								w,
								h,
								path
							});
						}
					}
				});
			},

			// 设置蒙层
			setBgBox() {
				const {
					maxW,
					maxH,
					screenHeight,
					screenWidth,
					xToTop
				} = this;
				const ctx = uni.createCanvasContext('firstCanvas');
				// 先清除矩形
				ctx.clearRect(0, 0, screenWidth, screenHeight);
				// 设置canvas透明度
				ctx.setGlobalAlpha(0.7);
				// 设置蒙层颜色
				ctx.setFillStyle('#000000');
				// 绘制蒙层
				ctx.fillRect(0, 0, screenWidth, screenHeight);
				// 基准框留白
				ctx.clearRect(40, xToTop, maxW, maxH);
				// 绘制基准框
				ctx.beginPath();
				ctx.setStrokeStyle('#FFFFFF');
				ctx.strokeRect(40, xToTop, maxW, maxH);
				ctx.closePath();
				ctx.draw();
			},
			// 预览
			previewCanvas({
				w,
				h,
				path
			}) {
				const ctx = uni.createCanvasContext('mycanvas');
				ctx.drawImage(path, 0, 0, w, h);
				ctx.draw();
			},
			onTouchstart(ev) {
				if (ev.changedTouches.length === 1) {
					this.isMove = true;
					this.start.left = ev.changedTouches[0].clientX;
					this.start.top = ev.changedTouches[0].clientY;
				}
			},
			onTouchmove(ev) {
				const {
					maxW,
					maxH,
					preImgH,
					preImgW,
					xToTop
				} = this;
				if (this.isMove && ev.changedTouches.length === 1) {
					let clientX = ev.changedTouches[0].clientX,
						clientY = ev.changedTouches[0].clientY;
					this.x = preImgW <= maxW ? 0 : this.oldx + clientX - this.start.left;
					this.y = preImgH <= maxH ? 0 : this.oldy + clientY - this.start.top;
				}
			},
			touchE(val) {
				const {
					preImgH,
					preImgW,
					maxH,
					maxW
				} = this;
				const query = uni.createSelectorQuery();
				const fx = this.x;
				query.select('.pre-i').boundingClientRect();
				query.exec(res => {
					// x、y回弹计算
					let y = (res[0].height - res[0].width) / 2;
					/**
					 * 判断照片可移动的距离是否大于留白的值,如果大于向右划时图片的宽减去基准框的宽减去留白向左时留白,小于时按图片的可移动值
					 * */ 
					let x = (preImgW - maxW) / 2 > 40 ? (fx < 0 ? preImgW - maxW - 40 : 40) : (preImgW - maxW) / 2;
					if (preImgH > maxH) {
						this.y = this.y > y ? y : this.y < -y ? -y : this.y;
					}
					if (preImgW > maxW) {
						this.x = this.x > x ? x : this.x < -x ? -x : this.x;
					}
					this.oldx = this.x;
					this.oldy = this.y;
					this.isMove = false;
				});
			},
			// 裁剪
			onCrop() {
				let y = 0;
				let x = 0;
				const query = uni.createSelectorQuery();
				query.select('.pre-i').boundingClientRect();
				query.exec(res => {
					// 获取预览img距离左上的距离
					y = Math.abs(res[0].top);
					x = Math.abs(res[0].left);
					const {
						maxW,
						maxH,
						preImgH,
						preImgW,
						xToTop
					} = this;
					uni.canvasToTempFilePath({
						x: Math.abs(res[0].left < 0 ? x + 40 : x - 40),
						y: Math.abs(res[0].top < 0 ? xToTop + y : xToTop - y),
						width: maxW,
						height: maxH,
						destWidth: maxW,
						destHeight: maxH,
						canvasId: 'mycanvas',
						success: fileRes => {
							console.log(fileRes);
							uni.previewImage({
								count: 1,
								urls: [fileRes.tempFilePath]
							});
						},
						fail: function(err) {
							console.log(err);
							uni.showToast({
								title: '上传失败:图片生成过程中遇到错误',
								icon: 'none'
							});
						}
					});
				});
			}
		}
	};
</script>

<style lang="scss" scoped>
	.settingHeadImage {
		background-color: #000000;
		overflow: hidden;

		.pre-canvas {
			position: fixed;
			top: 0;
			left: 0;
			z-index: 20;
		}

		.preImage {
			min-width: 100vw;
			height: 100vh;
			display: flex;
			justify-content: center;
			align-items: center;
			overflow: hidden;
			z-index: 1;

			.pre-i {
				// transition: all 0.1s;
			}
		}

		.setting-btns {
			position: fixed;
			bottom: 0;
			left: 0;
			z-index: 20;
			font-size: 14px;
			color: #ffffff;
		}
	}
</style>

  • 5
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值