前阵子公司的产品经理找我谈个需求,希望能为每个用户生成专属的资讯分享图片及让开通专栏的用户能够生成专属的文章分享图片。这两天刚好有空,就抽空预研了 "生成专属的资讯分享图片" 这个功能。
进入正题前,我们先来看一下最终实现的效果图:
接下来我们来简单的介绍一下 "生成专属的资讯分享图片" 这个功能需求:
了解完这个需求,我脑海中有三个可选方案:
由于对 App 端(Android 和 iOS)都不熟,只懂了点皮毛,所以打算就直接尝试第二种方案。确定使用第二种方案,我并没有马上动手开始开发,而是先在网上找一些相关的文章,因为觉得这个需求应该挺常见的。果然通过一番检索,找到了 用程序生成一张在简书的专属分享图片 这篇文章。文章作者对功能做了详细的分析,然后利用 Python 强大的图片处理库 Pillow 进行功能实现。建议有兴趣的同学,直接阅读原文。
虽然 Python 勉强算入门,结合 Pillow 的 API 文档,作者写的代码基本能看懂,但作为一个喜欢折腾的小前端,怎能不使用我们的 Node.js 来折腾一下呢?说做就做,当然马上到 npm 上挑选 Node.js 的图片处理库。经过一番筛选,最终选中了 sharp,这是为什么?当然是喜欢它的名字咯(嘿嘿,其实是看中它的高性能)。
High performance Node.js image processing, the fastest module to resize JPEG, PNG, WebP and TIFF images. Uses the libvips library. http://sharp.pixelplumbing.com/
再次感谢 用程序生成一张在简书的专属分享图片 该文章的作者,他把项目源码和资源都放到了 Github - jianshu_share 上。因为只是技术预研,我就直接使用该项目的图片资源,接下来我们来介绍一下具体实现。
// 创建圆形SVG,用于实现头像裁剪
const roundedCorners = new Buffer(
''
);
/**
* 生成圆形的头像
* @param {*} avatarPath 头像路径
*/
function genCircleAvatar(avatarPath) {
return sharp(avatarPath)
.resize(180, 180)
.overlayWith(roundedCorners, { cutout: true })
.png()
.toBuffer({
resolveWithObject: true
});
}
// 组合多个图层:图片+文字图层
return buffers
.reduce((input, overlay, index) => {
return input.then(result => {
console.dir(overlay.info);
return sharp(result.data)
.overlayWith(overlay.data, overlayOptions[index])
.toBuffer({ resolveWithObject: true });
});
}, backgroudBuffer)
.then((data) => {
return sharp(data.data).toFile(outFilePath);
}).catch(error => {
throw new Error('Generate Share Image Failed.');
});
// 加载字体文件
const textToSVG = TextToSVG.loadSync(path.join(__dirname, "./simhei.ttf"));
// 设置SVG文本元素相关参数
const attributes = { fill: "white" };
const svgOptions = {
x: 0,
y: 0,
fontSize: 32,
anchor: "top",
attributes: attributes
};
/**
* 使用文本生成SVG
* @param {*} text
* @param {*} options
*/
function textToSVGFn(text, options = svgOptions) {
return textToSVG.getSVG(text, options);
}
经过大半天地折腾,终于借助 Node.js 的 sharp 这个图片处理库,基本实现了上述的功能。由于源码过长,我直接放在 Gist 上,有兴趣的小伙伴可以查看 gen-share-image.js 完整源码。
本文主要介绍了如何利用 Node.js 的 sharp 图片处理库,生成专属的分享图片。源码中有很多细节需要处理,如动态获取头像、根据参数动态生成文本信息、异常处理及基于 Koa、Egg.js 或 Express 框架,创建对应的 API 服务等。 gen-share-image.js 源码只是介绍了完整的思路和实现方式,实际开发的时候,在根据具体需求进行调整。虽然目前是已经基于 Koa 开发了一个简单API服务,但还有一些流程需要优化,有兴趣了解具体细节或有更好方案的小伙伴可以给我留言哈。