Skip to content

Commit 02aa3a3

Browse files
committed
Update
1 parent 282c8e6 commit 02aa3a3

1 file changed

Lines changed: 95 additions & 0 deletions

File tree

docs/202006211925-support-ogp.mdx

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
---
2+
title: OGP対応をした
3+
created: 1592735118538
4+
tags: [amdxg]
5+
---
6+
7+
こんな感じ
8+
9+
![](https://i.gyazo.com/8ca7358293d7f1e46a1a7e974d023f2c.png)
10+
11+
## やり方
12+
13+
- `node-canvas` でタイトルを元にした画像を `public/ogp/[slug].png` に生成
14+
- `<meta property="og:image" content="<url>">` でその出力画像を指定
15+
- 他、`og:title``og:url`, `<meta name="twitter:card" content="summary_large_image" >` を追加
16+
17+
## 画像生成スクリプト
18+
19+
特に理由がないが node@14 の mjs で書いた。
20+
21+
```tsx
22+
// script/generate-ogp.mjs
23+
import canvas from "canvas";
24+
import fs from "fs/promises";
25+
import path from "path";
26+
27+
const W = 600;
28+
const H = 315;
29+
const LINE_HEIGHT = 30;
30+
31+
function getRows(ctx, text) {
32+
const words = text.split(" ");
33+
34+
let rows = [];
35+
let currentRow = [];
36+
let tokens = words.slice(0);
37+
let token;
38+
while ((token = tokens.shift())) {
39+
const mText = [...currentRow, token].join(" ");
40+
const measure = ctx.measureText(mText);
41+
if (measure.width <= W) {
42+
currentRow.push(token);
43+
} else {
44+
rows.push(currentRow.slice());
45+
currentRow = [token];
46+
}
47+
}
48+
if (currentRow.length > 0) {
49+
rows.push(currentRow);
50+
}
51+
52+
return rows;
53+
}
54+
55+
function renderText(ctx, rows) {
56+
const rowCount = rows.length;
57+
for (let i = 0; i < rowCount; i++) {
58+
const rowText = rows[i].join(" ");
59+
const m = ctx.measureText(rowText);
60+
61+
const w = (W - m.width) / 2;
62+
// const h = (LINE_HEIGHT + 12) * (i + 1);
63+
const h = 40 + 210 / 2 - (LINE_HEIGHT + 12) * (rowCount - i - 1);
64+
65+
ctx.fillText(rowText, w, h);
66+
}
67+
}
68+
69+
async function generateImage(text, outputPath) {
70+
const cvs = canvas.createCanvas(W, H);
71+
const ctx = cvs.getContext("2d");
72+
ctx.font = `${LINE_HEIGHT}px Impact`;
73+
74+
const rows = getRows(ctx, text);
75+
76+
ctx.fillStyle = "white";
77+
ctx.fillRect(0, 0, W, H);
78+
79+
ctx.fillStyle = "black";
80+
renderText(ctx, rows);
81+
82+
const m = ctx.measureText("mizdev");
83+
ctx.fillText("mizdev", (W - m.width) / 2, 250);
84+
const buf = cvs.toBuffer();
85+
await fs.writeFile(outputPath, buf);
86+
}
87+
88+
async function main() {
89+
// const out = path.join(dirname, "../public/ogp/", p.slug + ".png");
90+
await generateImage("ここにタイトルを入れる", "ogp-image.png");
91+
console.log("[gen:ogp]", out);
92+
}
93+
94+
main();
95+
```

0 commit comments

Comments
 (0)