くらげになりたい。

くらげのようにふわふわ生きたい日曜プログラマなブログ。趣味の備忘録です。

Cloud Functions + ImageMagickでOPG画像の動的生成してCloud Storageにアップロードする

OGP画像を生成したいな〜と思い、ImageMagickが使えるようなので、いろいろ調べたときの備忘録。

ImageMagickとは

画像を操作したり表示するためのソフトウェアスイート。
コマンドラインでも使えて、バッチ処理とかで一括処理するときに使ったりするやつ。

Cloud Functionsでも使えるらしい。。

やりたかったこと

やりたかったことは、以下の2点

  • ベースの画像に文字を入れたい
  • 文字を入れた画像をCloud Storageにアップロードしたい

OGP画像の動的生成で調べると、

  • HTMLからCanvasを生成してPNG化したり
  • Canvas自体を動的に作ってPNG化したり

する記事が多いけど、

  • ベースの画像が複雑なので、SVGにしにくかったり、
  • OPG画像としてしか使わず、クライアント側で処理させたくない

ので、Cloud Storageだけで完結したかったため、この感じになってる。

できたもの

こんな感じ。
spawnを使うと、ImageMagickのコマンドを実行できるらしい!

const functions = require("firebase-functions");
const admin = require("firebase-admin");
admin.initializeApp();

const spawn = require("child-process-promise").spawn;
const path = require("path");
const os = require("os");

// CONST
const FONT_BOLD = "font/NotoSansCJKjp-Medium.otf";
const FONT_REGULAR = "font/NotoSansCJKjp-Medium.otf";

async function genOgp(req, res) {
  // **************************************************
  // * ImagiMagickで画像生成
  // **************************************************
  const msg = "いれたい文字";
  // ベースの画像
  const template = `img/ogp.png`;
  // 生成した画像のパス。tmpディレクトリに配置する
  const outFile = path.join(os.tmpdir(), `generated_ogp.png`); 

  // ImageMagicで画像生成
  await spawn("convert", [
    "-font", FONT_BOLD,       // フォントの指定。カスタムフォントの場合はパスを指定
    "-pointsize", "38",       // フォントサイズの指定
    "-fill", "white",         // 文字色の指定。白文字に設定
    "-gravity", "Center",     // 位置の基準を指定。
    "-annotate", "+0+0", msg, // 文字の指定。+0+0は位置の基準からの相対位置。
    template,                 // 入力画像のパス
    outFile                   // 出力画像のパス
  ]);

  // **************************************************
  // * Cloud Storageへのアップロード
  // **************************************************
  const bucket = admin.storage().bucket();
  const uploadPath = `ogp/generate_ogp.png`; // アップロード先のパス
  await bucket.upload(outFile, { destination: uploadPath });

  // **************************************************
  // * アップロード画像のURLを組み立てる
  // **************************************************
  const STORAGE_ROOT = "https://firebasestorage.googleapis.com/v0/b";
  const bucketName = bucket.name;
  const dlPath = encodeURIComponent(uploadPath);
  const dlURL = `${STORAGE_ROOT}/${bucketName}/o/${dlPath}?alt=media`;

  // return Download URL
  res.send(dlURL);
}

exports.genOgp = functions.https.onRequest(genOgp);

ポイントはいくつか

  1. 日本語に対応したフォントを設定しないと日本語は表示されない。。
  2. firebase-adminを使う場合、storageへのアップロードは、bucket.uploadを使う
  3. 画像のURLは自分で組み立てるほうが楽。署名付きURLだとハマりやすい。。

ローカル実行

エミュレータを実行して、shellで実行確認ができるらしい。

// shellの立ち上げ
$ firebase experimental:functions:shell

// 実行
> genOgp

firebase serveだとHTTPトリガーしか確認しづらいが、
エミュレータだと、Firestoreトリガーとかでも確認できる!

以上!!

参考にしたサイト様