我在Twitter上分享我的博客文章,曾经有一段时间,我自娱自乐地为每篇博客文章画了一张图片。
我对Hugo进行了设置,使其使用存储在文章文件夹中的名为banner.png 或banner.jpg 的图片作为Open Graph的图片,就像这样。
<meta property="og:image" content="https://flaviocopes.com/axios/banner.png" />
如果一篇文章没有图片,我就显示我的头像来代替。
<meta property="og:image" content="https://flaviocopes.com/img/avatar.png" />
有一个问题:我很久以前就不再制作那些自定义的横幅图片了,而且我的大多数帖子都没有横幅。
它们在Twitter上看起来都是一样的。

我不可能随手制作500张横幅图片。自从我看到Indie Hackers为论坛博客文章生成这些图片(一个伟大的想法),我就有了用程序生成它们的想法。

因此,在偶然发现了一个很好的横幅图片的灵感后,我决定为我的每篇博客文章制作一个自定义的横幅。
这个横幅是一张PNG图片,为了让帖子集中在主题上("如何用Node.js和Canvas创建和保存图片"),我将跳过一些部分。
另外,我做的事情有很多不同的方法,这里只是一种方法。
首先,我们需要哪些npm包?
只有一个! canvas:
npm install canvas
这个包为我们提供了一个基于Node.js的Canvas API的实现,我们在浏览器中知道并喜爱这个API。
换句话说,我用来生成图片的所有东西在浏览器中也能用。
只不过我不是从<canvas> HTML 元素中获取 Canvas 实例,而是加载该库,从中获取函数createCanvas 。
const { createCanvas } = require('canvas')
然后我调用这个函数,传递画布的宽度和高度,我将其设置为1200x600。
const width = 1200
const height = 600
const canvas = createCanvas(width, height)
const context = canvas.getContext('2d')
让我们把它涂成黑色(随口说了句滚石乐队的话)。
context.fillStyle = '#fff'
context.fillRect(0, 0, width, height)

现在我们来添加文字。
我首先选择Menlo字体,大而粗。我把它放在中心位置,然后设置为白色。
最后我调用context.fillText() ,在画布上绘制文字。
const text = 'Hello, World!'
context.font = 'bold 70pt Menlo'
context.textAlign = 'center'
context.fillStyle = '#fff'
context.fillText(text, 600, 170)

让我们在文字后面画一个蓝色方框。
const text = 'Hello, World!'
context.textBaseline = 'top'
context.fillStyle = '#3574d4'
const textWidth = context.measureText(text).width
context.fillRect(600 - textWidth / 2 - 10, 170 - 5, textWidth + 20, 120)
context.fillStyle = '#fff'
context.fillText(text, 600, 170)
我们将textBaseline 属性设置为top ,以减轻矩形的定位。然后我检查文本的长度,使用measureText() ,并使用我们用来绘制文本的相同坐标来绘制它。
确保你在文本之前画出矩形,因为在 Canvas 中,你要按顺序一个接一个地画。

很好!现在我想在底部显示我的网站网址。
context.fillStyle = '#fff'
context.font = 'bold 30pt Menlo'
context.fillText('flaviocopes.com', 600, 530)

我还想添加我的标志。要做到这一点,让我们从canvas 模块中导入loadImage 函数。
const { createCanvas, loadImage } = require('canvas')
并且我们调用它,指定包含在我们运行脚本的同一文件夹中的logo.png 图片。
loadImage('./logo.png').then(image => {
})
一旦承诺得到解决,我们就有了图像对象,我们可以用drawImage() 把它画到画布上。
loadImage('./logo.png').then(image => {
context.drawImage(image, 340, 515, 70, 70)
})

就这样了!现在我们可以使用toBuffer() 方法将图像保存到一个image.png 文件。
const buffer = canvas.toBuffer('image/png')
fs.writeFileSync('./image.png', buffer)
这里是完整的代码。
const fs = require('fs')
const { createCanvas, loadImage } = require('canvas')
const width = 1200
const height = 630
const canvas = createCanvas(width, height)
const context = canvas.getContext('2d')
context.fillStyle = '#000'
context.fillRect(0, 0, width, height)
context.font = 'bold 70pt Menlo'
context.textAlign = 'center'
context.textBaseline = 'top'
context.fillStyle = '#3574d4'
const text = 'Hello, World!'
const textWidth = context.measureText(text).width
context.fillRect(600 - textWidth / 2 - 10, 170 - 5, textWidth + 20, 120)
context.fillStyle = '#fff'
context.fillText(text, 600, 170)
context.fillStyle = '#fff'
context.font = 'bold 30pt Menlo'
context.fillText('flaviocopes.com', 600, 530)
loadImage('./logo.png').then(image => {
context.drawImage(image, 340, 515, 70, 70)
const buffer = canvas.toBuffer('image/png')
fs.writeFileSync('./test.png', buffer)
})