如何使用Node.js和Canvas创建和保存图像

关于我如何改善Twitter卡的故事

我在Twitter上分享我的博客文章,有时候我会为每个博客文章绘制图像来娱乐自己。

我设置了Hugo,所以它使用了一个名为banner.png或者banner.jpg存储在post文件夹中,用作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张横幅图片。自从我看到了以编程方式生成它们的想法独立黑客为论坛博客帖子生成这些图像(一个好主意):

因此,在找到横幅图片的灵感之后,我决定为我的每个博客帖子都制作一个自定义横幅。

标语是PNG图片,为了使帖子重点关注主题(“如何使用Node.js和Canvas创建和保存图片”),我将跳过一些部分。

另外,做我所做的事情有很多不同的方式,这只是一种方式。

首先,我们需要什么npm软件包?

只有一个!canvas

npm install canvas

This package provides us a Node.js based implementation of the Canvas API that we know and love in the browser.

In other words, everything I use to generate images also works in the browser.

Except instead of getting a Canvas instance from a <canvas> HTML element, I load the library, get the function createCanvas out of it:

const { createCanvas } = require('canvas')

Then I call this function passing the canvas width and height, which I set to 1200x600:

const width = 1200
const height = 600

const canvas = createCanvas(width, height) const context = canvas.getContext(‘2d’)

Let’s paint it black (casually dropping a Rolling Stones reference):

context.fillStyle = '#fff'
context.fillRect(0, 0, width, height)

Let’s now switch to adding text.

I first pick the Menlo font, big and bold. I align it in the center, then I set the color white.

Finally I call context.fillText() to draw the text on the canvas:

const text = 'Hello, World!'

context.font = ‘bold 70pt Menlo’ context.textAlign = ‘center’ context.fillStyle = ‘#fff’ context.fillText(text, 600, 170)

Let’s draw a blue box behind the text:

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)

We set the textBaseline property to be top to ease the positioning of the rectangle. Then I check how ling the text is, using measureText(), and I draw it using the same coordinates we used to draw the text.

Make sure you draw the rectangle before the text, because in Canvas you draw things one on top of each other, in order:

Cool! Now I want to show my website URL at the bottom:

context.fillStyle = '#fff'
context.font = 'bold 30pt Menlo'
context.fillText('flaviocopes.com', 600, 530)

And I also want to add my logo. To do this, let’s import the loadImage function from the canvas module:

const { createCanvas, loadImage } = require('canvas')

and we call it specifying the logo.png image contained in the same folder where we run the script:

loadImage('./logo.png').then(image => {

})

Once the promise is resolved, we have the image object and we can draw it to the canvas using drawImage():

loadImage('./logo.png').then(image => {
  context.drawImage(image, 340, 515, 70, 70)
})

That’s it! Now we can save the image to an image.png file using the toBuffer() method:

const buffer = canvas.toBuffer('image/png')
fs.writeFileSync('./image.png', buffer)

Here is the full code:

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) })

Download my free Node.js Handbook


More node tutorials: