🌧️

Cloudinaryで動的OGP画像を10分で作る!

2023/08/10に公開

はじめに

皆さんは Cloudinary というサービスをご存知でしょうか?
Cloudinary とは画像を管理するクラウドサービスであり、画像の保存や編集、配信などが手軽に行えるものです。

Cloudinary に動的 OGP 画像のもととなるテンプレート画像をアップロードし、特定の形式の URL を叩けば動的な OGP 画像を簡単に作成できます。
実は Zenn のサービスでも、この Cloudinary が使われていて、Catnose さんも個人ブログの方で紹介されていました!

https://catnose.me/notes/cloudinary-dynamic-ogp-image

本当に 10 分で作成できちゃうくらい簡単なので、動的 OGP 画像の作成に困っている方は是非試してみてください!

早速作る

Cloudinary への登録と 1 つ以上の Cloud が作成された状態であることを前提とします。
https://cloudinary.com/users/login

1. テンプレート画像を作成する

まずは、静的な部分となるテンプレート画像を Figma などで作成して用意します。

↓ こんな感じのやつ(オレンジの線の上に動的なタイトルが来るようにします)
OGPのテンプレート画像

そして、このテンプレート画像を Cloudinary の Media Library にアップロードしておきます。
その際に、アップロードした画像の名前(Public ID)はogp_imageなどわかりやすいものにしておきます。

2. Cloudinary で提供されている SDK を使って OGP の URL を作成する

最終的な OGP Image の URL は以下のような形になります。
https://res.cloudinary.com/dpgixnkg1/image/upload/c_fit/co_rgb:626161,l_text:zen-maru-gothic.ttf_30:%E4%BB%99%E5%8F%B0%E3%81%AB%E8%A1%8C%E3%81%A3%E3%81%9F%E3%82%88/fl_layer_apply,g_west,x_50,y_-30/yajium_site_ogp

これは以下のような形式になっており、Cloudinary 側でなんやかんやしてくれるように特的のフォーマットの文字列にしておく必要があります。
https://res.cloudinary.com/<Cloud名>/image/upload/<アクショングループ>/<テンプレート画像のPublic ID>

まずは、上記の URL をうまいこと作成してくれる Cloudinary の JavaScript SDK をインストールします。

npm install @cloudinary/url-gen
または
yarn add @cloudinary/url-gen
または
pnpm add @cloudinary/url-gen

次に、cloudinary.tsファイルなどを作成し、URL を生成する関数を作成します。

cloudinary.ts
import { Cloudinary } from "@cloudinary/url-gen";

const cld = new Cloudinary({
  cloud: {
    cloudName: "dpgixnkg1", // 自分のCloud Nameに書き換える
  },
});

このように、新しい cloud オブジェクトを生成します。
その際に、cloudName には自分の Cloud Name を書くようにします。

Cloud Name は画像の Dashboard や、
Programmable MediaのDashboardページにあるCloud Name

左下に常に表示されている Product Environment から確認できます。
Product EnvironmentにあるCloud Name

その次に、実際に OGP 画像の URL を取得する関数getOgpImageUrlを作成します。

cloudinary.ts
import { Cloudinary } from "@cloudinary/url-gen";
+ import { source } from "@cloudinary/url-gen/actions/overlay";
+ import { fit } from "@cloudinary/url-gen/actions/resize";
+ import { Position } from "@cloudinary/url-gen/qualifiers";
+ import { compass } from "@cloudinary/url-gen/qualifiers/gravity";
+ import { text } from "@cloudinary/url-gen/qualifiers/source";
+ import { TextStyle } from "@cloudinary/url-gen/qualifiers/textStyle";

const cld = new Cloudinary({
  cloud: {
    cloudName: "dpgixnkg1",
  },
});

+export const getOgpImageUrl = (title: string) => {
+ const ogpImage = cld.image("ogp_image"); // 自分のCloudからアップロードしたテンプレート画像のPublic IDを書く
+ ogpImage
+   .resize(fit()) // fit:タイトル文字列の最大幅に応じて自動的に複数行に折り返す
+   .overlay(
+     source(
+       text(title, new TextStyle("zen-maru-gothic.ttf", 30)).textColor( // カスタムフォントファイルとテキストカラーの指定
+         "#626161"
+       )
+     ).position(
+       new Position().gravity(compass("west")).offsetX(50).offsetY(-30) // タイトル文字列を表示する位置の調整
+     )
+   );

+ return ogpImage.toURL();
+};

この関数の引数として title を受け取るようにします。この title が動的に変化して表示される文字列となります。

コメントに書いてある部分を部分を部分を見ていきます。

まず、ogpImageがテンプレート画像を指す変数になっています。
それに対して.resize().overlay()のメソッドを実行することで画像を加工しています。

.overlay()では、source に text を指定しており、文字の加工が行われています。
new TextStyle("zen-maru-gothic.ttf", 30)では、カスタムフォントの適用をしています。

Cloudinary では、デフォルトの日本語フォントが Sawarabi Gothic しかないため、それ以外のフォントを使いたい場合はカスタムフォントの対応を行う必要があります。
この適用方法に関しては、以下の記事のカスタムフォントを利用するセクションを参考にしてください。
フォントファイルは Google Fonts などでダウンロードができます。

https://www.memory-lovers.blog/entry/2021/09/09/070000

注意点として、フォントファイルの Public ID には「_(アンダースコア)」が使用できません。

.position()部分では、タイトル文字列の位置調整を行なっています。
gravity(compass("west"))では、文字列の初期値がどこかを設定しており、今回の場合はwestなので、文字列の一番左の文字が画像の左端に来るようにしています。

"west"の部分は、以下のように様々な方向で位置調整が行えるようになっています。

declare type ICompassGravity =
  | "north"
  | "center"
  | "east"
  | "west"
  | "south"
  | "north_west"
  | "south_east"
  | "south_west"
  | "north_east";

今回の"west"の状態から、文字列の一番左が、テンプレート画像のオレンジの線の上に揃うようにしたいので、.offsetX(50).offsetY(-30)にして x 座標と y 座標の位置調整をしています。

文字の加工に関しては以下が参考になるので、詳しく知りたい方はご覧ください!
https://cloudinary.com/documentation/javascript_image_transformations#adding_text_and_image_overlays

ちなみに、この公式の SDK を使わず、直で URL 文字列を生成してしまってもいいのですが、タイトルのエンコード処理などを自前でやる必要が出てくるので、今回は SDK を使いました。

3. 作成した URL を ogp のタグに埋め込む

最後に、URL を ogp のタグに埋め込んで完了です!

const ogpImageUrl = getOgpImageUrl(title);
---
<meta property="og:image" content="{ogpImageUrl}" />

↓ 自分のサイトはこんな感じになりました
OGP画像の例(yajium.dayの場合)

終わりに

どうでしたでしょうか?
個人的には vercel/og より簡単にできて、すごく良かったなと思っています。

動的 OGP 画像を作成するときの一候補としてぜひ参考にしてもらえると幸いです 😃

GitHubで編集を提案

Discussion