はじめに
Hugo v0.90.0から,images.Text
により画像に文字を合成した画像を生成できるようになりました。これにより,Qiitaとかみたいに画像中にタイトルとかを記述したOGP/Twitter Cardを自動生成できるようになりました。
この記事では最終的に次のような画像が生成されるようにします。
準備
まずHugoを0.90.0
以上にアップデートしてください。文字を合成する前の元画像を用意します。Twitter CardのLarge Summary Imageの推奨サイズが800 x 418 pxらしいのでそのサイズで用意しました。
画像生成
テキスト
と書いた画像を生成する場合次のようにしたら良いです。この例ではGoogle FontsのGitHubからresources.GetRemote
を使ってNotoSansJP-Bold.otf
を読み取りフォントをNotoSansJP Boldにしています。OGPの元画像として,static/images/ogp/ogp.png
にある画像を読み込んでいます。static/
にあるファイルにアクセスするためにconfig.toml
でassetDir = "static"
と設定してます。(images.Text ... (dict ...))
は見ての通りテキストの位置や大きさなどを設定しています。最後に$img.RelPermalink
で画像のリンクを取得します。
static/images/ogp/...
にある画像を参照することで,hugo
を実行した時に生成される画像はimages/ogp/...
になるので都合がいいので僕はこうしてます。
1
2
3
4
5
6
7
8
9
10
11
|
{{ $font := resources.GetRemote "https://github.com/google/fonts/raw/main/ofl/notosansjp/NotoSansJP-Bold.otf" }}
{{ $img := resources.Get "images/ogp/ogp.png" }}
{{ $img = $img | images.Filter
(images.Text "テキスト" (dict
"color" "#ff3300"
"size" 32
"x" 50 "y" 200
"font" $font
))
}}
<img src="{{ $img.RelPermalink }}" />
|
英文のようにスペースが入る文章なら,改行処理を行ってくれますが,和文のようにスペースが入らない文章では最初に改行が入ってそのままはみ出してしまいます。
英文の場合 |
和文の場合 |
|
|
そこで,長いタイトルの場合はみ出す分を切り取りこのようにします。
実際のソースコードを使って説明します。記事のタイトル以外に,ブログ名やカテゴリについても書きます。
4–8行目ではタイトルが長い場合に切り取っています。標準のタイトル文字数を22として,タイトルに英字を入れたことを考慮して手動で文字数を設定できるようにしています(5行目)。
date
は.Date.Format
で形式を指定します。categories
とtags
はループでカンマ区切りの1つのStringにまとめます。
$title
,$categories
とかを複数の(images.Text ...)
使って,同時に書きます。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
|
{{ $font := resources.GetRemote "https://github.com/google/fonts/raw/main/ofl/notosansjp/NotoSansJP-Bold.otf" }}
{{ $img := resources.Get "images/ogp/ogp-post.png" }}
{{ $title := .Title }}
{{ $strlen := 22 }}
{{ if .Params.strlen }}{{ $strlen = .Params.strlen }}{{ end }}
{{ if gt (strings.RuneCount $title) (add $strlen 1) }}
{{ $title = printf "%s…" (substr $title 0 $strlen) }}
{{ end }}
{{ $date := .Date.Format "2006 年 1 月 2 日" }}
{{ $categories := "" }}
{{ range .Params.categories }}{{ $categories = printf "%s, %s" $categories . }}{{ end }}
{{ $categories = substr $categories 2 }}
{{ $tags := "" }}
{{ range .Params.tags }}{{ $tags = printf "%s, %s" $tags . }}{{ end }}
{{ $tags = substr $tags 2 }}
{{ $img = $img | images.Filter
(images.Text .Site.Title (dict
"color" "#333"
"size" 32
"x" 90 "y" 19
"font" $font
))
(images.Text $title (dict
"color" "#333"
"size" 32
"x" 25 "y" 135
"font" $font
))
(images.Text $date (dict
"color" "#666"
"size" 24
"x" 80 "y" 230
"font" $font
))
(images.Text $categories (dict
"color" "#666"
"size" 24
"x" 80 "y" 280
"font" $font
))
(images.Text $tags (dict
"color" "#666"
"size" 24
"x" 80 "y" 330
"font" $font
))
}}
|
このように画像が出力されます。タイトルに英数字が入っているため,文字数の割に幅が狭いので,strlen: 34
と設定しています。
このブログではこんな感じでOGP/Twitter Cardを設定しています。
1
2
3
4
5
6
7
8
9
10
|
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:site" content="@Daiji256" />
<meta name="twitter:title" content="{{ .Title }} - {{ .Site.Title }}" />
<meta name="twitter:image" content="{{ $img.RelPermalink | absURL }}" />
<meta property="og:url" content="{{ .Permalink }}" />
<meta property="og:type" content="article" />
<meta property="og:title" content="{{ .Title }} - {{ .Site.Title }}" />
<meta property="og:description" content="{{ .Summary }}" />
<meta property="og:site_name" content="{{ .Site.Title }}" />
<meta property="og:image" content="{{ $img.RelPermalink | absURL }}" />
|
おまけ
ホームやカテゴリ/タグのページのような投稿日やカテゴリとかと無縁なページでは以下のように画像を生成するようにしました。
元の画像 |
出力画像 |
|
|
このようにホーム等のページでは.Params.tags
が設定されないので,それを判定して2種類の画像生成を分岐するようにしました。
1
2
3
4
5
|
{{ if or .Params.tags .Params.categories }}
<!-- カテゴリ,タグがある場合 -->
{{ else }}
<!-- カテゴリ,タグがない場合 -->
{{ end }}
|
追記
こんな風にちゃんとできてました!
文献
- Hugo releases/v0.90.0 (GitHub)