一、制作前的说明
上一篇文章讲了微信官方提供的动态生成小程序码的一些说明与注意事项。
本篇文章就带大家一起把绘制带参小程序码的宣传海报给画出来以及如何保存已经生成的小程序码,方便下次复用。
注意: 上一篇文章有说到,小程序要生成小程序码的话,小程序必须是已经上线了。所以为了方便,本文使用的小程序码数据(base64格式)是我从别的小程序copy过来的,真实项目中,其实也是一样的写法,有些部分我会使用伪代码来作为说明。
二、制作所需要的工具
微信官方提供的Canvas组件,谁用谁知道,所以作为小白的我还是决定使用大佬开发好的轮子吧。
工具一:Painter
painter是一个可以以很方便生成图片,并且还能屏蔽掉直接使用 Canvas 的一些坑的库,原理如下:
painter定义了一套绘图 JSON 规范,开发者可以根据需求构建生成图片的 Palette(调色板),然后在程序运行过程中把调色板传入给 Painter(画家)。Painter 会调用 Pen(画笔),根据 Palette 内容绘制出对应的图片后返回。
上面是在Paninter的github说明上搬过来的,还有更多的介绍详情就不介绍了,大家可以自行前往查阅。
Painter的gihub地址
工具二:生成JSON数据
Painter的简介里说到:painter定义了一套绘图 JSON 规范,所以方便开发者能够快速根据需求生成这套JSON数据,又有大神开发了一款工具。
这个工具可以通过可视化的操作,把海报的相关数据转成painter所需要的JSON数据。
使用相对来说比较简单,这里就不再详细介绍了。图片网络路径可以将图片上传到小程序的云存储里获的https链接。
生成后,点击复制代码/导出JSON备用。
PS:在某些网络情况下可能会打不开,多刷新几次,还是不行又特别急的话,就只能自己手撸代码了
三、实现原理与代码
实现原理
微信接口返回的小程序码并不是图片格式,而是arrayBuffer格式的数据。这个数据是无法被存储下来的,Painter目前也无法实现通过buffer数据绘制出图片。
所以要实现存储以及使用Painter绘制海报的话就要将buffer格式的数据转成base64格式的数据。
当然,painter也无法根据base64格式的数据绘制图片。所以需要将base64格式的数据转换成图片,并储存在小程序的临时文件路径里面,再将这个临时路径传给painter进行绘制。
实现代码
1、引入painter库
前往github把代码下载下来后,解压打开。进入components文件夹,将painter这个文件夹复制粘贴到小程序的components文件夹内。
2、引用Painter组件
在页面的*.json中引用Painter的组件。
3、wxml代码
<!-- canvas隐藏 -->
<painter customStyle='position: absolute; left: -9999rpx;' customActionStyle="{
{customActionStyle}}"
dancePalette="{
{template}}" palette="{
{paintPallette}}" bind:imgOK="onImgOK" bind:touchEnd="touchEnd"
action="{
{action}}" use2D="{
{true}}" widthPixels="520" />
<!-- canvas隐藏 -->
<image class="poster-img" src="{
{posterUrl}}"></image>
<button type="primary" bindtap="makePoster">生成海报</button>
4、wxss代码
.poster-img{
background-color: #bebebe;
height: 600rpx;
width: 450rpx;
margin: 45rpx auto;
}
效果如下
5、JS代码
通过实现原理可以知道,要想实现绘制小程序码的海报并储存小程序码进行复用,有两个问题:
1、将arrayBuffer数据转换成图片并保存到临时路径里。
2、把arrayBuffer转成base64格式保存在云数据库。
先说第二个问题,因为很好解决,微信小程序就有提供一个API给我们将arrayBuffer的数据转换成base64。代码如下:
const base64 = wx.arrayBufferToBase64(buffer)
这样我们就得到了一个base64格式的数据,我们只需要把它存储到数据库里即可。
然后我们来看看第一个问题,如何将arrayBuffer数据转换成图片并保存到临时路径里呢?
看代码:
/** 将小程序码的ArrayBuffer转换成临时图片路径 */
getQRCodeImg(arrayBuffer) {
const fs = wx.getFileSystemManager() // 获取文件管理器实例
const hash = new Date().getTime() // 随机文件名
const filePath = wx.env.USER_DATA_PATH + "/" + hash + ".jpg" // 临时路径
// 将arrayBuffer写入缓存中,并返回文件路径
return new Promise((resolve, reject) => {
fs.writeFile({
filePath: filePath,
data: arrayBuffer,
encoding: 'binary',
success(res) {
resolve(filePath)
},
fail(err) {
console.log('getQRCodeImgErr --- ', err)
}
})
})
}
OK,两个关键问题都得以解决了,那接下来看看完整的实现代码吧。在小程序主文件夹下新增一个文件夹palette,用于存放绘图的JSON数据以及实例。
完整JS代码
// pages/index/index.js
import poster from '../../palette/painter';
const db = wx.cloud.database()
Page({
/**
* 页面的初始数据
*/
data: {
posterUrl: "",
paintPallette: ""
},
/**
* 生命周期函数--监听页面加载
*/
onLoad: function (options) {
},
/** 绘制完成后的回调函数*/
onImgOK(res) {
wx.hideLoading({
success: (res) => {
},
})
// 这个路径就可以作为保存图片时的资源路径
console.log("海报临时路径", res.detail.path)
this.setData({
posterUrl: res.detail.path
})
},
/** 生成按钮点击 */
async makePoster() {
wx.showLoading({
title: '绘制中',
})
var QRCodeUrl = null
var buffer = null
var QRCodeBase64 = null
// 背景图片Url(可以放到云存储中获取路径,必须是https类型)
var bgImg = "XXXXXXX"
// 获取小程序码数据
// 如果是从微信接口获取,可以省略这步
var QRCodeDataObj = await this.getQRCodeData()
// 实际项目中,这里应该判断一下是否为空,如果不存在,则从微信官方接口获取
QRCodeBase64 = QRCodeDataObj.data[0].QRCodeData
// 将base64转成buffer
// 同理 如果是从微信接口获取,可以省略这步
buffer = wx.base64ToArrayBuffer(QRCodeBase64)
// 存到临时文件里
QRCodeUrl = await this.getQRCodeImg(buffer)
// 这是绘制海报所用到JSON数据
const viewList = {
"width": "450px",
"height": "798px",
"background": "#f8f8f8",
"views": [{
"type": "image",
"url": bgImg,
"css": {
"width": "450px",
"height": "798px",
"top": "0px",
"left": "0px",
"rotate": "0",
"borderRadius": "",
"borderWidth": "",
"borderColor": "#000000",
"shadow": "",
"mode": "scaleToFill"
}
},
{
"type": "image",
"url": QRCodeUrl,
"css": {
"width": "95px",
"height": "95px",
"top": "675px",
"left": "346px",
"rotate": "0",
"borderRadius": "",
"borderWidth": "",
"borderColor": "#000000",
"shadow": "",
"mode": "scaleToFill"
}
}
]
}
this.setData({
paintPallette: new poster().palette(viewList)
})
},
/** 将小程序码的ArrayBuffer转换成临时图片路径 */
getQRCodeImg(arrayBuffer) {
const fs = wx.getFileSystemManager() // 获取文件管理器实例
const hash = new Date().getTime() // 随机文件名
const filePath = wx.env.USER_DATA_PATH + "/" + hash + ".jpg" // 临时路径
// 将arrayBuffer写入缓存中,并返回文件路径
return new Promise((resolve, reject) => {
fs.writeFile({
filePath: filePath,
data: arrayBuffer,
encoding: 'binary',
success(res) {
resolve(filePath)
},
fail(err) {
console.log('getQRCodeImgErr --- ', err)
}
})
})
},
/** 从云数据库获取小程序码的base64数据
* 由于示例小程序没有上线
* 无法生成小程序码
* 所以我从其他小程序copy了一段
* 由buffer转成base64的数据
*/
getQRCodeData() {
return new Promise((resolve, reject) => {
db.collection('QRCode').get()
.then(res => {
resolve(res)
})
.catch(err => {
console.log(err)
})
})
},
})
6、运行效果
四、 结尾
由于篇幅关系,存储复用的详细代码就不写了,直接将buffer数据转成base64存到数据库,取得时候根据openid来取即可。没有的话就生成新的再存。
ps:本人技术有限,正在学习中,如果博客中有什么写得不恰当之处,还望大佬赐教。