Pulog

PHP(Drupal 8, 9)でQiitaの様に自動でOGP画像を生成する

サイトをリニューアルしました のタイミングで、記事画像の自動生成機能を開発しているので、どの様に実装したかを紹介します。

ゴール

  • PHP側で自動的に記事一覧用画像兼OGP画像を生成したい
  • PHP側で画像にタイトルテキストを重ねて新しい1つの画像として表示させたい
  • 上記の要件をDrupal 8, 9のコンテンツを保存するタイミングで画像を生成させる

実装

GitBucketでソースを公開しているので、そちらを参照いただければと思います。

https://git.pu10g.com/root/pu10g-image

解説

コンテンツを公開するタイミングで画像を生成したいので、当記事 Drupal 8, 9でコンテンツを保存する際に前処理を挟む で紹介した様に hook_entity_presave を使用します。

また、コンテンツを一時保存するタイミングでは画像を生成する処理を走らせたくないので、 Entitypublishedinterface::isPublished を用います。

EntityPublishedInterface::isPublished | EntityPublishedInterface.php | Drupal 9.0.x | Drupal API

今回一番重要な、PHPで画像にテキストを重ねて新しく画像を生成する方法として imagettftext を使用しています。

PHP: imagettftext - Manual

テキストを画像の中心に置く実装など、詳細な実装は上記のGitBucketのリンクから見れますが、この記事でも簡単に画像にテキストを重ねる処理を紹介しておきます。

<?php
// png画像をリソースとして読み込む
$imageSource = imagecreatefrompng('image.png');
// テキストを追加
imagettftext(
  $imageSource, // 画像のソースを指定
  40, // フォントサイズを指定
  0, // テキストを描画する方向を指定
  0, // 画像の左上を起点とする x軸座標の指定
  0, // 画像の左上を起点とする y軸座標の指定
  imagecolorallocate($imageSource, 0, 0, 0), // テキストの色を指定(今回は黒を指定している)
  'NotoSansCJKjp-Black.ttf', // テキストフォントの指定(サーバーにフォントファイルを用意する必要がある)
  'テキストテキストテキスト' // 画像に書き込むテキストの指定
);
// 画像をpng形式で出力する
imagepng($imageSource, 'image_add_text.png');

上記の実装だと、この実装が書かれているphpファイルと同じディレクトリにある image.png をベースに、黒テキストで左上に NotoSansCJKjp-Black.ttf フォントで テキストテキストテキスト とテキストを書いて image_add_text.png として画像を生成している処理となります。

問題点 日本語のわかち書き

画像に書くテキストが1行であれば特に問題ないのですが、テキストが長い場合は開業する必要が出てくるのですが、PHP側では日本語の適切な改行位置や禁則処理などのルールに基づいた改行はよしなにやってくれないので、こちらも独自で対応する必要がありました。

英語であれば単語と単語の間に半角スペースが入るので、改行を挟みやすいのですが、日本語となるとそうもいかないのです……

日本語のわかち書き対応前の状態

※左側中央の画像とかわかりやすいと思います、 Drupal 8のSearch[改行]モジュールの挙動について となってくれていれば自然ですが Drupal 8のSearchモ[改行]ジュールの挙動について と、残念な具合になっています。

日本語のわかち書き対応方法

TinySegmenter というものを利用して分かち書き対応しました。

TinySegmenter のPHP移植版があるのでそちらを利用させていただきました。

文章を単語に分割する(TinySegmenter PHP移植版) :: OMIMO.net/デザインとクラフトワークと、写真と映像と、少しのプログラム

これを用いることで形態素解析ツールやらサーバーやらを用意せずとも、PHPで分かち書きの処理をPHPだけで完結することができました。

日本語のわかち書き対応後

まとめ

わかち書きの問題をとりあえずクリアし、実際にサイトリニューアルの際に機能として組み込むことができました。
ただ、まだ問題点があるので、引き続き必要に応じて修正または運用で回避といった状態です。

上記で紹介した、TinySegmenter のPHP移植版ですが、2013年に移植されて以来メンテナンスを含むバグ修正などが行われていないようなので、自分の方で本家TinySegmenter(JavaScriptで作られているらしい)を見てイチから移植し直してみようかと思案中です。

こういった細かい改修は実際にブログ閲覧してくださっている方には見えづらいとは思いますが、これからも引き続きブログの改善を進めてまいりますので、今後ともPulogをよろしくお願いいたします。