效果图:

 

 

我用的是uni-app,直接在项目里创建一个vue文件代码放进去就可以了。

记得替换掉几处图片的地址:

有需要的可以封装成组件使用。

<template>
	<view>
		<canvas canvas-id="myCanvas" style="width: 690px;height:1040px; position: fixed;top: -10000px;"></canvas>
		<image @click="saveShareImg(canvasToTempFilePath)" style="width: 690upx; height: 1040upx;" :src="canvasToTempFilePath" mode=""></image>
	</view>
</template>

<script>
export default {
	onLoad() {
		this.createCanvasImage();
	},
	data() {
		return {
			ratio: 1,
			ctx: null, // 创建canvas对象
			canvasToTempFilePath: null, // 保存最终生成的导出的图片地址
			openStatus: true // 声明一个全局变量判断是否授权保存到相册
		};
	},
	methods: {
		// 生成海报
		async createCanvasImage() {
			let self = this;
			// 点击生成海报数据埋点
			if (!self.ctx) {
				let codeUrl = 'https://api.jiapeijia.com/wxcode/20200914/c4ca4238a0b923820dcc509a6f75849b.png';
				let coverUrl = 'https://api.jiapeijia.com/static/cover.jpg';
				let headUrl = 'https://api.jiapeijia.com/uploads/1.png';
				wx.showLoading({
					title: '生成中...'
				});
				let code = new Promise(function(resolve) {
					wx.getImageInfo({
						src: codeUrl,
						success: function(res) {
							resolve(res.path);
						},
						fail: function(err) {
							console.log(err);
							wx.showToast({
								title: '网络错误请重试',
								icon: 'loading'
							});
						}
					});
				});
				
				let cover = new Promise(function(resolve) {
					wx.getImageInfo({
						src: coverUrl,
						success: function(res) {
							resolve(res.path);
						},
						fail: function(err) {
							console.log(err);
							wx.showToast({
								title: '网络错误请重试',
								icon: 'loading'
							});
						}
					});
				});

				// 头像
				let headImg = new Promise(function(resolve) {
					wx.getImageInfo({
						src: headUrl,
						success: function(res) {
							resolve(res.path);
						},
						fail: function(err) {
							console.log(err);
							wx.showToast({
								title: '网络错误请重试',
								icon: 'loading'
							});
						}
					});
				});

				Promise.all([headImg, code,cover]).then(function(result) {
					const ctx = wx.createCanvasContext('myCanvas');
					console.log(ctx, self.ratio, 'ctx');
					let canvasWidthPx = 690 * self.ratio,
						canvasHeightPx = 1040 * self.ratio,
						
						avatarurl_width = 110, //绘制的头像宽度
						avatarurl_heigth = 110, //绘制的头像高度
						avatarurl_x = 95, //绘制的头像在画布上的位置
						avatarurl_y = 35, //绘制的头像在画布上的位置
						
						codeurl_width = 180, //绘制的二维码宽度
						codeurl_heigth = 180, //绘制的二维码高度
						codeurl_x = 70, //绘制的二维码在画布上的位置
						codeurl_y = 800, //绘制的二维码在画布上的位置
						
						coverurl_width = 610, //绘制的封面宽度
						coverurl_heigth = 350, //绘制的封面高度
						coverurl_x = 40, //绘制的封面在画布上的位置
						coverurl_y = 190; //绘制的封面在画布上的位置
						
					ctx.drawImage('/static/bg.jpg', 0, 0, 690, 1040); // 背景图片需要本地
					
					// 白底
					ctx.setFillStyle('#ffffff')
					ctx.fillRect(25, 175, 640, 840)
					
					ctx.save(); // 先保存状态 已便于画完圆再用
					ctx.beginPath(); //开始绘制
					//先画个圆   前两个参数确定了圆心 (x,y) 坐标  第三个参数是圆的半径  四参数是绘图方向  默认是false,即顺时针
					ctx.arc(avatarurl_width / 2 + avatarurl_x, avatarurl_heigth / 2 + avatarurl_y, avatarurl_width / 2, 0, Math.PI * 2, false);
					ctx.clip(); //画了圆 再剪切  原始画布中剪切任意形状和尺寸。一旦剪切了某个区域,则所有之后的绘图都会被限制在被剪切的区域内
					ctx.drawImage(result[0], avatarurl_x, avatarurl_y, avatarurl_width, avatarurl_heigth); // 推进去图片

					ctx.restore(); //恢复之前保存的绘图上下文状态 可以继续绘制
					
					ctx.font = 'normal bold 45px sans-serif';
					ctx.setFillStyle('#ffffff'); // 文字颜色
					ctx.fillText('微信昵称', 240, 85); // 绘制文字

					ctx.setFillStyle('#ffffff'); // 文字颜色
					ctx.setFontSize(30); // 文字字号
					ctx.fillText('推荐您来捷通驾校', 240, 130); // 绘制文字

					ctx.font = 'normal bold 40px sans-serif';
					ctx.setFillStyle('#222222');
					ctx.fillText('上捷通驾校', 40, 600);

					ctx.font = 'normal normal 26px sans-serif';
					ctx.setFillStyle('#666666'); // 文字颜色
					ctx.fillText('上海市松江区小昆山镇平原街398号5号楼', 40, 640); // 绘制文字
					
					// 白底
					ctx.setFillStyle('#CBE6FE')
					ctx.fillRect(40, 670, 125, 40)

					ctx.font = 'normal normal 24px sans-serif';
					ctx.setFillStyle('#1F8DFE'); // 文字颜色
					ctx.fillText('自有考场', 55, 700); // 绘制文字
					
					// 白底
					ctx.setFillStyle('#FDE5D2')
					ctx.fillRect(180, 670, 125, 40)
					
					ctx.setFillStyle('#F37F26'); // 文字颜色
					ctx.fillText('收费透明', 195, 700); // 绘制文字
					
					// 白底
					ctx.setFillStyle('#D2F1EF')
					ctx.fillRect(320, 670, 125, 40)
					
					ctx.setFillStyle('#2EBBB4'); // 文字颜色
					ctx.fillText('有接送', 335, 700); // 绘制文字
					

					ctx.beginPath();
					// 设置线宽
					ctx.lineWidth = 1;
					// 设置间距(参数为无限数组,虚线的样式会随数组循环)
					ctx.setLineDash([10, 10]);
					// 移动画笔至坐标 x20 y20 的位置
					ctx.moveTo(30, 760);
					// 绘制到坐标 x20 y100 的位置
					ctx.lineTo(660, 760);
					// 填充颜色
					ctx.strokeStyle="#aaaaaa";
					// 开始填充
					ctx.stroke();
					ctx.closePath();
					
					ctx.font = 'normal normal 36px sans-serif';
					ctx.setFillStyle('#E65449'); // 文字颜色
					ctx.fillText('长按识别', 300, 870); // 绘制孩子百分比
					
					ctx.font = 'normal normal 36px sans-serif';
					ctx.setFillStyle('#222222'); // 文字颜色
					ctx.fillText('小程序码', 444, 870); // 绘制孩子百分比
					
					ctx.font = 'normal normal 36px sans-serif';
					ctx.setFillStyle('#222222'); // 文字颜色
					ctx.fillText('查看驾校详细信息', 300, 920); // 绘制孩子百分比
					
					ctx.drawImage(result[2], coverurl_x, coverurl_y, coverurl_width, coverurl_heigth); // 绘制封面
					ctx.drawImage(result[1], codeurl_x, codeurl_y, codeurl_width, codeurl_heigth); // 绘制头像
					ctx.draw(false, function() {
						// canvas画布转成图片并返回图片地址
						wx.canvasToTempFilePath({
							canvasId: 'myCanvas',
							success: function(res) {
								self.canvasToTempFilePath = res.tempFilePath;
								self.showShareImg = true;
								console.log(res.tempFilePath, 'canvasToTempFilePath');
								wx.showToast({
									title: '绘制成功'
								});
							},
							fail: function() {
								wx.showToast({
									title: '绘制失败'
								});
							},
							complete: function() {
								wx.hideLoading();
								wx.hideToast();
							}
						});
					});
				});
			}
		},

		// 保存到系统相册
		saveShareImg: function(canvasToTempFilePath) {
			let self = this;
			// 数据埋点点击保存海报
			self.saveId = '保存学情海报';
			// 获取用户是否开启用户授权相册
			if (!self.openStatus) {
				wx.openSetting({
					success: result => {
						if (result) {
							if (result.authSetting['scope.writePhotosAlbum'] === true) {
								self.openStatus = true;
								wx.saveImageToPhotosAlbum({
									filePath: canvasToTempFilePath,
									success() {
										self.showShareImg = false;
										wx.showToast({
											title: '图片保存成功,快去分享到朋友圈吧~',
											icon: 'none',
											duration: 2000
										});
									},
									fail() {
										wx.showToast({
											title: '保存失败',
											icon: 'none'
										});
									}
								});
							}
						}
					},
					fail: () => {},
					complete: () => {}
				});
			} else {
				wx.getSetting({
					success(res) {
						// 如果没有则获取授权
						if (!res.authSetting['scope.writePhotosAlbum']) {
							wx.authorize({
								scope: 'scope.writePhotosAlbum',
								success() {
									self.openStatus = true;
									wx.saveImageToPhotosAlbum({
										filePath: canvasToTempFilePath,
										success() {
											self.showShareImg = false;
											wx.showToast({
												title: '图片保存成功,快去分享到朋友圈吧~',
												icon: 'none',
												duration: 2000
											});
										},
										fail() {
											wx.showToast({
												title: '保存失败',
												icon: 'none'
											});
										}
									});
								},
								fail() {
									// 如果用户拒绝过或没有授权,则再次打开授权窗口
									self.openStatus = false;
									console.log('请设置允许访问相册');
									wx.showToast({
										title: '请设置允许访问相册',
										icon: 'none'
									});
								}
							});
						} else {
							// 有则直接保存
							self.openStatus = true;
							wx.saveImageToPhotosAlbum({
								filePath: canvasToTempFilePath,
								success() {
									self.showShareImg = false;
									wx.showToast({
										title: '图片保存成功,快去分享到朋友圈吧~',
										icon: 'none',
										duration: 2000
									});
								},
								fail() {
									wx.showToast({
										title: '保存失败',
										icon: 'none'
									});
								}
							});
						}
					},
					fail(err) {
						console.log(err);
					}
				});
			}
		}
	}
};
</script>

<style></style>

里面有用到虚线绘制:

context.beginPath();
// 设置线宽
context.lineWidth = 4;
// 设置间距(参数为无限数组,虚线的样式会随数组循环)
context.setLineDash([8, 8]);
// 移动画笔至坐标 x20 y20 的位置
context.moveTo(20, 20);
// 绘制到坐标 x20 y100 的位置
context.lineTo(20, 100);
// 绘制到坐标 x70, y100 的位置
context.lineTo(70, 100);
// 填充颜色
context.strokeStyle="red";
// 开始填充
context.stroke();
context.closePath();


// 切换回实线
context.setLineDash([]);

 

Logo

前往低代码交流专区

更多推荐