小程序开发-利用canvas实现保存二维码海报到本机

场景及需求

在小程序开发过程中,经常需要实现保存某个页面为带小程序码的二维码海报图片到本地,然后用于分享或者发朋友圈等操作。

主要技术点及小程序相关api

技术注意事项

  • 小程序的canvas与H5 canvas使用api大部分一致,但由于小程序中没有DOM节点的概念,所以不能使用很多现成的工具库
  • 小程序canvas默认宽度300px、高度225px
  • 小程序canvas相关的api中单位为px,并非rpx,所以在业务实现过程中需要处理适配
  • 小程序canvas对跨域图片不支持,需要先将图片缓存到本地

技术点

  • wx.getImageInfo()
  • wx.getSystemInfo()
  • wx.canvasToTempFilePath()
  • wx.saveImageToPhotosAlbum()
  • canvas渲染相关api

整体流程

1.先获取所有图片资源,线上图片需要缓存到本地,使用图片的本地路径做渲染

2.获取设备信息,根据设备宽度计算出宽度因子x

3.绘制canvas

4.将canvas转化为图片,将图片保存到本机

实现

宽度因子x及元素宽度的尺寸计算

rpx(responsive pixel): 可以根据屏幕宽度进行自适应。规定屏幕宽为750rpx。如在 iPhone6 上,屏幕宽度为375px,共有750个物理像素,则750rpx = 375px = 750物理像素,1rpx = 0.5px = 1物理像素。

参考文档: 小程序-WXSS-尺寸单位

由文档可以看出不同的设备,宽度是不同数值的px,但是均为750rpx,由此可以利用750rpx计算出宽度因子x:

设备宽度 / 750

以设计稿宽度750rpx为例,则在不同设备下,设计稿宽度y在不同设备下的px宽度均为:

Y = y * x

Y = y * (设备宽度 / 750)

由此,在实现中,canvas标签宽高需要设置为变量,且使用微信提供的 wx.getSystemInfo() 接口获取设备宽度信息后,进行计算

<canvas canvas-id="qrcode-canvas" :style="{width: canvas.width + 'px', height: canvas.height + 'px'}"></canvas>
复制代码
// wx.js
// 获取设备基本信息
export function wxGetSystemInfo () {return new Promise(async function (resolve, reject) {wx.getSystemInfo({success: function (res) {resolve(res);},fail: function (err) {reject(err);}})});
}
// demo.vue
// 获取手机基本信息
async getPhoneSystemInfo () {let _this = this;let systemInfoRes = await wxGetSystemInfo();_this.canvas.width = systemInfoRes.screenWidth;// 设计稿宽高为 750 * 912_this.canvas.height = 912 / 750 * _this.canvas.width;_this.storageQrcode();
},
复制代码

获取远程图片缓存到本地使用

  • api
    • wx.getImageInfo()
    • 参考文档: wx.getImageInfo()

注意:如果是本地图片,即'static'文件夹中的图片,如'/static/logo.png'经过wx.getImageInfo返回的path会省去开头的'/',即'static/logo.png',这会导致拿不到资源,所以本地图片不需要调用wx.getImageInfo()进行本地缓存

// wx.js
// 获取图片基本信息
export function wxGetImgInfo (imgUrl) {return new Promise(async function (resolve, reject) {wx.getImageInfo({src: imgUrl,success: function (res) {resolve(res);},fail: function (err) {reject(err);}})});
}
// demo.vue
// 缓存远程图片
async storageQrcode () {let _this = this;// 背景图url转path// let bgRes = await wxGetImgInfo(_this.bgImg);// _this.imgPath.bgImg = bgRes.path;// Logo url转path// let logoRes = await wxGetImgInfo(_this.logo);// _this.imgPath.logo = logoRes.path;// 头像 url转path// let headerImgRes = await wxGetImgInfo(_this.cardDetail.header);// _this.imgPath.headerImg = headerImgRes.path;// 二维码 url转pathlet qrCodeRes = await wxGetImgInfo(_this.qrCode);_this.imgPath.qrCode = qrCodeRes.path;console.log(_this.imgPath);// _this.initCanvas(_this.canvas.width);
},
复制代码

绘制canvas

canvas绘制主要用到了图片绘制、文字绘制,图片绘制及文字绘制的时候,需要引入上文说到的宽度因子x进行计算

图片绘制

  • canvasContext.drawImage
    • 参考文档: canvasContext.drawImage

这里的图片绘制之前先计算宽度因子

  let _this = this;// variableVal即为上文拿到的设备宽度const variableNum = variableVal / 750; // 根据设备宽度算出一个rpx为多少pxconst ctx = wx.createCanvasContext('qrcode-canvas');// 清除画布上矩形的内容ctx.clearRect(0, 0, 0, 0);// 绘制上部card背景图const bgImgDesc = {url: _this.imgPath.bgImg,left: 0,top: 0,width: 750 * variableNum,height: 912 * variableNum};ctx.drawImage(bgImgDesc.url, bgImgDesc.left, bgImgDesc.top, bgImgDesc.width, bgImgDesc.height);ctx.draw();
复制代码

文字的绘制

  • canvasContext.setFillStyle - 设置颜色
  • canvasContext.setFontSize - 设置大小
  • canvasContext.fillText - 填充文本
const nameDesc = {text: _this.cardDetail.name,fontSize: 36 * variableNum,color: '#4F5E6F',left: 102 * variableNum,top: 200 * variableNum
};
ctx.setFillStyle(nameDesc.color);
ctx.setFontSize(nameDesc.fontSize);
ctx.fillText(nameDesc.text, nameDesc.left, nameDesc.top);
ctx.draw();
复制代码

canvas转图片并保存到本地

  • wx.canvasToTempFilePath - canvas转图片
    • 参考文档: wx.canvasToTempFilePath
  • wx.saveImageToPhotosAlbum - 保存图片到本地
    • 参考文档: wx.saveImageToPhotosAlbum

注意点

tip: wx.canvasToTempFilePath() 在 draw 回调里调用该方法才能保证图片导出成功。

由于导出图片需要在canvas绘制图片的draw()方法回调中使用才能,所以我们在绘制canvas的时候直接转canvas为图片,然后将路径存下来,点击下载的时候,再直接拿图片路径进行下载操作。

// wx.js
// canvas画布转图片
export function wxCanvasToTempFilePath (canvasObj) {return new Promise(async function (resolve, reject) {wx.canvasToTempFilePath({x: canvasObj.x,y: canvasObj.y,width: canvasObj.width,height: canvasObj.height,destWidth: canvasObj.destWidth,destHeight: canvasObj.destHeight,canvasId: canvasObj.canvasId,fileType: canvasObj.fileType ? canvasObj.fileType : 'png',success: function (res) {resolve(res);},fail: function (err) {reject(err);}})});
}
// demo.vue
// 绘制canvas
initCanvas () {let _this = this;// 绘制canvas......ctx.draw(false, function () {_this.saveImg();});
},
// 将canvas转为图片
async saveImg () {let _this = this;const canvasObj = {x: 0,y: 0,width: _this.canvas.width,height: _this.canvas.height,destWidth: _this.canvas.width * 4,destHeight: _this.canvas.height * 4,canvasId: 'qrcode-canvas',fileType: 'png'};let imgRes = await wxCanvasToTempFilePath(canvasObj);_this.qrCodeImgPath = imgRes.tempFilePath;
},
复制代码

下载图片到本地

<canvas canvas-id="qrcode-canvas" :style="{width: canvas.width + 'px', height: canvas.height + 'px'}"></canvas>
<button type="primary" plain="true" @click="downLoadImg"> 保存二维码 </button>
复制代码
// wx.js
// 保存图片到本地
export function wxSaveImageToPhotosAlbum (filePath) {return new Promise(async function (resolve, reject) {wx.saveImageToPhotosAlbum({filePath: filePath,success: function (res) {resolve(res);},fail: function (err) {reject(err);}})});
}
// demo.vue
// 保存图片到本机
async downLoadImg () {let _this = this;let saveRes = await wxSaveImageToPhotosAlbum(_this.qrCodeImgPath);if (saveRes.errMsg === 'saveImageToPhotosAlbum:ok') {wx.showToast({duration: 3000,icon: 'none',title: '保存图片成功!',mask: true});} else {wx.showToast({duration: 3000,icon: 'none',title: '保存图片失败,请重试!',mask: true});}
},
复制代码

demo代码已经放在 './demo' 文件夹,欢迎交流

总结

在业务实现中,我们只要把业务流程进行分割,然后一步一步去实现,捋明白流程之后各个击破很多第一反应去查找已有的库来实现的功能自己实现起来也很简单。

在某种意义上,自己弄明白原理之后去实现反而更加轻松,更加得心应手。

-- LucaLJX: github:https://github.com/LucaLJX

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

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

相关文章

Docker系统六:Docker网络管理

Docker网络 I. Docer的通信方式 默认情况下&#xff0c;Docker使用网桥&#xff08;brige&#xff09; NAT的通信模型. Docker启动时会自动创建网桥Docker0&#xff0c;并配置ip 172.17.0.1/16 ifconfig docker0 docker0 Link encap:Ethernet HWaddr 02:42:e0:31:ac:10inet …

pthread_cond_wait

1. 首先pthread_cond_wait 的定义是这样的 The pthread_cond_wait() andpthread_cond_timedwait() functions are used to block on a condition variable. They are called withmutex locked by the calling thread or undefined behaviour will result. These functions ato…

HDU 1525 Euclid's Game

题目大意&#xff1a; 题目给出了两个正数a.b 每次操作&#xff0c;大的数减掉小的数的整数倍。一个数变为0 的时候结束。 谁先先把其中一个数减为0的获胜。问谁可以赢。Stan是先手。 题目思路&#xff1a; 无论a,b的值为多少&#xff0c;局面&#xff1a;[a%b&#xff0c;b] 一…

SRAM BIST技术学习

MBIST 方法是目前大容量存储器测试的主流技术&#xff0c;该技术利用芯片内部专门设计的BIST 电路进行自动化测试&#xff0c;能够对嵌入式存储器这种具有复杂电路结构的嵌入式模块进行全面的测试。MBIST 电路将产生测试向量的电路模块以及检测测试结果的比较模块都置于芯片的内…

【Zigbee技术入门教程-02】一图读懂ZStack协议栈的核心思想与工作机理

【Zigbee技术入门教程-02】一图读懂ZStack协议栈的核心思想与工作机理 广东职业技术学院 欧浩源 Z-Stack协议栈是一个基于任务轮询方式的操作系统&#xff0c;其任务调度和资源分配由操作系统抽象层OSAL管理着。 你可以理解为&#xff1a;Z-Stack协议栈 OSAL操作系统 CC25…

CMOS图像传感器——SmartSens

近年来CIS发展成为增量市场,国产CIS厂商也踊跃布局,给业界带来许多惊喜。思特威(上海)电子科技股份有限公司(SmartSens)正是国产CIS中亮眼的一家厂商。数据显示,2020年思特威安防监控市场的CIS芯片出货量为1.46亿颗,继续位居全球出货量TOP1的位置;同年,思特威的新兴领…

Servlet第二篇【Servlet调用图、Servlet细节、ServletConfig、ServletContext】

Servlet的调用图 前面我们已经学过了Servlet的生命周期了&#xff0c;我们根据Servlet的生命周期画出Servlet的调用图加深理解 Servlet的细节 一个已经注册的Servlet可以被多次映射 同一个Servlet可以被映射到多个URL上。 <servlet><servlet-name>Demo1</servle…

vue响应式原理

vue响应式原理 initState new Vue() > _init() > initState: function initState (vm: Component) {vm._watchers []const opts vm.$optionsif (opts.props) initProps(vm, opts.props)if (opts.methods) initMethods(vm, opts.methods)if (opts.data) {initData(vm)} …

Oracle数据库管理与开发pdf

下载地址&#xff1a;网盘下载基本介绍编辑内容简介Oracle是一个适合于大中型企事业的数据库管理系统&#xff0c;在银行、电信、移动通信、航空、保险、金融、气象、铁路、跨国公司和电子商务等诸多领域得到了广泛的应用。据统计&#xff0c;在所有数据库管理系统中&#xff0…

DVS/DVR区别

一、DVS &#xff08;Digital Video Server&#xff09;网络视频服务器的简称。DVS(网络视频服务器)的原理网络视频服务器主要实现模拟视音频信号的IP 化。经数字化的视音频信号MPEG-4 视频压缩算法和G.729/ADPCM 音频压缩算法进行压缩编码&#xff0c;然后通过IP 网将低码率的…

自动对焦方法学习

实现自动对焦的方法有很多种,可以根据不同的工作原理,将自动对焦技术分成不同种类。 按照系统是否自带信号发射系统,可以分为主动式与被动式两种类型。 主动式对焦方法是由成像系统中的发射装置发出信号,然后再由接收装置接收从被摄景物所反射回来的反馈信号并利用通过计算…

微粒化运营:升级内容产业消费体验(附视频版)

那些最受欢迎的内容平台做对了什么&#xff1f; Facebook和Google是全球互联网广告产业中最早开始微粒化运营的代表&#xff0c;Google的互联网精准广告的思路与微粒化运营是完全相同的&#xff0c;这两家公司也因此获得了全球超过20%的互联网广告的收入。 以Facebook为例&…

mycat读写分离

只需要读写分离的功能&#xff0c;分库分表的都不需要。 涉及到的配置文件&#xff1a; 1.conf/server.xml 主要配置的是mycat的用户名和密码&#xff0c;mycat的用户名和密码和mysql的用户名密码是分开的&#xff0c;应用连接mycat就用这个用户名和密码。 <?xml version&q…

chisel快速入门(一)

一、概述 Chisel&#xff08;Constructing Hardware In a Scala Embedded Language&#xff09;是一种嵌入在高级编程语言Scala的硬件构建语言。Chisel实际上只是一些特殊的类定义&#xff0c;预定义对象的集合&#xff0c;使用Scala的用法&#xff0c;所以在写Chisel程序时实际…

DVS/DVR常见的监控名词

英文名词 说明BNC 全称Bayonet Nut Connector&#xff0c;一种用于同轴电缆的连接器DHCP 动态主机配置协议&#xff0c;用于动态地指派配置信息DNS 域名系统&#xff0c;以用户友好的方式将名字转换为…

导出数据生成excel

前台&#xff1a; <asp:Button ID"btnMoney" runat"server" Text"经费使用总结表" CssClass"admin_cx marginleft" Height"25" OnClick"btnMoney_Click" /> 后台&#xff1a; protected void btnMoney_Cli…

U盘基本处理,U盘与移动固态硬盘

一、辨别 USB2.0 和 USB3.0 1、从USB外观上来看&#xff0c;USB2.0通常是白色或黑色&#xff0c;而USB3.0则改观为“高大上”的蓝色接口。 目前&#xff0c;部分笔记本电脑USB接口&#xff0c;已同时提供对USB2.0及USB3.0的支持&#xff0c;我们可以通过接口颜色来区别。 2、从…

UWP_小说在线阅读器:功能要求与技术要求

注&#xff1a;2017年2月23日正式提上日程 学了WP开发也有一年了&#xff0c;也没做过什么软件的。17年进发UWP&#xff0c;锻炼自己一下。做一个开源的小说阅读器吧。 既然开发一个软件。所以要设计一下吧。 功能要求&#xff1a; 可能要用到的技术&#xff0c;这个吗&#xf…

chisel快速入门(二)

上一篇见此&#xff1a; chisel快速入门&#xff08;一&#xff09;_沧海一升的博客-CSDN博客简单介绍了chisel&#xff0c;使硬件开发者能快速上手chisel。https://blog.csdn.net/qq_21842097/article/details/121415341 十、运行和测试 现在我们已经定义了模块&#xff0c;…

【WPF】设置TextBox内容为空时的提示文字

原文:【WPF】设置TextBox内容为空时的提示文字<TextBox Width"150" Margin"5"><TextBox.Resources><VisualBrush x:Key"HintText" TileMode"None" Opacity"0.5" Stretch"None" AlignmentX"Le…