微信小程序自定义字体海报图方案

1,953 阅读3分钟

微信小程序中的canvas等原生组件不支持wx.loadFontface加载的字体,所以对于有自定义字体需求的海报图就得寻找其他解决方案了。因为之前做过服务端绘图的工作,我第一反应就是能不能服务端绘图,然后小程序下载直接保存到相册里,基于小程序丰富的API,这个想法是完全可行的,那剩下的问题是怎么让小程序云函数画出这张图来。

image.png

绘图引擎使用SpriteJS ,目前SpriteJS最新版是3.x,性能比2.x好很多,支持的特性更多,在浏览器环境默认使用webGL,还可以降级到canvas2D,由于2.x版本的Label对于文字排版支持比较好,所以我选择使用Spritejs 2.7。

SpriteJS 2.x没有线上文档地址,可以自行克隆项目npm run doc

SpriteJS 2.7 在服务端使用需要node-canvas提供Canvas API,node-canvas是tj大神使用c++实现的,也就是说npm install时需要编译,由于node-canvas编译时间比较久,将编译好的node-canvas上传到云函数是个比较好的选择。编译node-canvas的服务器环境至少是CentOS 7.5,node-canvas依赖glibc,低于这个版本编译不出来(不要打glic的主意)。Node.js我用的是8.9版本。

请确保编译环境跟云函数环境一致,否则处出现环境兼容性问题。

我分别为云函数环境和我的MBP各编译了一份node-canvas,开发的时候使用开发机的node-canvas方便本地调试,相信我,等开始调海报图细节的时候,你就会觉得为开发机编译node-canvas是多么明智的决定。另外为了减少node_modules的体积,建议你用node-prune来清理一下垃圾文件。

node-prune有可能会错删文件,请在使用后务必确认运行正常。

最开始是因为小程序canvas不支持自定义字体才做这套方案的,那云函数中如何支持自定义字体呢?node-canvas提供了一个API registerFont可以将字体文件注册到系统上,然后就可以正常使用这个字体了。

registerFont('/path/to/font/file', { 
  family: 'Source Han Serif', 
  weight?: '400', 
  style?: 'normal' 
}) => void

在画好图后,通过SpriteJS提供的snapshot方法可以给画布拍一个快照,然后将生成的buffer直接上传到云存储中,返回小程序一个FileID,让小程序端下载下这个文件来并保存到相册里,一张海报图就生成好了。

注意事项

  1. SpriteJS的scene提供了preload预加载图片,如果使用小程序云存储中的图片文件,先获取临时文件HTTPS路径。
  2. 小程序的时区是UTC+0,不是UTC+8,如果海报图上有展示时间的需求,记得调整好时区。Date原型上有ge tTimezoneOffset方法,通过这个API调整也可以。