Node图片编辑工具gm和sharp

准备工作 实现方式 参考:

我们经常会在微信上生成一些个性化的海报,海报中嵌入用户的微信头像和昵称,以及应用的二维码,如下两张海报:

*.png *.png

下面先与大家分享如何在后台使用nodejs生成海报。

ps:在后台生成海报有好处也有坏处。相对于前端生成,好处是:由于服务器的配置统一,生成出的海报的尺寸一致,不会有变形的情况;坏处是:由于后台生成需要引入文字包,一般来说普遍不支持emoji表情符号。

准备工作

先安装gm和sharp这两个图片处理包。

gm和sharp在linux上安装会有权限问题,需要手动创建文件夹。

或者使用如下命令安装:

npm install --unsafe-perm

安装部署方式参考之前的博客

https://www.daguanren.cc/post/promise_graphicsmagick.html

gm的下载地址:

https://sourceforge.net/projects/graphicsmagick/files/graphicsmagick/

实现方式

以第一张海报图为例,我们讲解代码如何实现。

思路如下:

先来直观的看下最终实现的效果图和所需的背景图,就可以大致知道我们要在哪些区域写入文字和拼接图片 *.png *.png 需要在背景图上拼接一个头像和一个二维码,以及写入昵称(姓名)、手机号、过期日期这些白色文字。由于昵称的长度不固定,所以如果采用上下排布的方式需要对昵称进行居中,比较麻烦,所以稍作调整,采用左右排布的方式。最终效果如本文第一张海报所示 接下来各个击破,微信头像可以用通过微信公众号或小程序的api获取,例如公众号的获取用户基本信息 获取的头像通常为一个远程的url,例如http://thirdwx.qlogo.cn/mmopen/g3MonUZtNHkdmzicIlibx6iaFqAc56vxLSUfpb6n5WKSYVY0ChQKkiaJSgQ1dZuTOgvLLrhJbERQQ4eMsv84eavHiaiceqxibJxCfHe/0 我们需要将远程头像下载到本地临时文件夹,以便后续使用sharp和gm进行拼接 带参二维码的获取方式也类似,参照生成带参数的二维码api。生成后通过ticket换取二维码的url
// 引入用到的npm包,没安装的先npm install 安装
const rp =require('request-promise');
const gm = require('gm');
const sharp = require('sharp');
const fs = require('fs');

// 定义请求参数
const options = {
          method: 'GET',
          uri: img_url, // 头像或二维码地址
          encoding: 'binary' // 或者也可以是 null
        }

// 发送请求
let res = await rp(options);

// 生成一串字符串来标记该头像是谁的
let variable = think.uuid();

// 将图片存到本地临时文件,存在了根目录下的tmp/img/文件夹下
await fs.writeFileSync('tmp/img/avatar_'+variable +'.png', res, 'binary');

// 头像和二维码均使用此方式存储到本地
// 省略.....


// 头像存储好了后,由于头像是正方形的,我们要将其改成圆形,并且调整其大小
// 使用sharp将头像转成圆角
        const roundedCorners = Buffer.from(
        '<svg><rect x="0" y="0" width="130" height="130" rx="65" ry="65"/></svg>'
        )
        let sharpStream2 = sharp('tmp/img/avatar_'+ variable +'.png')
        .resize(130,130)
        .composite([{input:roundedCorners, blend: 'dest-in'}])
        .png()

// 将异步的sharpStream2.toFile函数封装下,改成同步
let sharpWrite2 = think.promisify(sharpStream2.toFile, sharpStream2);

// 将圆形头像存储到临时文件夹
await sharpWrite2('tmp/img/circleAvatar_'+ variable +'.png');


// 同理,可以对二维码做类似处理
// 缩小二维码
        let sharpStream = sharp(qrcode_local_path)
        .resize(193,193)
        .png()

        let sharpWrite1 = think.promisify(sharpStream.toFile, sharpStream);
        await sharpWrite1(qrcode_local_path_output);


// 拼接图片和根据坐标点预估位置写入文字

let stream =  await gm()
                                // 在(0,0)位置处放入背景图
                .in('-page', '+0+0')
                .in(think.ROOT_PATH + '/www/static/image/poster/coupon_template.jpg')
                                // 在(240,138)位置处放入圆形头像
                .in('-page', '+240+138')
                .in('tmp/img/circleAvatar_'+ variable +'.png')
                                // 在(327,987)位置处放入二维码
                .in('-page', '+327+987')
                .in(qrcode_local_path_output)
                                // 拼接
                .mosaic()
                //写完赛日期
                .fill('#ffffff')
                                // 加载指定字体
                .font("msyh.ttf")
                .fontSize(30)
                                // 在指定位置写入名字
                .drawText(387, 195, decodeURI(name))
                // 写手机号
                .fill('#ffffff')
                .font("msyh.ttf")
                .fontSize(30)
                .drawText(387, 240, decodeURI(phone))
                // 写有效期
                .fill('#ffffff')
                .font("msyh.ttf")
                .fontSize(20)
                .drawText(405, 887, decodeURI(coupon.validto.split(" ")[0]))

                        // 保存最终的海报
                let gmWrite = think.promisify(stream.write, stream);
                await gmWrite(qrcode_local_path_output);

至此大功告成,当然代码并不是完整的,这里只是大致介绍。后面还有很多可以优化,例如可以将生成的海报保存下来,以便下次直接使用。下次生成海报的时候可以先判断之前是否已经生成了海报,如果已经生成了,那么直接从数据库把海报的url读取出来。

参考:

头像转圆形

https://zhuanlan.zhihu.com/p/137131729

带参二维码

https://developers.weixin.qq.com/doc/offiaccount/Account_Management/Generating_a_Parametric_QR_Code.html

在线免费生成条码:

https://barcode.tec-it.com/zh/?data=ZdPlSigNGrQl9CO4

文章来源:

Author:大官人
link:https://www.daguanren.cc/post/Node-tu-pian-bian-ji-gong-ju-gm-he-sharp.html