当前位置: 首页 > 后端技术 > Node.js

犀利小测生成专属分享图片

时间:2023-04-03 14:28:49 Node.js

前段时间公司产品经理找我说一个需求,希望为每个用户生成专属的资讯分享图片,让开栏的用户生成专属文章分享图片。这两天刚好有空,就抽空预研了一下“生成专属信息分享图片”的功能。进入正题之前,先来看一下最终效果图:需求分析接下来简单介绍一下“生成专属信息分享图片”的功能需求:图片中有一块区域可以显示对方的头像和昵称共享用户;需要在图片中展示用户的一些数据信息;App的二维码信息需要显示在图片底部。了解了这个需求后,我脑子里有三个选择:使用app端原生提供的API进行图像合成;在服务端使用特定语言提供的图像处理库进行图像合成;在服务端使用不同的用户信息生成网页,然后使用HTML转IMAGE的库;或者使用iOS企业证书过期填坑一文介绍的神器puppeteer提供的API实现全屏截图功能。由于本人对App端(Android和iOS)不熟悉,只知道一点点,所以打算直接尝试第二种方案。确定使用第二种方案,并没有马上开始开发,而是先在网上找了一些相关的文章,因为我觉得这个需求应该是比较普遍的。果不其然,一番查找后,在简书上找到了利用程序生成专属分享图片的文章。文章作者对该功能进行了详细的分析,然后利用Python强大的图像处理库Pillow实现了该功能。建议感兴趣的同学直接阅读原文。虽然Python勉强入门,结合Pillow的API文档,作者写的代码基本都能看懂,但是作为一个喜欢折腾的小前端,怎么能不用我们的Node.js来折腾呢?说干就干,当然是马上去npm挑选Node.js的图像处理库。经过一番筛选,我最终选择了夏普,为什么呢?当然,我喜欢它的名字(嘿,其实是因为它的高性能)。高性能Node.js图像处理,调整JPEG、PNG、WebP和TIFF图像大小的最快模块。使用libvips库。http://sharp.pixelplumbing.com/再次感谢使用程序生成简书独家分享图。文章作者,他把项目源码和资源放在了Github-jianshu_share。因为只是技术预研,我会直接使用项目的图片资源。下面介绍一下具体的实现。裁剪头像的实现步骤(方形->圆形):通过查看sharp项目的文档,找到了裁剪头像的解决方案。具体实现如下://创建一个圆形SVG用于头像裁剪constroundedCorners=newBuffer('');/***生成圆形头像*@param{*}avatarPath头像路径*/functiongenCircleAvatar(avatarPath){returnsharp(avatarPath).resize(180,180).overlayWith(roundedCorners,{cutout:true}).png().toBuffer({resolveWithObject:true});}叠加背景图、头像和二维码图层:该功能类似于PS图层叠加。其实就是将裁剪后的头像和二维码粘贴到背景图的指定位置。要实现这个功能,还需要用到夏普提供的overlayWith方法。//合并多个层:图像+文本层returnbuffers.reduce((input,overlay,index)=>{returninput.then(result=>{console.dir(overlay.info);returnsharp(result.data).overlayWith(overlay.data,overlayOptions[index]).toBuffer({resolveWithObject:true});});},backgroundBuffer).then((data)=>{returnsharp(data.data).toFile(outFilePath);}).catch(error=>{thrownewError('生成共享图像失败。');});Createtextbasedonuserinformation:在实现这个功能的时候遇到了一个问题。因为官方API没有提供从文件创建图片的方法,最后参考了Howtodynamicallywritetexttoimage?这个issue中提供的解决方案。在sharp项目中解决了这个问题。即使用text-to-svg库,先将文本转成SVG,再使用overlayWith方法合并图层。//加载字体文件consttextToSVG=TextToSVG.loadSync(path.join(__dirname,"./simhei.ttf"));//设置SVG文本元素相关参数constattributes={fill:"white"};constsvgOptions={x:0,y:0,fontSize:32,anchor:"top",attributes:attributes};/***使用文本生成SVG*@param{*}text*@param{*}options*/functiontextToSVGFn(text,options=svgOptions){returntextToSVG.getSVG(text,options);}叠加所有图层生成最终图像:在实现最后一步的时候,我们也遇到了一个大坑,官方没有提供相应的方法。好在最后通过issueEasierwaytocomposite3+layersintheproject提供的方案完美解决了问题。几经折腾,终于借助Node.js锐利的图片处理库,基本实现了以上功能。由于源码太长,我直接放在了Gist上。感兴趣的朋友可以查看gen-share-image.js的完整源码。小结本文主要介绍如何使用Node.js锐图处理库生成专属分享图片。源码中有很多细节需要处理,比如动态获取头像、根据参数动态生成文字信息、异常处理、基于Koa、Egg.js或Express框架创建相应的API服务等。gen-share-image.js的源码只介绍了完整的思路和实现方法。在实际开发中,根据具体需要进行调整。虽然基于Koa已经开发了一个简单的API服务,但是还有一些流程需要优化。如果大家有兴趣了解详情或者有更好的解决方案,可以给我留言。