改善 Twitter 卡片的一個故事
我會在 Twitter 上分享我的博客文章,曾經有一段時間,我為每篇博文畫了一張圖片。
我設置了 Hugo,使其使用存儲在帖子文件夾中的 banner.png
或 banner.jpg
圖片作為開放圖形圖片,如下所示:
<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 實現,我們在瀏覽器中非常熟悉和喜愛。
換句話說,我用來生成圖片的所有內容在瀏覽器中也可以運行。
只是,我們不是從 <canvas>
HTML 元素獲取 Canvas 實例,而是載入庫,從中獲取 createCanvas
函數:
const { createCanvas } = require('canvas')
然後,我調用此函數,傳遞 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()
在 canvas 上繪製文本:
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 中,你按照順序將東西一個接一個地繪製在頂部。
很酷!現在,我希望在底部顯示我的網站 URL:
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()
將其繪製到 canvas 上:
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)
})