-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
1 changed file
with
95 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
--- | ||
title: OGP対応をした | ||
created: 1592735118538 | ||
tags: [amdxg] | ||
--- | ||
|
||
こんな感じ | ||
|
||
![](https://i.gyazo.com/8ca7358293d7f1e46a1a7e974d023f2c.png) | ||
|
||
## やり方 | ||
|
||
- `node-canvas` でタイトルを元にした画像を `public/ogp/[slug].png` に生成 | ||
- `<meta property="og:image" content="<url>">` でその出力画像を指定 | ||
- 他、`og:title` や `og:url`, `<meta name="twitter:card" content="summary_large_image" >` を追加 | ||
|
||
## 画像生成スクリプト | ||
|
||
特に理由がないが node@14 の mjs で書いた。 | ||
|
||
```tsx | ||
// script/generate-ogp.mjs | ||
import canvas from "canvas"; | ||
import fs from "fs/promises"; | ||
import path from "path"; | ||
|
||
const W = 600; | ||
const H = 315; | ||
const LINE_HEIGHT = 30; | ||
|
||
function getRows(ctx, text) { | ||
const words = text.split(" "); | ||
|
||
let rows = []; | ||
let currentRow = []; | ||
let tokens = words.slice(0); | ||
let token; | ||
while ((token = tokens.shift())) { | ||
const mText = [...currentRow, token].join(" "); | ||
const measure = ctx.measureText(mText); | ||
if (measure.width <= W) { | ||
currentRow.push(token); | ||
} else { | ||
rows.push(currentRow.slice()); | ||
currentRow = [token]; | ||
} | ||
} | ||
if (currentRow.length > 0) { | ||
rows.push(currentRow); | ||
} | ||
|
||
return rows; | ||
} | ||
|
||
function renderText(ctx, rows) { | ||
const rowCount = rows.length; | ||
for (let i = 0; i < rowCount; i++) { | ||
const rowText = rows[i].join(" "); | ||
const m = ctx.measureText(rowText); | ||
|
||
const w = (W - m.width) / 2; | ||
// const h = (LINE_HEIGHT + 12) * (i + 1); | ||
const h = 40 + 210 / 2 - (LINE_HEIGHT + 12) * (rowCount - i - 1); | ||
|
||
ctx.fillText(rowText, w, h); | ||
} | ||
} | ||
|
||
async function generateImage(text, outputPath) { | ||
const cvs = canvas.createCanvas(W, H); | ||
const ctx = cvs.getContext("2d"); | ||
ctx.font = `${LINE_HEIGHT}px Impact`; | ||
|
||
const rows = getRows(ctx, text); | ||
|
||
ctx.fillStyle = "white"; | ||
ctx.fillRect(0, 0, W, H); | ||
|
||
ctx.fillStyle = "black"; | ||
renderText(ctx, rows); | ||
|
||
const m = ctx.measureText("mizdev"); | ||
ctx.fillText("mizdev", (W - m.width) / 2, 250); | ||
const buf = cvs.toBuffer(); | ||
await fs.writeFile(outputPath, buf); | ||
} | ||
|
||
async function main() { | ||
// const out = path.join(dirname, "../public/ogp/", p.slug + ".png"); | ||
await generateImage("ここにタイトルを入れる", "ogp-image.png"); | ||
console.log("[gen:ogp]", out); | ||
} | ||
|
||
main(); | ||
``` |