IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 游戏开发 -> 小程序 - canvas绘制海报 -> 正文阅读

[游戏开发]小程序 - canvas绘制海报

需求背景

小程序不能直接分享至朋友圈,所以采用海报(最关键的就是邀请码)邀请好友。
从展示层面来讲,就是几张图,通过定位放在一起即可,但是关键是要保存,这个时候,就需要canvas去进行图片合成。那么canvas绘制海报,就拆分两个部分

通过css ,给用户展现的组合图片,这跟简单

通过css 布局,将各个元素组合在一起。这个想必不用多说,
在这里插入图片描述

保存时,通过canvas绘图,将图片合成一个完整的图片

canvas 绘图,有两种模式

  1. 新版 2d 模式(有坑,慎用)
    在这里插入图片描述

  2. 老版 canvas-id=“drawPoster”,虽然操作繁琐,但是兼容性好
    在这里插入图片描述
    获取图片尺寸

downShareImage(imgurl) {
		console.log('imgurl', imgurl);
		return new Promise((resolve, reject) => {
			wx.getImageInfo({
				src: imgurl,
				success: (res) => {
					let { width, height, path } = res;
					resolve({
						width,
						height,
						path,
					});
				},
				fail: () => {
					wx.showToast({
						title: '下载失败',
						icon: 'none',
					});
					reject('下载失败...');
				},
			});
		});
	},

canvas 绘图

	async drawPoster() {
		const { qrCodeImg, avatarImg, downImgRes, nickname } = this.data;
		const ctx = wx.createCanvasContext('drawPoster');
		ctx.drawImage(downImgRes.path, 0, 0, downImgRes.width, downImgRes.height);
		const avatarImgW = 233;
		const qrCodeW = 220;
		const radius = 233 / 2;
		let qrRadious = qrCodeW / 2;
		let avX = downImgRes.width / 2 - avatarImgW + 120;
		let avY = 100;
		let qrX = downImgRes.width / 2 - qrCodeW + 110;
		let qrY = 990;
		ctx.save();
		ctx.beginPath();
		ctx.arc(avX + radius, avY + radius, radius, 0, 2 * Math.PI); // arc方法画曲线,按照中心点坐标计算,所以要加上半径
		ctx.clip();
		ctx.drawImage(avatarImg, avX, avY, 233, 233);
		ctx.restore();
		ctx.setFontSize(50);
		ctx.setTextAlign('center');
		ctx.setFillStyle('#7700d9');
		ctx.fillText(nickname, downImgRes.width / 2, 415);
		ctx.save();
		ctx.arc(qrX + qrRadious, qrY + qrRadious, qrRadious, 0, 2 * Math.PI); // arc方法画曲线,按照中心点坐标计算,所以要加上半径
		ctx.clip();
		ctx.drawImage(qrCodeImg, qrX, qrY, 220, 220);
		ctx.restore();
		ctx.draw(false, async () => {
			let canvasData = await this.exportPoster();
			this.setData({
				canvasData,
			});
		});
	},

canvas合成图片

exportPoster() {
		return new Promise((resolve, reject) => {
			wx.canvasToTempFilePath({
				x: 0,
				y: 0,
				width: 1061,
				height: 1404,
				canvasId: 'drawPoster',
				fileType: 'png',
				success(res) {
					resolve(res.tempFilePath);
				},
				fail() {
					wx.showToast({
						title: '下载失败',
						icon: 'none',
					});
					reject('二维码生成失败');
				},
			});
		});
	},

长按保存:

	saveImage() {
		const { canvasData } = this.data;
		if (!canvasData)
			return wx.showToast({
				title: '海报生成中',
				icon: 'none',
			});
		if (this.drawPosterLock) return;
		this.drawPosterLock = true;
		wx.saveImageToPhotosAlbum({
			filePath: canvasData,
			success: (res) => {
				if (res.errMsg == 'saveImageToPhotosAlbum:ok') {
					wx.showToast({
						title: '保存成功',
					});
				}
			},
			complete: () => {
				this.drawPosterLock = false;
			},
			fail: () => {
				wx.showToast({
					title: '保存失败',
					icon: 'none',
				});
			},
		});
	},

授权逻辑

// 保存为图片
	handlerSavePhoto() {
		let touchTime = this.data.touchEnd - this.data.touchStart;
		console.log('touchTime', touchTime);
		if (touchTime > 800) {
			wx.getSetting({
				success: (res) => {
					var userPhotosAlbum = res.authSetting['scope.writePhotosAlbum'];
					if (userPhotosAlbum) {
						this.saveImage();
						return;
					}
					if (userPhotosAlbum == undefined) {
						//第一次,从未请求过权限
						wx.authorize({
							scope: 'scope.writePhotosAlbum',
							success: (res) => {
								if (res.errMsg == 'authorize:ok') {
									//授权位置弹框中点击 允许
									this.saveImage();
								}
							},
						});
						return;
					}
					if (userPhotosAlbum != 'undefined') {
						// 第一次授权弹框点拒绝的情况 未允许授权
						wx.showModal({
							title: '提示',
							content: '暂无权限,请开启使用权限',
							success: (res) => {
								if (res.confirm) {
									wx.openSetting({
										success: (res) => {
											if (res.authSetting['scope.writePhotosAlbum']) {
												this.saveImage();
											} else {
												// 未授权
											}
										},
									});
								}
							},
						});
					}
				},
			});
		}
	},

总结:

  1. 我们在画canvas总是会担心尺寸问题,并且由尺寸带来的绘图模糊问题。因为小程序单位是rpx(根据不同机型进行适配的单位),但是canvas绘图单位是px,这里有一个好方法。
  • 其实给用户看的,就是一个css布局的图片,用小程序本身的单位,就能解决不同分辨率的问题,而且渲染速度特别快。
  • 用户保存的时候,保存的是canvas画图,合成图片的照片,肯定是px,那么你给canvas宽高,只要和目标图一致即可,或者放大两倍,都是ok的
  1. 由于画图需要拿到数据,并且是异步的,要用await去做同步顺序
  2. 利用promise封装很优美
  3. 用ctx.clip();去裁剪图片,会破坏当前的画布环境 ,所以需要先保存之前的画布环境,然后开始画,画完恢复之前的画布环境
  游戏开发 最新文章
6、英飞凌-AURIX-TC3XX: PWM实验之使用 GT
泛型自动装箱
CubeMax添加Rtthread操作系统 组件STM32F10
python多线程编程:如何优雅地关闭线程
数据类型隐式转换导致的阻塞
WebAPi实现多文件上传,并附带参数
from origin ‘null‘ has been blocked by
UE4 蓝图调用C++函数(附带项目工程)
Unity学习笔记(一)结构体的简单理解与应用
【Memory As a Programming Concept in C a
上一篇文章      下一篇文章      查看所有文章
加:2022-04-22 19:10:32  更:2022-04-22 19:12:04 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 13:44:04-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码