HUGO v0.90.0で追加されたimages.TextでブログカードとOGP画像を自動生成する
HUGOのv0.90.0からimages.Text
を使って、画像と文字を合成した画像を生成できるようになりました。images.Text
を使うと、記事ファイル内のテキスト情報を埋め込んだ画像を自動で生成できそうです。
この記事では、記事ファイルのFrontmatterの情報とimages.Text
を使って、生成したブログカードの画像を一覧に表示したり、OGP画像として設定することを試してみました。
動作を確認した環境
HUGO v0.90.0
img.Textの使い方を確認する
img.Text
は、Image Filtersの引数として渡すための関数です。
参考:ドキュメントのサンプルimg.Text
に渡されたテキストリソースと指定した画像を、Image Filtersを使って合成します。
{{ $img := resources.Get "/images/background.png"}}
{{ $img = $img.Filter (images.Text "Hugo rocks!" (dict
"color" "#ffffff"
"size" 60
"linespacing" 2
"x" 10
"y" 20
))}}
実装のイメージ
画像ファイルは、Frontmatterのimage
で指定し、テキストにはtitle
を指定します。
---
title: 福岡の美味しいラーメン
image: ramen.jpg
---
## 福岡といえばとんこつ
記事や画像ファイルは、次のように配置しました。
$ tree content
content
└── post
├── _index.md # 一覧ページ
├── gourmet.jpg
├── ramen.jpg
├── ramen.md # 記事ページ
├── udon.jpg
└── udon.md # 記事ページ
以降の説明では、hugo new theme THEME_NAME
で生成した空のテンプレートに実装することを想定しています。
一覧ページに記事情報から生成したブログカードを表示する
リストテンプレートの実装
それぞれの記事から、ブログカードの画像を作成し表示するリストページを作ります。
{{- define "main" }}
<h1>{{ .Title }}</h1>
{{ $font := resources.Get "https://github.com/google/fonts/raw/main/ofl/notosansjp/NotoSansJP-Black.otf" }}
{{ range .RegularPages }}
<div>
{{- $img := .Page.Parent.Resources.GetMatch (.Params.image) }}
{{- $title := .Title }}
{{- with $img }}
{{- $options := images.Text $title (dict "color" "#eee" "size" 30 "y" 120 "font" $font) }}
{{- $img = $img.Fill "600x315 Center" | images.Filter $options }}
<div><img src="{{ $img.RelPermalink }}" alt="ブログカード" ></div>
{{- end }}
<div>
<a href="{{ .Permalink }}">{{ .Date.Format "2006-01-02" }} | {{ .Title }}</a>
</div>
</div>
{{ end -}}
{{ end -}}
- 6行目: Frontmatterの
image
(.Params.image
)で指定されたパスから画像を取得する - 7, 9行目:テキスト情報には記事のタイトル(
.Title
)を使う - 10行目:
images.Text
で生成したテキストを元の画像に合成する
動作確認
http://localhost:1313/posts/
を確認してみます。
それぞれの記事のタイトルを埋め込んだブログカードの画像が一覧に表示されていました。
生成した画像をOGP画像に設定する
head内に表示するテンプレートの実装
同様に、生成した画像のパスをOGPのメタ情報として指定します。
<meta property="og:type" content="article">
<meta property="og:title" content="{{ .Title }}">
<meta property="og:description" content="{{ .Description }}">
<meta property="og:site_name" content="{{ .Site.Title }}">
{{- $font := resources.Get "https://github.com/google/fonts/raw/main/ofl/notosansjp/NotoSansJP-Black.otf" }}
{{- $img := "" }}
{{- if .IsPage }}{{- $img = .Page.Parent.Resources.GetMatch (.Params.image) }}
{{ else if .IsSection }}{{- $img = .Page.Resources.GetMatch (.Params.image) }}
{{ end }}
{{- $title := .Title }}
{{- with $img }}
{{- $option := images.Text $title (dict "color" "#eee" "size" 30 "y" 120 "font" $font) }}
{{- $img = $img.Fill "600x315 Center" | images.Filter $option }}
<meta property="og:image" content="{{ $img.RelPermalink }}">
{{ end -}}
- 7, 8行目:記事ページと一覧ページでは、リソースにアクセスする方法が違います。そのため、それぞれに合った方法で画像を取得します。
動作確認
ローカルでOGP情報を確認できるChrome拡張Social Share Previewを使って、プレビューしてみます。
一覧ページのOGPのプレビュー(http://localhost:1313/posts/
)
記事ページのOGPのプレビュー(http://localhost:1313/posts/udon/
)
それぞれ、記事の情報に合わせたOGP画像を設定できました。
気になったこと
今回、実装してみて気になったのは、次の点です。
- テキストが長い場合、画像の幅に合わせてサイズを縮小してくれない
- Frontmatterからフォントサイズや位置情報を渡せば解決しそう
- フォントファイルを取得するときに、キャッシュが効いているか