uniapp绘制分享海报

uniApp 分享海报

uniapp生成海报,带适配,文字多出省略号,圆角矩形

<template>
	<view>
		<view class="invite_img" @click="showposter">生成海报</view>
		<canvas canvas-id="poster" id="poster" class="poster-box"></canvas>
		<u-popup v-model="show" mode="center">
			<image :src="posterImg" class="posterImg" mode=""></image>
			<image src="../../static/images/poster_close.png" mode="" class="close" @click="close"></image>
			<view class="button" @click="saveposter">保存到相册</view>
		</u-popup>
	</view>
</template>

<script>


export default {
    
    
	data() {
    
    
		return {
    
    
			_w:0,
			userInfo: {
    
    
				//海报所需数据
				avatar_url: 'https://t7.baidu.com/it/u=1595072465,3644073269&fm=193&f=GIF',
				qRCodeImgUrl: 'https://t7.baidu.com/it/u=1595072465,3644073269&fm=193&f=GIF',

				nickname: '笑一个吧123123哈哈哈哈哈哈哈哈哈',
				mobile: '182****1022',
				code: '123456'
			},
			bgImgUrl: 'https://img2.baidu.com/it/u=2556294903,542088888&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=281', //海报背景
			finger: 'https://img1.baidu.com/it/u=3298452815,4076337725&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=501', //海报手指图片
			show: false,
			posterImg: '',
			loading: false
		};
	},
	async onReady() {
    
    
		this.getSystemInfo(); //获取屏幕宽度适配比例
	},
	async onLoad() {
    
    
		this.showposter();
	},
	onShow() {
    
    
	
	},
	mounted() {
    
    
		
	},
	methods: {
    
    
		//将canvas转图片
		async showposter() {
    
    
			// if (this.detail.is_vip != 1) {
    
    
			// 	uni.showModal({
    
    
			// 		title: '您还不是会员',
			// 		content: '需要购买会员勋章后邀请,用户才能获得分销金',
			// 		cancelText: '前往购买',
			// 		confirmText: '知道了',
			// 		cancelColor: '#8392A6',
			// 		success: (res) => {
    
    
			// 		        if (res.confirm) {
    
    
			// 		            console.log('用户点击确定');
			// 		        } else if (res.cancel) {
    
    
			// 		           uni.navigateTo({
    
    
			// 		           	url: "/pages/vipDetail/vipDetail?id=" + this.detail.member_deal_list[0].id
			// 		           })
			// 		        }
			// 		    }

			// 	})
			// 	return
			// }

			uni.showLoading({
    
    
				title: '海报生成中...'
			});

			//  绘制海报所需数据    如果是本地图片使用this.getImageInfoUrl
			let bgImgUrl = await this.createImgUrl(this.bgImgUrl);
			let fingerUrl = await this.createImgUrl(this.finger);
			let avatar_url = await this.createImgUrl(this.userInfo.avatar);
			let qRCodeImgUrl = await this.createImgUrl(this.userInfo.qr_code);
			console.log('posterMsg', this.userInfo.avatar, this.userInfo.qr_code);
			this.posterCanvas({
    
    
				bgImgUrl,
				fingerUrl,
				headImgUrl: avatar_url,
				CodeImgUrl: qRCodeImgUrl,
				nickName: this.userInfo.nickname,
				phone: this.userInfo.mobile,
				code: this.userInfo.code
			});
		},
		//保存图片
		saveposter() {
    
    
			const that = this;
			uni.getImageInfo({
    
    
				src: this.posterImg,
				success: res => {
    
    
					console.log('res', res.path);
					uni.saveImageToPhotosAlbum({
    
    
						filePath: res.path,
						success: function() {
    
    
							uni.showToast({
    
    
								title: '保存成功'
							});
						},
						fail: function(err) {
    
    
							console.log('err1', err);
						}
					});
				},
				fail: err => {
    
    
					console.log('errr', err);
				}
			});
		},
		close() {
    
    
			this.show = false;
		},
		// 绘制海报
		posterCanvas({
    
     bgImgUrl = '', headImgUrl = '', nickName = '', phone = '', CodeImgUrl = '', code = '', fingerUrl = '' }) {
    
    
			let that = this;
			let ctx = uni.createCanvasContext('poster', this);
			//填充白色背景
			ctx.fillStyle = '#FFFFFF';
			ctx.fillRect(0, 0, this.calculate(310), this.calculate(494.5));
			//头部背景图
			ctx.drawImage(bgImgUrl, 0, 0, this.calculate(310), this.calculate(200));
			ctx.restore();
			//头像
			console.log('头像');
			ctx.save()
			//ctx.drawImage(headImgUrl, this.calculate(16), this.calculate(182), this.calculate(68), this.calculate(68));
			this.circleImgTwo(ctx, headImgUrl, this.calculate(16), this.calculate(182), this.calculate(68), this.calculate(68), 10);
			ctx.restore();
			// 名字
			console.log('名字');
			this.dealWords({
    
    
				ctx,
				fontSize: 18,
				color: '#292F3E',
				word: nickName,
				maxWidth: this.calculate(210),
				x: this.calculate(93),
				y: this.calculate(210),
				maxLine: 1
			});
			ctx.restore();
			// 电话号码
			console.log('电话');
			ctx.setFillStyle('#6E717A');
			ctx.setFontSize(12);
			ctx.fillText(phone, this.calculate(93), this.calculate(246));
			ctx.restore();
			//绘制二维码
			console.log('二维码');
			ctx.drawImage(CodeImgUrl, this.calculate(75), this.calculate(265), this.calculate(160), this.calculate(160));
			ctx.restore();
			//绘制邀请码
			ctx.setFillStyle('#292F3E');
			ctx.setFontSize(12);
			ctx.fillText('专属邀请码:', this.calculate(88), this.calculate(445));
			ctx.restore();
			//邀请码
			ctx.setFillStyle('#FF0677');
			ctx.setFontSize(17);
			ctx.fillText(code, this.calculate(162), this.calculate(445));
			ctx.restore();
			// 提示语
			ctx.drawImage(fingerUrl, this.calculate(39), this.calculate(465), this.calculate(20), this.calculate(14));
			ctx.restore();
			ctx.setFillStyle('#5C6476');
			ctx.setFontSize(12);
			ctx.fillText('分享给你的好友,让TA跟你一起做任务', this.calculate(65), this.calculate(476));

			ctx.restore();
			ctx.draw();
			// 海报绘制完成
			// 转换成图片
			setTimeout(() => {
    
    
				uni.canvasToTempFilePath({
    
    
					x: 0,
					y: 0,
					width: that.calculate(310),
					height: that.calculate(494.5),
					// destWidth: this.calculate(930),
					// destHeight: this.calculate(1483.5),
					quality: 1,
					canvasId: 'poster',
					success: res => {
    
    
						console.log(res.tempFilePath, '生成图片');
						that.posterImg = res.tempFilePath;

						uni.hideLoading();

						that.show = true;
					},
					fail: err => {
    
    
						console.log('err', err);
						uni.showToast({
    
    
							title: '生成失败',
							icon: 'none'
						});
						uni.hideLoading();
					}
				});
			}, 1000);
		},

		// 获取系统适配
		getSystemInfo() {
    
    
			let _this = this;
			uni.getSystemInfo({
    
    
				success(res) {
    
    
					_this._w = res.windowWidth;
				}
			});
		},
		// 画布计算比例
		calculate(num) {
    
    
			let w = this._w;
			let n = parseInt((w * num) / 375);
			return n;
		},
		// 创建本地地址
		createImgUrl: url =>
			new Promise((resolve, reject) => {
    
    
				uni.downloadFile({
    
    
					url,
					success: val => resolve(val.tempFilePath),
					fail: err => {
    
    
						console.log('e', err);
						uni.showToast({
    
    
							title: '图片出现错误',
							icon: 'none'
						});
						reject(err);
					}
				});
			}),
		// 本地资源路径
		getImageInfoUrl: url =>
			new Promise((resolve, reject) => {
    
    
				uni.getImageInfo({
    
    
					src: url,
					success: val => resolve(val.path),
					fail: err => {
    
    
						console.log('e', err);
						reject(err);
					}
				});
			}),
			/*  绘制圆角矩形   需要在前面save一下   再用restore恢复
		 *  参数说明
		 *  ctx Canvas实例
		 *  img 图片地址
		 *   x  x轴坐标
		 *   y  y轴坐标
		 *   w  宽度
		 *   h  高度
		 *   r  弧度大小
		 */
		circleImgTwo(ctx, img, x, y, w, h, r) {
    
    
			// 画一个图形
			if (w < 2 * r) r = w / 2;
			if (h < 2 * r) r = h / 2;
			ctx.beginPath();
			ctx.moveTo(x + r, y);
			ctx.arcTo(x + w, y, x + w, y + h, r);
			ctx.arcTo(x + w, y + h, x, y + h, r);
			ctx.arcTo(x, y + h, x, y, r);
			ctx.arcTo(x, y, x + w, y, r);
			ctx.closePath();
			ctx.strokeStyle = '#FFFFFF'; // 设置绘制圆形边框的颜色
			ctx.stroke();
			ctx.clip();  //从原始画布中剪切任意形状和尺寸。一旦剪切了某个区域,则所有之后的绘图都会被限制在被剪切的区域内(不能访问画布上的其他区域)。可以在使用 clip() 方法前通过使用 save() 方法对当前画布区域进行保存,并在以后的任意时间对其进行恢复(通过 restore() 方法)      需要在前面save一下
			ctx.drawImage(img, x, y, w, h);
		},
		//处理文字多出省略号显示
		dealWords(options) {
    
    
			options.ctx.setFontSize(options.fontSize); //设置字体大小
			options.ctx.setFillStyle(options.color); //设置字体颜色
			var allRow = Math.ceil(options.ctx.measureText(options.word).width / options.maxWidth); //实际总共能分多少行
			var count = allRow >= options.maxLine ? options.maxLine : allRow; //实际能分多少行与设置的最大显示行数比,谁小就用谁做循环次数

			var endPos = 0; //当前字符串的截断点
			for (var j = 0; j < count; j++) {
    
    
				var nowStr = options.word.slice(endPos); //当前剩余的字符串
				var rowWid = 0; //每一行当前宽度
				if (options.ctx.measureText(nowStr).width > options.maxWidth) {
    
    
					//如果当前的字符串宽度大于最大宽度,然后开始截取
					for (var m = 0; m < nowStr.length; m++) {
    
    
						rowWid += options.ctx.measureText(nowStr[m]).width; //当前字符串总宽度
						if (rowWid > options.maxWidth) {
    
    
							if (j === options.maxLine - 1) {
    
    
								//如果是最后一行
								options.ctx.fillText(nowStr.slice(0, m - 1) + '...', options.x, options.y + (j + 1) * 18); //(j+1)*18这是每一行的高度
							} else {
    
    
								options.ctx.fillText(nowStr.slice(0, m), options.x, options.y + (j + 1) * 18);
							}
							endPos += m; //下次截断点
							break;
						}
					}
				} else {
    
    
					//如果当前的字符串宽度小于最大宽度就直接输出
					options.ctx.fillText(nowStr.slice(0), options.x, options.y + (j + 1) * 18);
				}
			}
		}
	}
};
</script>

<style lang="scss" scoped>
.header {
    
    
	background: url(../../static/images/memberCenter_bg.png) no-repeat;
	height: 520rpx;
	background-size: cover;
	background-position: center;
	padding-bottom: 30rpx;
	position: relative;
	::v-deep .u-navbar {
    
    
		background: rgba(0, 0, 0, 0) !important;
	}
}

.on ::v-deep .u-navbar {
    
    
	background: RGBA(196, 213, 255, 1) !important;
}

::v-deep .u-mode-center-box {
    
    
	background: none;
}

.userInfo {
    
    
	display: flex;
	align-items: center;
	padding-left: 40rpx;
	margin-top: 15rpx;

	.headerImg {
    
    
		height: 120rpx;
		width: 120rpx;
		border-radius: 50%;
		margin-right: 26rpx;
	}

	.username {
    
    
		font-size: 40rpx;
		font-family: PingFang SC;
		font-weight: bold;
		color: #292f3e;

		.vip {
    
    
			height: 36rpx;
			width: 36rpx;
			margin-left: 16rpx;
		}
	}

	.inviteed {
    
    
		margin-top: 10rpx;
		font-size: 24rpx;
		font-family: PingFang SC;
		font-weight: 500;
		color: rgba(92, 100, 118, 0.6);

		.inviteed_num {
    
    
			font-size: 32rpx;
			font-family: PingFang SC;
			font-weight: bold;
			color: rgba(92, 100, 118, 0.8);
		}
	}
}

.explain {
    
    
	// position: absolute;
	box-sizing: border-box;

	margin: 0 24rpx;
	margin-top: 48rpx;
	// top: 310rpx;
	// left: 24rpx;
	// right: 24rpx;
	// width: 702rpx;
	// height: 403rpx;
	background: #ffffff;
	padding: 29rpx 33rpx 33rpx 33rpx;
	box-shadow: 0px 0px 25rpx 0px rgba(83, 105, 161, 0.1);
	border-radius: 16rpx;

	.explain_title {
    
    
		font-size: 30rpx;
		font-family: PingFang SC;
		font-weight: bold;
		color: #292f3e;
		margin-bottom: 10rpx;
		// margin-top: 29rpx;
	}
}

.invite_img {
    
    
	height: 175rpx;
	margin: 0 24rpx;
	margin-top: 15rpx;
	.invite_img_cover {
    
    
		height: 175rpx;
		width: 100%;
	}
}

.buy_vip_title {
    
    
	font-size: 32rpx;
	font-family: PingFang SC;
	font-weight: bold;
	color: #292f3e;
	margin: 51rpx 0 0rpx 32rpx;
}

.buy_vip_item {
    
    
	// width: 686rpx;
	height: 196rpx;
	background: #fcfbf7;
	border: 2rpx solid #eaac3c;
	border-radius: 16rpx;
	margin: 0 32rpx;
	margin-top: 30rpx;
	display: flex;
	justify-content: space-between;
	align-items: center;
	padding: 0 42rpx;
}

.vip_name {
    
    
	font-size: 36rpx;
	font-family: PingFang SC;
	font-weight: bold;
	color: #cc9512;
}

.vip_time {
    
    
	font-size: 26rpx;
	font-family: PingFang SC;
	font-weight: 500;
	color: #cc9512;
	margin-top: 20rpx;
}

.vip_money_num {
    
    
	font-size: 32rpx;
	font-family: PingFang SC;
	font-weight: bold;
	color: #292f3e;
}

.buy_button {
    
    
	margin-top: 24rpx;
	width: 160rpx;
	height: 56rpx;
	background: linear-gradient(90deg, #f2e098 0%, #f1c370 100%);
	border-radius: 28rpx;
	font-size: 24rpx;
	text-align: center;
	line-height: 56rpx;
	font-family: PingFang SC;
	font-weight: bold;
	color: #934b0c;
}

.buy_vip_name {
    
    
	display: flex;
	flex-direction: column;
	justify-content: space-between;
	align-items: center;
}

.buy_vip_money {
    
    
	display: flex;
	justify-content: space-between;
	flex-direction: column;
	align-items: center;
}

.poster-box {
    
    
	width: 620rpx;
	height: 989rpx;
	position: fixed;
	// left: 10rpx;
	left: 110vw;
	top: 0rpx;
	z-index: -1;
	// background-color: #fff;
	// border: 1px solid red;
	// z-index: -1;
}

.posterImg {
    
    
	width: 620rpx;
	height: 989rpx;
	border-radius: 20rpx;
}

.button {
    
    
	width: 400rpx;
	height: 88rpx;
	line-height: 88rpx;
	margin: 0 auto;
	text-align: center;
	font-size: 30rpx;
	font-family: PingFang SC;
	font-weight: 500;
	color: #262a32;
	background: #ffffff;
	border-radius: 16rpx;
	margin-top: 48rpx;
}
.close {
    
    
	height: 32rpx;
	width: 32rpx;
	position: absolute;
	top: 20rpx;
	right: 20rpx;
}
</style>

猜你喜欢

转载自blog.csdn.net/weixin_45028704/article/details/125315635