微信小程序-生成canvas图片并保存到手机相册
wxml页面
<button class="rightbtn bottomBtnCss" catch:tap="canvasImg"><image src='{{imgUrl}}/images/mine/jspj-icon.png' class="restNumImg"></image><text class="btnText">生成图片</text></button>
<!-- 生成图片弹框 -->
<view class="wx-dialog_wrapper " wx:if="{{isShowCanvas}}" ><view class="wx-dialog wx-dialogwidth80"><view class="wx-dialog_body"><view class="canvasWrap"><canvas type="2d" id='posterCanvas' style="width: 100%;height: 1000rpx;"></canvas></view><button class="rightbtn bottomBtnCss" catch:tap="saveImg"><image src='{{imgUrl}}/images/mine/jspj-icon.png' class="restNumImg"></image><text class="btnText">保存图片</text></button></view></view>
</view>
wxss页面
.wx-dialogwidth80{width:80%;
}
#posterCanvas {margin: 0 auto;
}
.canvasWrap {
margin: 10px auto;
text-align: center;
}
js代码
const app = getApp()
Page({/*** 页面的初始数据*/data: {imgUrl: app.globalData.imgUrl,//线上图片路径totalCnt: '',isSaveCanvas: false,},/*** 生命周期函数--监听页面加载*/onLoad(options) {let totalCnt = wx.getStorageSync('totalCnt')this.setData({totalCnt: totalCnt || '0.00'})},// 重新计算restClick() {wx.navigateTo({url: '../../index'})},/*** 用户点击右上角分享*/onShareAppMessage() {},// 关闭showVipDialogClose() {this.setData({isShowCanvas: false})},canvasImg() {this.setData({isShowCanvas: true})// wx.showLoading({// title: '海报生成中...',// })let _this = this//选取画板const query = wx.createSelectorQuery()query.select('#posterCanvas').fields({node: true,size: true}).exec(async (res) => {const canvas = res[0].node;const ctx = canvas.getContext('2d');const dpr = wx.getSystemInfoSync().pixelRatio //手机分辨率 为了使保存到相册的图片清晰canvas.width = res[0].width * dprcanvas.height = res[0].height * dprconsole.log('dpr', dpr);ctx.clearRect(0, 0, 320, 410); //清空画板ctx.fillStyle = '#fff';ctx.fillRect(0, 0, 320, 410);// 1.背景图const image = canvas.createImage();image.src = this.data.imgUrl + "/images/carbonEmissionImages/排放总量背景.png";;let bgImg = await new Promise((resolve, reject) => {image.onload = () => {resolve(image)}image.onerror = (e) => {reject(e)}});ctx.drawImage(bgImg, 0, 0, canvas.width, canvas.height);// 2.头部文字 在背景图上作画// 设置文字样式ctx.font = "700 36px sans-serif";ctx.fillStyle = "#fff";ctx.textAlign = "center" //居中是以文字设定的x轴( canvas.width/2)为中心点// 添加文字ctx.fillText("我在ESGPRO上测了企业碳排放总量", canvas.width / 2, 200);// 3.画中心圆图const image1 = canvas.createImage();image1.src = this.data.imgUrl + "/images/carbonEmissionImages/tco2背景.png";;let bgImgPo = await new Promise((resolve, reject) => {image1.onload = () => {resolve(image1)}image1.onerror = (e) => {reject(e)}});ctx.drawImage(bgImgPo, 0.5 * (canvas.width - 400), 0.5 * (canvas.height - 800), 400, 400);// 4.圆圈内文字 在背景图上作画// // 设置文字样式ctx.font = "700 36px sans-serif";ctx.fillStyle = '#00bf5b'; //文字颜色:默认黑色ctx.textAlign = "center"ctx.fillText(_this.data.totalCnt, canvas.width / 2, 0.5 * (canvas.height - 400)) //绘制文本// 设置文字样式ctx.font = "28px sans-serif";ctx.fillStyle = "#bdbdbd";ctx.textAlign = "center" //居中是以文字设定的x轴( canvas.width/2)为中心点// 添加文字ctx.fillText('tCO2', canvas.width / 2, 0.5 * (canvas.height - 300));// 5.小程序二维码let image2 = canvas.createImage();// image2.src = this.data.imgUrl + '/images/carbonEmissionImages/COimg.jpg'; // 引入本地图片image2.src = '../../images/COimg.jpg'; // 引入本地图片image2.onload = function () {ctx.drawImage(image2, 0.5 * (canvas.width - 300), 0.5 * (canvas.height + 400), 300, 300);// 6.添加文字// 设置文字样式ctx.font = "24px sans-serif";ctx.fillStyle = "#999999";ctx.textAlign = "center" //居中是以文字设定的x轴( canvas.width/2)为中心点// 添加文字ctx.fillText('微信扫码或搜索ESGPRO', canvas.width / 2, 0.5 * (canvas.height + 1100));ctx.font = "24px sans-serif";ctx.fillStyle = "#999999";ctx.textAlign = "center" //居中是以文字设定的x轴( canvas.width/2)为中心点// 添加文字ctx.fillText('即可免费使用碳排放计算器', canvas.width / 2, 0.5 * (canvas.height + 1200));}})},async saveImg() {let _this = this;const query = wx.createSelectorQuery();const canvasObj = await new Promise((resolve, reject) => {query.select('#posterCanvas').fields({node: true,size: true}).exec(async (res) => {resolve(res[0].node);})});wx.canvasToTempFilePath({canvas: canvasObj, //现在的写法success: (res) => {console.log(res);_this.setData({isShowCanvas: false});//保存图片wx.saveImageToPhotosAlbum({filePath: res.tempFilePath,success(res) {wx.hideToast();wx.showModal({title: '图片保存成功',content: '图片成功保存到相册了',showCancel: false,confirmText: '好哒',confirmColor: '#5096cd',success: function (res) {if (res.confirm) {console.log('用户点击确定');}}})},fail(err) {wx.hideToast()if (err.errMsg === "saveImageToPhotosAlbum:fail:auth denied" ||err.errMsg === "saveImageToPhotosAlbum:fail auth deny" ||err.errMsg === "saveImageToPhotosAlbum:fail authorize no response") {wx.showModal({title: '提示',content: '需要您授权保存相册',showCancel: false,success: res => {wx.openSetting({success(res) {if (settingdata.authSetting['scope.writePhotosAlbum']) {wx.showModal({title: '提示',content: '获取权限成功,再次点击即可保存',showCancel: false,})} else {wx.showModal({title: '提示',content: '获取权限失败,将无法保存到相册哦~',showCancel: false,})}},fail(err) {console.log("fail", err)},complete(res) {console.log("finish", res)}})}})} else if (err.errMsg === "saveImageToPhotosAlbum:fail cancel") {wx.showModal({title: '提示',content: '取消了保存图片,再次点击下载即可保存',showCancel: false,})} else {wx.showModal({title: '提示',content: err.errMsg,showCancel: false,})}}})},fail(err) {wx.showToast({title: '保存失败,稍后再试',duration: 2000,icon: 'none'});}}, this)},/*** 生命周期函数--监听页面初次渲染完成*/onReady() {},/*** 生命周期函数--监听页面显示*/onShow() {},/*** 生命周期函数--监听页面隐藏*/onHide() {},/*** 生命周期函数--监听页面卸载*/onUnload() {},/*** 页面相关事件处理函数--监听用户下拉动作*/onPullDownRefresh() {},/*** 页面上拉触底事件的处理函数*/onReachBottom() {},})
相关文章:
微信小程序-生成canvas图片并保存到手机相册
wxml页面 <button class"rightbtn bottomBtnCss" catch:tap"canvasImg"><image src{{imgUrl}}/images/mine/jspj-icon.png class"restNumImg"></image><text class"btnText">生成图片</text></but…...
设计模式8:代理模式-动态代理
上一篇:设计模式8:代理模式-静态代理 目录 如何理解“动态”这两个字?动态代理简单的代码实例一个InvocationHandler代理多个接口有动态代理,为什么还要用Cglib代理? 如何理解“动态”这两个字? “动态”…...
tcp字节传输(java)-自定义包头和数据识别
1、背景 tcp传输的时候会自动拆包,因此服务端接收的数据段可能跟客户端发送过来的数据段长度不一致,比如客户端一次发送10000个字节。但是服务端接收了两次才接收完整(例如第一次接收6000字节,第二次接收4000字节)。但…...
pyspark 系统找不到指定的路径; \Java\jdk1.8.0_172\bin\java
使用用具PyCharm 2023.2.1 1:pyspark 系统找不到指定的路径, Java not found and JAVA_HOME environment variable is not set. Install Java and set JAVA_HOME to point to the Java installation directory. 解决方法:配置正确环境变量…...
UE4 Physics Constraint Actor 实现钟摆效果
放入场景,然后将一个球体放入场景 选择小球 将小球改为Movable 选择模拟物理,并将小球移除平衡点 就实现了...
UE4/UE5 动画控制
工程下载 https://mbd.pub/o/bread/ZJ2cm5pu 蓝图控制sequence播放/倒播动画: 设置开启鼠标指针,开启鼠标事件 在场景中进行过场动画制作 设置控制事件...
Springboot整合shiro
导入依赖 <!-- 引入springboot的web项目的依赖 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency> <!-- shiro --><depende…...
阻塞/非阻塞、同步/异步(网络IO)
1.阻塞/非阻塞、同步/异步(网络IO) 【思考】典型的一次 IO 的两个阶段是什么? 数据就绪 和 数据读写 数据就绪 :根据系统 IO 操作的就绪状态 阻塞 非阻塞 数据读写 :根据应用程序和内核的交互方式 同步 异步 陈硕:在处理 IO …...
为什么大家会觉得考PMP没用?
一是在于PMP这套知识体系,是一套底层的项目管理逻辑框架,整体是比较抽象的。大家在学习工作之后,会有人告诉你很多职场的一些做事的规则,比如说对于沟通,有人就会告诉如何跟客户沟通跟同事相处等等,这其实就…...
AVR128单片机 USART通信控制发光二极管显示
一、系统方案 二、硬件设计 原理图如下: 三、单片机软件设计 1、首先是系统初始化 void port_init(void) { PORTA 0xFF; DDRA 0x00;//输入 PORTB 0xFF;//低电平 DDRB 0x00;//输入 PORTC 0xFF;//低电平 DDRC 0xFF;//输出 PORTE 0xFF; DDRE 0xfE;//输出 PO…...
为什么5G 要分离 CU 和DU?(4G分离RRU 和BBU)
在 Blog 一文中,5G--BBU RRU 如何演化到 CU DU?_5g rru_qq_38480311的博客-CSDN博客 解释了4G的RRU BBU 以及 5G CU DU AAU,主要是讲了它们分别是什么。但是没有讲清楚 为什么,此篇主要回答why。 4G 为什么分离基站为 RRU 和 BBU…...
Python中的数据输入
获取键盘输入 input语句 使用input()可以从键盘获取输入,使用一个变量来接收 print("你是谁?") name input() print(f"我知道了,你是{name}")# print("你是谁?") name input("你是谁&…...
cms系统稳定性压力测试出现TPS抖动和毛刺的性能bug【杭州多测师_王sir】
一、并发线程数100,分10个阶梯,60秒加载时间,运行1小时进行压测,到10分钟就出现如下 二、通过jstat -gcutil 16689 1000进行监控...
【UE】材质描边、外发光、轮廓线
原教学视频链接: ue4 材质描边、外发光、轮廓线_哔哩哔哩_bilibili 步骤 1. 首先新建一个材质,这里命名为“Mat_outLine” 在此基础上创建一个材质实例 2. 在视口中添加一个后期处理体积 设置后期处理体积为无限范围 点击添加一个数组 选择“资产引用”…...
百模大战,打响AI应用生态的新赛点
点击关注 文|郝鑫 黄小艺,编|刘雨琦 “宇宙中心”五道口,又泛起了昔日的光芒。 十字路口一角的华清嘉园里,各种互联网大佬们,王兴、程一笑、张一鸣等人的创业传说似乎还有余音,后脚搬进来的AI…...
【C++二叉树】进阶OJ题
【C二叉树】进阶OJ题 目录 【C二叉树】进阶OJ题1.二叉树的层序遍历II示例代码解题思路 2.二叉搜索树与双向链表示例代码解题思路 3.从前序与中序遍历序列构造二叉树示例代码解题思路 4.从中序与后序遍历序列构造二叉树示例代码解题思路 5.二叉树的前序遍历(非递归迭…...
C++——vector:resize与reserve的区别,验证写入4GB大数据时相比原生操作的效率提升
resize和reserve的区别 reserve:预留空间,但不实例化元素对象。所以在没有添加新的对象之前,不能引用容器内的元素。而要通过调用push_back或者insert。 resize:改变容器元素的数量,且会实例化对象(指定或…...
基础配置xml
# 配置端口 server.port8081# 文件上传配置 # 是否支持文件上传 spring.servlet.multipart.enabledtrue # 是否支持文件写入磁盘 spring.servlet.multipart.file-size-threshold0 # 上传文件的临时目录 spring.servlet.multipart.locationd:/opt/tmp # 最大支持上传文件大小 sp…...
win环境安装SuperMap iserver和配置许可
SuperMap iServer是我国北京超图公司研发的基于跨平台GIS内核的云GIS应用服务器产品,通过服务的方式,面向网络客户端提供与专业GIS桌面产品相同功能的GIS服务,能够管理、发布多源服务,包括REST服务、OGC服务等。 SuperMap iserve…...
【Apollo学习笔记】——规划模块TASK之PIECEWISE_JERK_NONLINEAR_SPEED_OPTIMIZER(一)
文章目录 TASK系列解析文章前言PIECEWISE_JERK_NONLINEAR_SPEED_OPTIMIZER功能介绍PIECEWISE_JERK_NONLINEAR_SPEED_OPTIMIZER相关配置PIECEWISE_JERK_NONLINEAR_SPEED_OPTIMIZER流程确定优化变量定义目标函数定义约束ProcessSetUpStatesAndBoundsOptimizeByQPCheckSpeedLimitF…...
后进先出(LIFO)详解
LIFO 是 Last In, First Out 的缩写,中文译为后进先出。这是一种数据结构的工作原则,类似于一摞盘子或一叠书本: 最后放进去的元素最先出来 -想象往筒状容器里放盘子: (1)你放进的最后一个盘子(…...
接口测试中缓存处理策略
在接口测试中,缓存处理策略是一个关键环节,直接影响测试结果的准确性和可靠性。合理的缓存处理策略能够确保测试环境的一致性,避免因缓存数据导致的测试偏差。以下是接口测试中常见的缓存处理策略及其详细说明: 一、缓存处理的核…...
Lombok 的 @Data 注解失效,未生成 getter/setter 方法引发的HTTP 406 错误
HTTP 状态码 406 (Not Acceptable) 和 500 (Internal Server Error) 是两类完全不同的错误,它们的含义、原因和解决方法都有显著区别。以下是详细对比: 1. HTTP 406 (Not Acceptable) 含义: 客户端请求的内容类型与服务器支持的内容类型不匹…...
SpringCloudGateway 自定义局部过滤器
场景: 将所有请求转化为同一路径请求(方便穿网配置)在请求头内标识原来路径,然后在将请求分发给不同服务 AllToOneGatewayFilterFactory import lombok.Getter; import lombok.Setter; import lombok.extern.slf4j.Slf4j; impor…...
「全栈技术解析」推客小程序系统开发:从架构设计到裂变增长的完整解决方案
在移动互联网营销竞争白热化的当下,推客小程序系统凭借其裂变传播、精准营销等特性,成为企业抢占市场的利器。本文将深度解析推客小程序系统开发的核心技术与实现路径,助力开发者打造具有市场竞争力的营销工具。 一、系统核心功能架构&…...
HybridVLA——让单一LLM同时具备扩散和自回归动作预测能力:训练时既扩散也回归,但推理时则扩散
前言 如上一篇文章《dexcap升级版之DexWild》中的前言部分所说,在叠衣服的过程中,我会带着团队对比各种模型、方法、策略,毕竟针对各个场景始终寻找更优的解决方案,是我个人和我司「七月在线」的职责之一 且个人认为,…...
实战设计模式之模板方法模式
概述 模板方法模式定义了一个操作中的算法骨架,并将某些步骤延迟到子类中实现。模板方法使得子类可以在不改变算法结构的前提下,重新定义算法中的某些步骤。简单来说,就是在一个方法中定义了要执行的步骤顺序或算法框架,但允许子类…...
2025年- H71-Lc179--39.组合总和(回溯,组合)--Java版
1.题目描述 2.思路 当前的元素可以重复使用。 (1)确定回溯算法函数的参数和返回值(一般是void类型) (2)因为是用递归实现的,所以我们要确定终止条件 (3)单层搜索逻辑 二…...
使用VMware克隆功能快速搭建集群
自己搭建的虚拟机,后续不管是学习java还是大数据,都需要集群,java需要分布式的微服务,大数据Hadoop的计算集群,如果从头开始搭建虚拟机会比较费时费力,这里分享一下如何使用克隆功能快速搭建一个集群 先把…...
生产管理系统开发:专业软件开发公司的实践与思考
生产管理系统开发的关键点 在当前制造业智能化升级的转型背景下,生产管理系统开发正逐步成为企业优化生产流程的重要技术手段。不同行业、不同规模的企业在推进生产管理数字化转型过程中,面临的挑战存在显著差异。本文结合具体实践案例,分析…...
