uniapp H5生成画布,插入网络图片。下载画布

news2024/10/6 6:04:14

因为网络图片不能直接使用ctx.drawImage()插入。得使用uni.getImageInfo()方法下载后插入。
但是当画布中存在多张网络图片时,必须等待uni.getImageInfo()下载完成后才行。这样得下载套下载。太过于繁琐。所以定义了一个递归下载方法。同时避免下载图片异步,画布不显示的结果。

 

一、引用函数

/**
 * canvas文本自动换行,注意调用前要设置字体,例如: ctx.font = '12px Arial'
 * @param {*} ctx CanvasRenderingContext2D
 * @param {*} text  文本
 * @param {*} x 
 * @param {*} y 
 * @param {*} lw 所占宽度
 * @param {*} lh 行高
 * return 绘制文本所需的高度
 */
const fillTextLineBreak = (ctx, text, x, y, lw, lh, color = '#000', font = '14') => {
	var i = 0;
	var n = 0;
	var r = -1;
	var initHeight = 0;
	ctx.font = "" + font + "px Arial"; //字体大小
	ctx.fillStyle = color; //字体颜色
	while (i < text.length) {
		while (ctx.measureText(text.substring(n, i)).width < lw && i < text.length) {
			i++
		}
		r++
		ctx.fillText(text.substring(n, i), x, y + lh * r)
		n = i
	}
	initHeight = lh * r;
	wx.setStorageSync('initHeight', initHeight);
}


/**
 * 自定义函数roundRect
 * 画圆弧
 * ctx >> 画布
 *bg_x 图片的x坐标
 *bg_y 图片的y坐标
 *bg_w 图片宽度
 *bg_h 图片高度
 *bg_r 图片圆角
 *
 */
function roundRect(ctx, img, bg_x, bg_y, bg_w, bg_h, bg_r) {
	// 开始绘制
	ctx.save();
	ctx.beginPath();
	ctx.arc(bg_x + bg_r, bg_y + bg_r, bg_r, Math.PI, Math.PI * 1.5);
	ctx.arc(bg_x + bg_w - bg_r, bg_y + bg_r, bg_r, Math.PI * 1.5, Math.PI * 2);
	ctx.arc(bg_x + bg_w - bg_r, bg_y + bg_h - bg_r, bg_r, 0, Math.PI * 0.5);
	ctx.arc(bg_x + bg_r, bg_y + bg_h - bg_r, bg_r, Math.PI * 0.5, Math.PI);
	ctx.clip();
	ctx.drawImage(img, bg_x, bg_y, bg_w, bg_h);
	// 恢复之前保存的绘图上下文
	ctx.restore();
}


/*
 * 画布网络图片预处理
 */
function canvasImage(that, Datas = {}, callback = null) {
	var i = Datas.i ? Datas.i : 0;
	var callback_Datas = Datas.callback_Datas ? Datas.callback_Datas : [];
	var data = Datas.data ? Datas.data : [];
	uni.getImageInfo({
		src: data[i],
		success(res) {
			i++;
			callback_Datas.push(res.path)
			if (i == data.length) {
				//回调函数
				if (callback) {
					callback(that, callback_Datas);
					return;
				}
			} else {
                //递归执行下一个上传
				canvasImage(that, {
					i,
					callback_Datas,
					data,
				}, callback);
			}
		},
		fail(e) {
			wx.hideLoading();
			//关闭画布弹窗
			that.posterHideCanvas();
			setTimeout(function() {
				wx.showToast({
					title: '生成失败,稍后再试',
					icon: 'none',
				})
			}, 0)
		}
	});
}

 二、index.vue

<view v-show="posterDatas.hidden" @touchmove="posterTouchMove" class="canvasMain flex center">
			<view class="box flex center column">
				<canvas :canvas-id="canvasId" :style="canvasStyle" class="canvas"></canvas>
				<button v-if="posterDatas.buttonType==1" class="btn" @click="posterDownImage">点击保存图片到相册</button>
				<button v-else-if="posterDatas.buttonType==2" class="btn">已保存到相册,快去分享吧</button>
				<button v-else-if="posterDatas.buttonType==3" class="btn" open-type="openSetting"
					bindopensetting="posterOpenSetting">进入设置页,开启“保存到相册”</button>
				<text class="iconfont icon-x" @click="posterHideCanvas"></text>
			</view>
		</view>

<style>
/* 海报 */
.canvasMain {
  position: fixed;
  left: 0;
  top: 0;
  width: 100%;
  height: 100%;
  background-color: rgba(0, 0, 0, 0.6);
  z-index: 9999;
}

.canvasMain.hidden {
  top: 100%;
  left: 100%;
}

.canvasMain .box {
  position: relative;
}

.canvasMain .box .canvas {
  margin: 0;
}

.canvasMain .box .btn {
  height: 40px;
  width: 280px;
  background-color: rgba(0, 0, 0, 0.3);
  border-radius: 40px;
  color: #fff;
  font-size: 15px;
}

.canvasMain .box .btn {
  margin: 10px 0;
  padding-left: 0;
  padding-right: 0;
}

.canvasMain .box .iconfont {
  font-size: 46rpx;
  color: #fff;
}
</style>

三、index.js

	data() {
		return {
			posterDatas: {
				width: 285, //画布宽度
				height: 406, //画布高度
				buttonType: 1,
				hidden: false, // 是否隐藏海报弹窗
				success: false, // 是否成功生成过海报
			},
			canvasId: 'firstCanvas',
			canvasStyle: 'width: 285px; height: 406px;', // 根据实际需要设置 canvas 的宽高
		};
	},
    
    	//海报生成配置
		posterSetCanvas() {
			var that = this
			var posterDatas = that.posterDatas;
			var tempConfig = that.tempConfig;
			//展示海报弹窗
			that.posterDatas.hidden = true;
			util.showLoading('生成中');
			var userInfo = wx.getStorageSync('userInfo') || {};

			var Datas = {};
			Datas.i = 0;
			Datas.callback_Datas = [];
			Datas.data = [];
			Datas.data[0] = userInfo.touimg; //头像
			Datas.data[1] = app.globalData.swtCircle + "/mp_ewm_v2.php?act=getwxacode&tjrhao=" + (userInfo
				.tjrhao || '') + "&url=pages/home/home"; //小程序码
			util.canvasImage(that, Datas, function(that, canvasImage_arr) {
				//要延时执行的代码
				setTimeout(function() {
					//预处理画布网络地址图片
					var ctx = uni.createCanvasContext(that.canvasId, that);
					// 清除背景
					//ctx.clearRect(0, 0, posterDatas.width, posterDatas.height);
					// 绘制背景
					// ctx.fillStyle = "#fff";
					// ctx.fillRect(0, 0, posterDatas.width, posterDatas.height);
					var bgImg = '/static/images/yao_bj.png';
					// 绘制背景图
					ctx.drawImage(bgImg, 0, 0, posterDatas.width, posterDatas.height);

					//简介
					util.fillTextLineBreak(ctx, "邀请您使用" + tempConfig.appMain.name + "小程序", 100, 81, 150,
						20, '#fff',
						13);
					//标题文字
					ctx.font = "bold 18px PingFang SC";
					ctx.fillStyle = "#fff";
					ctx.textAlign = "start";
					ctx.fillText(userInfo.nickName_hai, 100, 60);

					util.roundRect(ctx, canvasImage_arr[0], 30, 35, 56, 56, 28);

					ctx.font = "bold 18px PingFang SC";
					ctx.fillStyle = "#0D7239";
					ctx.textAlign = "start";
					ctx.fillText('分享有礼 荐者有份', 70, 170);

					ctx.drawImage(canvasImage_arr[1], 65, 200, 160, 160);
					ctx.draw();
					wx.hideLoading();

				}, 200)
			});
		},

		//海报下载图片
		posterDownImage: function() {
			var that = this
			util.showLoading('保存中');
			var posterDatas = that.posterDatas
			uni.canvasToTempFilePath({
				canvasId: "firstCanvas",
				success(res) {
					console.log(res)
					wx.showToast({
						icon: 'none',
						title: '已保存到相册,快去分享吧',
					})
					posterDatas["buttonType"] = 2;
					that.posterDatas = posterDatas;

					// 在 h5 中,res.tempFilePath 返回的是 base64 类型要处理,通过 a 标签的形式下载
					var arr = res.tempFilePath.split(',');
					var bytes = atob(arr[1]);
					let ab = new ArrayBuffer(bytes.length);
					let ia = new Uint8Array(ab);
					for (let i = 0; i < bytes.length; i++) {
						ia[i] = bytes.charCodeAt(i);
					}
					var blob = new Blob([ab], {
						type: 'application/octet-stream'
					});
					var url = URL.createObjectURL(blob);
					var a = document.createElement('a');
					a.href = url;
					a.download = new Date().valueOf() + ".png";
					var e = document.createEvent('MouseEvents');
					e.initMouseEvent('click', true, false, window, 0, 0, 0, 0, 0, false, false, false,
						false, 0, null);
					a.dispatchEvent(e);
					URL.revokeObjectURL(url);
				},
				fail(e) {
					console.log(e, "fail");
					util.showToast('保存失败,稍后再试”', 'none');
					that.posterHideCanvas();
				}
			})
		},

		//海报隐藏弹窗
		posterHideCanvas: function() {
			var that = this;
			that.posterDatas.buttonType = 1;
			that.posterDatas.hidden = false;
		},

		//海报弹窗禁止屏幕滚动
		posterTouchMove: function() {
			//在蒙层加上 catchtouchmove 事件
			//这里什么都不要放
		},

四、最终结果

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1004533.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【数据结构】长篇详解堆,堆的向上/向下调整算法,堆排序及TopK问题

文章目录 堆的概念性质图解 向上调整算法算法分析代码整体实现 向下调整算法算法分析整体代码实现 堆的接口实现初始化堆销毁堆插入元素删除元素打印元素判断是否为空取首元素实现堆 堆排序创建堆调整堆整合步骤 TopK问题 堆的概念 堆就是将一组数据所有元素按完全二叉树的顺序…

四川玖璨电子商务有限公司:新媒体视频运营

新媒体视频运营是随着互联网技术的发展而兴起的一种新型媒体运营方式。它通过制作、发布和推广优质视频内容&#xff0c;以吸引受众眼球&#xff0c;提升品牌知名度和影响力。四川玖璨电商小编在此次新媒体视频运营实验中&#xff0c;我们对新媒体视频运营的关键要素进行了探索…

大数据精准营销适合什么行业,面临哪些问题?

大数据营销适合的行业还是非常多的&#xff0c;毕竟现在大部分的企业都是通过网络方式来获得客户的&#xff0c;只要同领域有网站&#xff0c;而且他们存在竞价或者是优化&#xff0c;或者是使用了相关的软件&#xff0c;这种情况下都是完全可以运用的。比较常见的行业有金融行…

高端知识竞赛中选手台桌设计方案和配套软件

高端知识竞赛选手台桌用于知识竞赛现场选手台&#xff0c;集成了知识竞赛软硬件设备&#xff0c;包括台前计分一体机或LED屏、抢答按钮等&#xff0c;和天纵竞赛软件配合使用&#xff0c;实现高端竞赛的计分需要。 知识竞赛选手台桌前计分屏可以显示丰富的内容&#xff0c;包括…

(JavaEE)多线程带来的的风险-线程安全 (第一部)

前言&#xff1a;线程安全是整个多线程中&#xff0c;最为复杂的部分&#xff0c;也是最重要的部分。 目录 什么是线程安全问题&#xff1f; 线程不安全的原因 ⁜⁜总结 &#xff1a;线程安全问题的原因 ⁜⁜ 解决方法1 ——加锁 synchronized &#xff08;监视器锁monitor…

客户画像的作用是什么?

1、深度挖掘 客户画像包括客户的基本信息和个人行为数据&#xff0c;这些都可以作为企业成员和客户沟通的基础&#xff0c;且在此基础上可以更好地共情并深度挖掘客户真正想要什么。 2、分层精细运营 根据客户画像能充分了解客户的需求&#xff0c;再结合产品属性和企业文化…

【memmove函数的功能介绍及模拟实现】

memmove函数的功能介绍及模拟实现✍️ 1.memmove函数的功能介绍&#x1f9d0; 1.1函数结构&#x1f575;️ void * memmove ( void * destination, const void * source, size_t num );1.2 功能介绍&#x1f92f; 根据cplusplus网站上对memmove函数的介绍&#xff1a; 它的…

全栈测试平台RunnerGo你了解嘛

在当今这个数字化时代&#xff0c;应用程序的性能至关重要。一款可靠的性能测试工具&#xff0c;能够为企业带来无数的好处。最近&#xff0c;一款名为RunnerGo的开源性能测试工具备受瞩目。本文将详细介绍RunnerGo的特点、优势以及如何解决性能测试中的痛点。 RunnerGo产品介绍…

02-Redis持久化

上一篇&#xff1a;01-Redis核心数据结构与高性能原理 1.RDB快照&#xff08;snapshot&#xff09; 在默认情况下&#xff0c; Redis 将内存数据库快照保存在名字为 dump.rdb 的二进制文件中。 你可以对 Redis 进行设置&#xff0c; 让它在“ N 秒内数据集至少有 M 个改动”…

MemJam: A false Dependency attack against constant-time crypto implementations【存储缓存】

作者&#xff1a;A. Moghimi, J. Wichelmann, T. Eisenbarth, and B. Sunar. 发布&#xff1a;International Journal of Parallel Programming 时间&#xff1a;Aug 2019. 笔记&#xff1a; 缓存定时攻击 1、攻击原理 共享缓存存在定时侧信道的风险&#xff08;例如在处理…

C++信息学奥赛1168:大整数加法

#include <iostream> #include <string> #include <cstring> using namespace std;char ArrString[205], BrrString[205];// 自定义的取最大值函数 int max(int a, int b){if(a > b){return a;}else{return b;} }int main(){int len 0;cin >> ArrS…

C++11 新特性 ⑤ | 仿函数与 lambda 表达式

目录 1、引言 2、仿函数 3、lambda表达式 3.1、lambda表达式的一般形式 3.2、返回类型说明 3.3、捕获列表的规则 3.4、可以捕获哪些变量 3.5、lambda表达式给编程带来的便利 VC常用功能开发汇总&#xff08;专栏文章列表&#xff0c;欢迎订阅&#xff0c;持续更新...&a…

开源大模型ChatGLM2-6B 2. 跟着LangChain参考文档搭建LLM+知识库问答系统

0. 环境 租用了1台GPU服务器&#xff0c;系统 ubuntu20&#xff0c;Tesla V100-16GB &#xff08;GPU服务器已经关机结束租赁了&#xff09; SSH地址&#xff1a;* 端口&#xff1a;17520 SSH账户&#xff1a;root 密码&#xff1a;Jaere7pa 内网&#xff1a; 3389 &#xf…

【Linux】自制shell

本期我们利用之前学过的知识&#xff0c;写一个shell命令行程序 目录 一、初始代码 二、使用户输入的ls指令带有颜色分类 三、解决cd指令后用户所在路径不变化问题 3.1 chdir函数 四、关于环境变量的问题 一、初始代码 #include<stdio.h> #include<unistd.h…

第三节:在WORD为应用主窗口下关闭EXCEL的操作(2)

【分享成果&#xff0c;随喜正能量】凡事好坏&#xff0c;多半自作自受&#xff0c;既不是神为我们安排&#xff0c;也不是天意偏私袒护。业力之前&#xff0c;机会均等&#xff0c;毫无特殊例外&#xff1b;好坏与否&#xff0c;端看自己是否能应机把握&#xff0c;随缘得度。…

Pyspark案例综合(数据计算)

数据计算 map方法 map算子 map算子&#xff08;成员方法&#xff09;接受一个处理函数&#xff0c;可用lambda快速编写&#xff0c;对RDD内的元素一一处理&#xff0c;返回RDD对象 链式调用 对于返回值是新的RDD的算子&#xff0c;可以通过链式调用的方式多次调用算子 &q…

Windows Server操作系统概述

文章目录 一、计算机系统的层次结构二、五大基本功能1. 处理器管理2. 储蓄器管理3. 文件管理4. 设备管理5. 作业管理 三、应用场景四、发展历程1. Unix概述相关版本应用场景 2. Linux概述相关版本应用场景 3. windows概述普通版本服务器版本 首先可以看下思维导图&#xff0c;以…

Win10 NVIDIA Incompatible

Win10 NVIDIA 不兼容 https://www.nvidia.cn/Download/index.aspx?langcn https://www.nvidia.com/Download/Find.aspx?langen-us win10 version 1803

Python安装与环境变量配置傻瓜式教程(2023年9月)

给我家憨憨写的python教程 ——雁丘 Python的环境变量可以在安装包勾选自动配置&#xff0c;故相比Java相比简单不少 Python安装与环境变量配置傻瓜式教程&#xff08;2023年9月&#xff09; 一 Python的下载二 Python的安装三 手动配置环境变量四 检验环境变量 一 Python的下…

强化历程7-排序算法(2023.9.12)

此笔记学习图片来自于如下网址 1https://www.west999.com/info/html/chengxusheji/Javajishu/20190217/4612849.html 文章目录 强化历程7-排序算法1 冒泡排序(交换排序)2 选择排序3 直接插入排序4 希尔排序5 归并排序6 快速排序7 堆排序8 计数排序 强化历程7-排序算法 1 冒泡排…