【实战教程】在小程序中快速生成分享海报
在小程序中生成分享海报是一个很常见的需求,目前主要有以下两种做法:
直接由前端生成,使用小程序提供的 canvas
API
由后端知晓云「云函数」生成,前端再获取
本文将介绍通过知晓云「云函数」来生成分享海报的功能,并使用 webpack
和 mincloud
将代码打包上传到知晓云。
技术栈:
代码打包工具: [email protected]
部署工具:[email protected]
图片处理:[email protected]
其他:知晓云 SDK
、imageMagick
(云函数内置)
一、项目搭建
项目文件结构:
gm-draw-image ├── index.js ├── package.json ├── src │ └── index.js ├── webpack.config.js └── yarn.lock
项目搭建与云函数代码打包示例文档基本一致。项目搭建好后,还需要安装以下依赖(两种安装方式选其一即可):
// 使用 yarn 安装 yarn add gm mincloud // 使用 npm 安装 npm install --save gm mincloud
修改 deploy
脚本,如下:
// package.json ... "scripts": { "build": "webpack --mode production", "predeploy": "npm run build", "deploy": "mincloud deploy gm-draw-image ../" }, ...
最终我们会使用以下两个命令来部署和测试:
npm run deploy // 部署到知晓云 mincloud invoke gm-draw-image // 测试已经部署到知晓云上的云函数
二、生成海报
这里分为 4 个步骤:
- 下载海报需要的资源
- 图片 / 文本处理
- 海报绘制
- 将绘制完成的海报上传到知晓云
使用知晓云 Node SDK 的 request
方法将资源下载下来(不能直接使用其他第三方 request
包):
BaaS.request.get(url) .then(res => {}) .catch(err => {})
引入 gm 库对图片进行处理,云函数沙箱环境已经内置 imageMagick
工具:
const gm = require('gm').subClass({ imageMagick: true })
在处理文字的时候需要注意,设置字体时需选择知晓云已支持的字体,详见文档文档。
另外,这里有一个 bug:在同一个图层中,如果填充颜色之前有填充图片操作,那么后续填充的颜色将会不起作用。推荐的做法是如果有需要同时填充图片以及填充颜色,建议将这两个操作分开处理,最后再合成一张图。
bug 示例如下:
gm(width, height, 'none') .fill(bg) // 填充了一张图片 .drawRectangle(`0, 0, ${width}, ${height}`) .fill('#fff') // 字体颜色,这个操作不起作用 .fontSize(20) .drawText(140, 170, 'mincloud')
下载图片,图片保存路径需在 /tmp/
路径下:
BaaS.request.get(url, {responseType: 'arraybuffer'}) .then(res => {}) .catch(err => {})
上传图片到知晓云:
var MyFile = new BaaS.File() MyFile.upload(img, {filename: 'test.png'})
完整代码如下:
const fs = require('fs') const gm = require('gm').subClass({ imageMagick: true }) // 海报资源 const avatarImg = 'https://cloud-minapp-6.cloud.ifanrusercontent.com/1gQ5Mat7WAwyW1hl.jpg' const backgroundImg = 'https://cloud-minapp-6.cloud.ifanrusercontent.com/1gQ7hCpFCK1qw8XQ.jpeg' const MyFile = new BaaS.File() const imageSize = { width: 375, height: 250, } function downloadImage(url) { const filename = `/tmp/${Math.random().toString().slice(2)}.jpg` const file = fs.createWriteStream(filename) return BaaS.request.get(url, {responseType: 'arraybuffer'}).then(res => { file.write(res.data) file.end() return filename }) } function uploadImage(buffer) { return MyFile.upload(buffer, {filename: Math.random().toString().slice(2) + '.png'}) } function drawText(filename) { return new Promise((resolve, reject) => { gm(imageSize.width, imageSize.height, 'none') // 设置字体以及文字大小,这里只能设置云函数已支持的字体 .font('/usr/share/fonts/ttf-bitstream-vera/VeraMoBd.ttf') .fill('#fff') .fontSize(20) .drawText(140, 170, 'mincloud') .fill('#fff') .fontSize(14) .drawText(30, 200, 'An easy-to-use MiniApp development tool.') .write(filename, function(err) { if (err) { return reject(err) } resolve(filename) }) }) } function genAvatar(avatar) { return new Promise((resolve, reject) => { gm(avatar) .resize(100, 100) .write(avatar, function(err) { if (err) { return reject(err) } resolve(avatar) }) }) } function genBackground(bg) { return new Promise((resolve, reject) => { gm(bg) .resize(500, 350) .blur(20, 2) .write(bg, function(err) { if (err) { return reject(err) } resolve(bg) }) }) } module.exports = function (event, callback) { const {width, height} = imageSize const job1 = downloadImage(backgroundImg).then(res => genBackground(res)) const job2 = downloadImage(avatarImg).then(res => genAvatar(res)) const job3 = drawText('/tmp/textLayer.png') Promise.all([job1, job2, job3]).then(res => { gm(width, height, 'none') .fill(res[0]) .drawRectangle(`0, 0, ${width}, ${height}`) // 绘制背景 .fill(res[1]) .drawCircle(190, 80, 190, 125) // 绘制头像 .fill(res[2]) .drawRectangle(`0, 0, ${width}, ${height}`) // 绘制文本 .toBuffer('PNG', function (err, buffer) { if (err) { return callback(err) } uploadImage(buffer).then((res) => { console.log('success') callback(null, res.data.file_link) }).catch(err => { callback(err) }) }) }) }
三、部署并测试
跟 npm
一样,部署前需要先登录,请参照文档配置。
使用以下命令即可将云函数部署到知晓云:
npm run deploy
执行结果如下:
使用以下的命令来测试:
mincloud invoke image-crawler
执行结果如下:
上传到知晓云的图片如下:
生成的海报效果图:
素材原图:
四、参考文档
知晓云开发文档:https://doc.minapp.com/
gm 官方文档:http://aheckmann.github.io/gm...