Hugo で作成したサイトの記事ごとの OGP 画像を GitHub Actions で生成する

Dec 29, 2021 ( Feb 11, 2022 更新 )

こちらの記事Hugo で管理しているブログを GitHub Pages から Firebase Hosting に移行した話を書いたのですが、このタイミングで OGP 画像にも対応したのでやり方を書いておきます。

OGP 画像とは

OGP とは Open Graph Protocol の略称で、めちゃくちゃ雑に説明すると SNS 等でリッチコンテンツを生成するための HTML の meta タグの仕様です。

<meta property="og:site_name" content="IMDb" /> のような感じで、 propertyog:xxx を付与して色々なメタ情報を宣言していくことができます。

https://ogp.me/

Twitter だと OGP にも対応しつつ、Twitter Card という仕様でも Twitter で URL を展開する場合に引用される情報を規定しています。

Twitter Card を設定していると、以下のように Twitter 上で展開されます:

ImageMagick で任意のテキストを配置した画像を生成する

今回追加したい OGP 画像についてやりたいことは、

  • 記事ごとに画像を生成したい
    • 画像には記事のタイトルを入れたい
  • 記事を公開したら自動的に OGP 画像が生成されるようにしたい

でした。

記事ごとの画像の生成については、ImageMagick を使ってブログ記事で使う共通の画像に記事のタイトルを追加する方法をとることにしました。 ImageMagick ではテキストを扱う機能も提供しており、ここのページにも例が沢山載っています1

まずは記事で共通の画像を作らなければいけないのですが、 Adobe Creative Cloud Express というブラウザ上で画像編集できるサービスを使って作ってみました。 基本的に無料なのですが、フォントを自分で用意したい場合は有料プランにする必要があります。3ヶ月は無料で試せるようです。

こんな感じでアイコンの画像をアップロードしたり、テキストを配置したりしてイメージを固めました。

編集が終わったら、記事のタイトル部分のパーツは一旦削除して画像に書き出します。

この画像を使って、ImageMagick で任意のテキストを追加していきます。

LC_CTYPE="ja_JP.UTF-8" convert \
  -fill '#333333' \
  -gravity west \
  -size 1000x320 \
  -font NotoSansJP-Black.otf \
  caption:'色即是空の教義は 2000 年の時を超えて Event Sourcing Model として受け入れられている' \
  base.png \
  +swap \
  -geometry +80+50 \
  -composite out.png

改行位置がイマイチですが…、これで任意のテキストを入れて画像を生成することはできました。

Hugo の記事ごとに OGP 画像を生成する

Hugo の記事ごとの画像は、以下のように配置していくことにしました。

public
└── images
    └── meta
        ├── og
        │   ├── blog-ja
        │   │   ├── choco60
        │   │   │   └── og.png
        │   │   │ 
        │   ...  ...
        └── twitter
            ├── blog-ja
            │   ├── choco60
            │   │   └── twitter-card.png
            ...  ...

画像のURL としては {デプロイ先のベース URL}/images/meta/{og|twiter}/{ページの relational path} となります。

Hugo のテーマファイルに meta タグを追加する

Hugo のテーマファイルの記事の HTML 部分に、 OGP 画像の meta タグを追加します。

前述した画像の配置場所を指すようにテンプレート変数を交えて書いていきます。

<meta name="twitter:image" content="{{ .Site.BaseURL }}images/meta/twitter{{ relURL .Permalink }}twitter-card.png" />

GitHub Actions で OGP を生成する step を追加する

  • 記事ごとの画像の生成
  • Hugo で生成される HTML の meta タグ設定

ができたので、CI で自動的にこの画像が追加されるようにしていきます。

今回はブログを管理しているリポジトリに、以下のように画像生成用のスクリプトや必要なファイルを置きました。

tools
├── ogp
│   ├── NotoSansJP-Black.otf
│   ├── base.png
│   └── generate.sh
...

画像生成のシェルスクリプトはこんな感じです。かなりやっつけですが…。 全部のコンテンツの画像を生成するのでかなり無駄がありますが、まあ後で直せばいいでしょう!

#!/bin/bash -xe

# $1 = caption text
# $2 = path to save an image
cnv() {
  LC_CTYPE="ja_JP.UTF-8" \
    convert  -fill '#333333' \
     -gravity west \
     -size 1000x320 \
     -font tools/ogp/NotoSansJP-Black.otf \
     caption:"$1" \
     tools/ogp/base.png \
     +swap \
     -geometry +80+50 \
     -composite \
     $2
}
export -f cnv

# $1 = target; format is {title},{permalink}
generate() {
  TITLE=$(echo $1 | cut -d',' -f 1)
  DIRPATH=$(echo $1 | cut -d',' -f 2 | awk '{gsub("https://blog.mookjp.io/", ""); print}')
  TWITTER_DIRPATH=public/images/meta/twitter/${DIRPATH}
  OG_DIRPATH=public/images/meta/og/${DIRPATH}
  mkdir -p ${TWITTER_DIRPATH}
  mkdir -p ${OG_DIRPATH}
  cnv "${TITLE}" ${TWITTER_DIRPATH}twitter-card.png
  cnv "${TITLE}" ${OG_DIRPATH}og.png
}
export -f generate

hugo list all | tail -n +2 | awk -F ','  'BEGIN {OFS=","} { if ($7 == "false")  print $3,$8 }' |\
  xargs -P 12 -I {} bash -c 'generate "$@"' _ {}

これを Github Actions の Workflow で実行できるように yaml を編集します。

  • ImageMagick のインストール
  • 画像生成スクリプトの実行

という step を書いています:

name: Deploy to Firebase Hosting on main branch
'on':
  push:
    branches:
      - main
jobs:
  build_and_preview:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - name: Install dependencies
        run: sudo apt-get update && sudo apt-get install -y imagemagick
      - name: Setup Hugo
        uses: peaceiris/actions-hugo@v2
        with:
          hugo-version: '0.91.2'
      - name: Build pages
        run: hugo --minify -t simple
      - name: Build OGP images
        run: ./tools/ogp/generate.sh
      - name: Deploy
        uses: FirebaseExtended/action-hosting-deploy@v0
        with:
          repoToken: '${{ secrets.GITHUB_TOKEN }}'
          firebaseServiceAccount: '${{ secrets.FIREBASE_SERVICE_ACCOUNT_FOOBAR }}'
          channelId: main
          projectId: foobar

こんな感じで、Hugo で管理しているサイトで OGP 画像を用意することができました。

結構やっつけなので、

  • 更新した記事のみ、画像を再生成したい
  • GitHub Actions でキャッシュ使いたい

とか改良ポイントはあるのですが、また後々直していけばよいかなと思います。


  1. サブドメインが legacy になっている…のですが、新しいバージョンの 7.1.0 でもこのページで紹介されている例は使えました。もっといいやり方はあるかもしれませんが深追いしていません。 ↩︎

Return to top