小程序canvas绘制邀请码

2023-10-26

针对小程序邀请好友功能,可以下载当前的海报图,分享给好友,好友通过扫描二维码跳转至小程序。

 但是邀请好友,要根据当前登录者的信息去生成二维码,目的是把邀请到的好友绑定到该用户下,所以会将二维码嵌入背景海报中,合成一张图后,生成一个临时地址,再去下载图片。下边是相关代码:

html部分

<view style="visibility: hidden;">
	<canvas canvas-id="shareCanvas" class="canvas" v-if="isShowCav"
:style="{height:canvasHeight+'rpx',width:canvasWidth+'rpx'}">
	</canvas>
</view>
		
<view class="canvasImage">
	<text>下图为您的专属小程序码</text>
	<image :show-menu-by-longpress="true" style="" :src="pageData.first_post_img" mode=""></image>
	<text>长按保存图片或发送给你的好友</text>
</view>
:show-menu-by-longpress="true"是打开长按图片的菜单

JS部分

为了邀请码更快的展示,这里用了将网络图片转换为本地图片的方法:

//获取图片的基本信息,即将网络图片转成本地图片,
			getImageInfo(src) {
				return new Promise((resolve, reject) => {
					uni.getImageInfo({
						src,
						success: (res) => resolve(res),
						fail: (res) => reject(res)
					})
				});
			},

接下来就是canvas画图:

exportPost() {
	let that = this

	uni.showLoading({
		title: '海报生成中'
	})
	//image是画布的底图
    let image = 'https://XXXXXXX.png'
	//获取系统的基本信息,为后期的画布和底图适配宽高
	uni.getSystemInfo({
		success: function(res) {
			that.windowObj = res
			that.windowObj.ratio = that.windowObj.windowWidth / 750 
//因为小程序是用rpx单位,为了是后期合成的图片更好是适应各个手机屏幕的尺寸,这里先计算出一个比率,后面除以这个比率就可以对各个手机尺寸进行适配了
			that.canvasWidth =1065 
//*that.windowObj.ratio*2 //that.windowObj.windowWidth/that.windowObj.ratio 
//设置画布的宽高
			that.canvasHeight =1350 //*that.windowObj.ratio*2 //that.windowObj.windowHeight/that.windowObj.ratio

Promise.all([that.getImageInfo(image), that.getImageInfo(that.pageData.codePng), that
							.getImageInfo(that.userHeadImg)
						]).then(res => {
							console.log(1111,res)
							let arr = [{
									width: res[0].width,
									height: res[0].height
								},
								{
									width: res[1].width,
									height: res[1].height
								},
								{
									width: res[2].width,
									height: res[2].height
								}

							]
							
			that.ctx.setFillStyle('white'); //填充白色
		    that.ctx.fillRect(0, 0, 244, 457); //画出矩形白色背景
			that.ctx.save()
						
			that.ctx.drawImage(res[0].path, 0, 0, 1065 * that.windowObj.ratio, 1350 *
								that.windowObj.ratio);
	        that.ctx.drawImage(res[1].path, (arr[1].width * that.windowObj.ratio) + 60,
								(arr[1].height * that.windowObj.ratio) + 190, res[1].width / 2,res[1].height / 2);
							
_canvas.drawCircular(that.ctx, res[2].path, 450 * that.windowObj.ratio,
170 * that.windowObj.ratio, 200 * that.windowObj.ratio, 200 * that.windowObj.ratio) //绘制圆形头像
	that.ctx.setFontSize(45 * that.windowObj.ratio)
	that.ctx.setFillStyle("#000")
		
	that.ctx.textAlign = 'center'; //文字水平居中
	that.ctx.fillText(that.strWXNickName, (1090 / 2) * that.windowObj.ratio,
			430 * that.windowObj.ratio)
	that.ctx.save()

	that.ctx.draw(false, function() {
								uni.canvasToTempFilePath({
									x: 0,
									y: 0,
									width: 1065,
									height: 1350,
									destWidth: 1065, //这里乘以2是为了保证合成图片的清晰度
									destHeight: 1350,
									canvasId: 'shareCanvas',
									fileType: 'jpg', //设置导出图片的后缀名
									success: function(res) {
										that.pageData.first_post_img = res
											.tempFilePath
										that.isShowCav = false;
										uni.hideLoading();
									}
								})
							});
						})
					}
				})
			},

这里的_canvas是自己引用的一个关于canvas的常用方法,在这里分享给大家

/**
 * 绘制矩形
 * 参数:cxt、x坐标、y坐标、宽度、高度、圆角、颜色
 */
function fillRoundRect(cxt, x, y, width, height, radius, /*optional*/ fillColor) {
	console.log(cxt, 'fillRoundRect')
	//圆的直径必然要小于矩形的宽高
	if (2 * radius > width || 2 * radius > height) {
		return false;
	}
	cxt.save();
	cxt.translate(x, y);
	//绘制圆角矩形的各个边
	drawRoundRectPath(cxt, width, height, radius);
	cxt.fillStyle = fillColor || '#000'; //若是给定了值就用给定的值否则给予默认值
	cxt.fill();
	cxt.restore();
}

function drawRoundRect(ctx, r, x, y, w, h, img) {
	ctx.save();
	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.clip();
	ctx.drawImage(img, x, y, w, h);
	ctx.restore(); // 返回上一状态
}

function drawRoundRectPath(cxt, width, height, radius) {
	cxt.beginPath(0);
	//从右下角顺时针绘制,弧度从0到1/2PI
	cxt.arc(width - radius, height - radius, radius, 0, Math.PI / 2);
	//矩形下边线
	cxt.lineTo(radius, height);
	//左下角圆弧,弧度从1/2PI到PI
	cxt.arc(radius, height - radius, radius, Math.PI / 2, Math.PI);
	//矩形左边线
	cxt.lineTo(0, radius);
	//左上角圆弧,弧度从PI到3/2PI
	cxt.arc(radius, radius, radius, Math.PI, (Math.PI * 3) / 2);
	//上边线
	cxt.lineTo(width - radius, 0);
	//右上角圆弧
	cxt.arc(width - radius, radius, radius, (Math.PI * 3) / 2, Math.PI * 2);
	//右边线
	cxt.lineTo(width, height - radius);
	cxt.closePath();
}
//加载图片
function getImageInfo(image) {
	return new Promise((req, rj) => {
		uni.getImageInfo({
			src: image,
			success: function(res) {
				console.log(res, 'getImageInfo图片')
				req(res)
			},
		});
	})
}

/**
 * 绘制圆形头像
 * 参数:cxt、图标路径path、x坐标、y坐标、宽度、高度
 */
function drawCircular(ctx, url, x, y, width, height) {
	//画圆形头像
	var avatarurl_width = width;
	var avatarurl_heigth = height;
	var avatarurl_x = x;
	var avatarurl_y = y;
	ctx.save();
	ctx.beginPath();
	ctx.arc(avatarurl_width / 2 + avatarurl_x, avatarurl_heigth / 2 + avatarurl_y, avatarurl_width / 2, 0, Math.PI * 2,
		false);
	ctx.clip();
	ctx.drawImage(url, avatarurl_x, avatarurl_y, avatarurl_width, avatarurl_heigth);
	ctx.restore();
}

/*
 * 绘制图片cover
 * t:cxt;
 * e:图片属性(通过getImageInfo获取)
 * i:绘制图片宽度
 * a:绘制图片高度
 * s:x坐标
 * o:y坐标
 */
function drawImgCover(t, e, i, a, s, o) {
	console.log(e, 'drawImgCover')
	if (e.width / e.height >= i / a) {
		var r = e.height,
			n = Math.ceil(i / a * r);
		t.drawImage(e.path, (e.width - n) / 2, 0, n, e.height, s, o, i, a)
	} else {
		var c = e.width,
			l = Math.ceil(a / i * c);
		t.drawImage(e.path, 0, (e.height - l) / 2, e.width, l, s, o, i, a)
	}
}

/*
 * 文本自定义换行
 * family = " 'PingFang SC',tahoma,arial,'helvetica neue','hiragino sans gb','microsoft yahei',sans-serif";
 * var options = {
				font:"22px" + family,  字体大小
				ctx:ctx,          uni.createCanvasContext('firstCanvas')
				word:"文字",      文字
				maxWidth:750,     最大宽度
				maxLine:2,        最大行数
				x:100,            x坐标
				y:100,            y坐标
				l_h:40            行高
			}
 * callback 自定义函数
 */
function dealWords(options) {
	options.ctx.font = options.font; //设置字体
	
	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) * options
							.l_h); //(j+1)*18这是每一行的高度        
					} else {
						options.ctx.fillText(nowStr.slice(0, m), options.x, options.y + (j + 1) * options.l_h);
					}
					endPos += m; //下次截断点
					break;
				}
			}
		} else { //如果当前的字符串宽度小于最大宽度就直接输出
			options.ctx.fillText(nowStr.slice(0), options.x, options.y + (j + 1) * options.l_h);
		}
	}
}
/*
 * 绘制圆角按钮
 * ctx:createCanvasContext
 * color:背景颜色;
 * x:x坐标
 * y:y坐标
 * width:宽
 * height:高
 * radius:圆角
 * text:文字
 * fontColor:文字颜色
 * textAlign: left/center/right
 */
export const drawButton = function(ctx, color, x, y, width, height, radius, text, fontColor, textAlign) {
	//分为4条直线4个圆角绘制
	ctx.beginPath();
	ctx.fillStyle = color;
	ctx.moveTo(x + radius, y);
	ctx.lineTo(x + width - radius, y);
	ctx.arc(x + width - radius, y + radius, radius, Math.PI * 3 / 2, Math.PI * 2);
	ctx.lineTo(x + width, y + height - radius);
	ctx.arc(x + width - radius, y + height - radius, radius, Math.PI, Math.PI / 2);
	ctx.lineTo(x + radius, y + height);
	ctx.arc(x + radius, y + height - radius, radius, Math.PI / 2, Math.PI);
	ctx.lineTo(x, y + radius);
	ctx.arc(x + radius, y + radius, radius, Math.PI, Math.PI * 3 / 2);
	ctx.fill();
	ctx.closePath();

	ctx.beginPath();
	ctx.fillStyle = fontColor;
	// ctx.font = 'normal bold 12px sans-serif';
	ctx.textAlign = textAlign;
	ctx.textBaseline = "middle";
	ctx.fillText(text, x + width / 2, y + height / 2);
}

export default {
	fillRoundRect: fillRoundRect, //绘制矩形
	getImageInfo: getImageInfo, //加载图片
	drawCircular: drawCircular, //绘制圆形头像
	drawImgCover: drawImgCover, //绘制图片cover
	dealWords: dealWords, //文本自定义换行
	drawButton: drawButton, //绘制圆角按钮
	drawRoundRect:drawRoundRect
}

然后自己调一调样式就可以了!!!!

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

小程序canvas绘制邀请码 的相关文章

  • python opencv 调用摄像头失败问题的解决 Windows

    省流 内含 Python Opencv 双目相机拍照代码 手动 or 自动 可自取 如果你的 cv2 VideoCapture 函数卡住但不报错 打开 Windows 相机 应用可以正常看到摄像头画面 且能够正常用 cv2 imshow 打
  • python flask api接口开发编程

    使用 Python 和 Flask 设计 RESTful API 近些年来 REST REpresentational State Transfer 已经变成了 web services 和 web APIs 的标配 在本文中我将向你展示如
  • 简述同步和异步的区别

    同步是阻塞模式 异步是非阻塞模式 同步就是指一个进程在执行某个请求的时候 若该请求需要一段时间才能返 回信息 那么这个进程将会一直等待下去 直到收到返回信息才继续执行下去 异步是指进程不需要一直等下去 而是继续执行下面的操作 不管其他进程的
  • do-while(0)语句到底有什么用?

    前言 在一个群里面看到一个人问 do while 0 语句有什么用 do while 0 这个程序最终结果不应该就是程序只跑一次 那么写和不写有什么区别呢 do while 0 在复杂宏定义上的优点 为什么需要复杂宏 1 在讲解do whi
  • 反射的补充

    反射可以绕过编译阶段为集合添加数据 反射是作用在运行时的技术 此时集合的泛型将不能产生约束了 此时可以为集合存入其他任意类型的元素 泛型只是在编译阶段可以约束集合只能操作某种数据类型 在编译成Class文件进入运行阶段时 其真实类型都是Ar
  • 数据结构与算法笔记:计算思维之经典农夫过河问题C++实现

    农夫 羊 狼 菜的过河问题 问题描述 角色 农夫 羊 狼 菜 条件1 船很小 只能装下农夫和其他一个角色 条件2 无人看管 羊吃菜 狼吃羊 问 如何让其他三种角色被农夫平安带着过河 相关分析 我们可以先用人脑尝试一下相关渡河策略 1 先渡狼

随机推荐

  • 基于 itemCF (item collaborative filtering) 推荐(基于物品的协同过滤算法)的理解

    推荐系统 一般是用于电商 广告 内容 信息流等推荐平台 以挖掘数据的最大价值 可以提升用户粘性和转化率 而本文提及到的基于内容的协同过滤算法就是一个经典的算法 基本思想 首先 什么是协同呢 协同在这里指的就是 用集体的智慧来为个体过滤出他需
  • C++程序员应了解的那些事(117)~进程、线程、协程

    相关博文 程序员应了解的那些事 111 进程 线程及堆栈关系 线程堆栈 so what的博客 CSDN博客 概念与区分 1 进程 进程是程序一次动态执行的过程 是程序运行的基本单位 每个进程都有自己的独立内存空间 不同进程通过进程间通信来通
  • angular路由传参和获取路由参数的方法

    1 首先是需要导入的模块 import Router from angular router 路由传参用到 import ActivatedRoute Params from angular router 获取路由传参用到 2 第二步 注入
  • 3DMAX、MAYA、C4D区别

    一 3Dmax 优势 1 3DMAX主要面向建筑动画 bai建筑漫游和室内设计 用于室du内和室外渲染的基本建zhi模 材料分配 映射使用和照明创建的图形文件 2 3DMAX软件的应用主要是动画制作 游戏动画制作 建筑效果图 建筑动画等 3
  • STL——list详解

    一 list基本使用 1 1 初始化 在C 11之前 std list容器没有提供初始化列表的构造函数 因此需要使用push back或push front函数向列表中添加元素 以下是一些常见的std list初始化方式 使用默认构造函数创
  • javascript对任意颜色获取更亮或更暗的颜色值

    预处理CSS 比如Sass和less可以通过设定一个特定值 让任何颜色变得更亮或者更暗 但是在javascript中却没有这种方法 下面这个方法能在javascript中得到一个更亮或者更暗的值 通过一个给定的十六进制颜色值 比如 F06D
  • 【数据分析】基于RFM模型的线上零售中的客户细分(二):RFM模型实战

    基于RFM模型的线上零售中的客户细分 二 摘要 在上一篇博客 基于RFM模型的线上零售中的客户细分 一 客户细分 中 我们了解了什么是客户细分 这篇博客将会结合具体的商业实例介绍同期群分析 RFM模型 并利用K Means聚类算法在RFM模
  • 【已解决】XAMPP无法启动mysql

    最近在学习安卓开发 为了免于自己搭服务器 选择连接到XAMPP的mysql数据库 在这贴出自己遇到的一些问题 It seems that the port 3306 is already in use aer you sure you wa
  • ubuntu系统安装Anaconda与使用入门

    一 什么是Anaconda Anaconda是一个开源的Python发行版本 包含了conda Python等180多个科学包及其依赖项 可以用于包管理器和环境管理 比如A项目中用了Python2 而B项目使用Python3 而同时安装两个
  • Pygame实战:Python开挂版无敌小恐龙【源码免费领】

    导语 hi 大家好呀 你们还记得 很久很久以前 那只谷歌断网之后的
  • 通俗解释卡尔曼滤波

    汽车位置p和速度v例子 有点矩阵 https blog csdn net codesamer article details 81191487 飞机速度和位置 跟上面差不多 但是无矩阵 https blog csdn net varysha
  • nexus 搭建maven私服

    环境是 nexus 2 7 0 maven 3 1 1 jdk 1 7 45 CentOs 6 2 一 首先从首先从 http nexus sonatype rog downloads 下载最新版的Nexus 目前最新的版本是 nexus
  • Docker学习(23)——Docker 三剑客之 Docker Swarm集群(图形化界面管理swarm集群、添加服务等等,更方便)

    搭建过程如下 这个是基于上一片篇文章写的 1 在server1上面清空之前的所有的web服务和监控服务 我们接下来使用更加牛逼的图形化管理界面 比命令 文件的部署方式简单多了 2 可以看到server2 server3 server4上面的
  • Android减小Apk包大小的常用方法

    我们之所以要减小apk的大小 一方面是为了节省用户手机的内存 另一方面是为了节省用户在App安装和版本升级时的流量 直接减小apk文件大小的方法 1 使用图片压缩工具 目前常用的工具是 ImageOptim 压缩效果很好 使用默认配置即可
  • js 时分秒 转换为 秒

    p p
  • HTML+CSS小实战案例

    HTML CSS小实战案例 登录界面的美化 综合最近所学进行练习 网页设计先布局 搭建好大框架 然后进行填充 完成页面布局 1 2 3 4 5
  • GitHub Star超3.3K的超实用AI工具,涵盖OCR、目标检测、NLP、语音合成多个方向

    点击左上方蓝字关注我们 今天为大家推荐一个相当牛的项目 本周暴涨1300 Star 厚着脸皮大胆预判 这个项目肯定能更火 未来Star数应该可以到10k甚至20k 着急的 可以Github直接去看源码 传送门 https github co
  • 互联网上年入10万的新玩法?

    这句话说的有道理 不要用战术上的勤奋掩盖战略上的懒惰 战略是一个宏大的全局框架 总体构思 战术是微观层面的具体细节 执行步骤 做好每日复盘才能及时调整方向 完善正确的战略决策 不要闭门造车 多结交有价值的人脉圈子 经年累月耳濡目染就会变得和
  • OpenSea上如何创建自己的NFT(Polygon)

    发现 收藏和销售非凡的艺术品NFT OpenSea 是世界上第一个也是最大的 NFT 市场 一起来了解下如何通过Polygon网络 创建自己喜爱的NFT艺术品并进行收藏和交易 Polygon网络解决了ETH网络高昂的GAS费用和拥堵问题 使
  • 小程序canvas绘制邀请码

    针对小程序邀请好友功能 可以下载当前的海报图 分享给好友 好友通过扫描二维码跳转至小程序 但是邀请好友 要根据当前登录者的信息去生成二维码 目的是把邀请到的好友绑定到该用户下 所以会将二维码嵌入背景海报中 合成一张图后 生成一个临时地址 再