【記事タイトル入りog:image自動生成】
Pythonでタイトル入りog:imageを自動生成し、SNS流入を強化する

記事イメージ

お疲れ様です。堺です。

SNSで自分のウェブサイトをシェアしてもらいやすくするための仕組み、OGP。特に目を引くための"og:image"は、SNS流入を得るためにはこだわる必要があります。

当ブログはワードプレスなどCMSを一切入れずにスクラッチビルドしていますが、その中で「ブログタイトル入りog:image」をPythonで自動生成する取り組みをしています。

今回は、その手順とコードを共有します。

この記事の目標:ワードプレスなどのCMSが入っていないサイトで、下図のようなブログタイトル入りog:imageをPythonで自動生成、より具体的にはタイトルを画像に書き込むノウハウを共有

当ブログ記事をツイッター等に投稿・プレビューすると、この図のようにタイトル入り画像が表示されるようになっています。
当ブログ記事をツイッター等に投稿・プレビューすると、この図のようにタイトル入り画像が表示されるようになっています
同じく、LINEの場合
同じく、LINEの場合
同じく、Facebookの場合
同じく、Facebookの場合

画像自動生成の手順

ベースとなる画像を用意

先ず↓のような、ブランド情報などを含めてあるベース画像を用意します。

文字を書き込む前のベース画像。固定で表示する部分はこちらで予め書き込みしておきます。
文字を書き込む前のベース画像

フォントファイルを用意

PILライブラリで書き込むために、フォントファイル(ttf)を用意する必要があります。

当ブログでは、フリーで使用可能なGenShinGothic-Bold(源真ゴシック)をありがたく使用させていただいています。

"GenShinGothic-Bold.ttf"などと検索すれば、配布サイトが見つかるかと思います。

必要なPythonライブラリをインストール

コマンドは環境によって異なります。適宜、sudoやpython等のプレフィクス等を追加して環境にライブラリを加えてください。

また、pipのパスが通っていないとエラーになりますのでご注意ください。

コマンドライン/ターミナル
pip install numpy
pip install pillow
pip install opencv-contrib-python

PIL.ImageDraw形式でベース画像を読み込み

読み込み手段はcv2以外にもいくつかありますが、いずれのルートでもPIL.ImageDraw形式に変換できればOKです。

Python
from PIL import Image, ImageFont, ImageDraw
import cv2
import numpy as np


#cv2で画像を3次元配列として読み込み
img = cv2.imread('base.img')
#PIL.ImageDraw形式に変換
img = Image.fromarray(img)
draw = ImageDraw.Draw(img)

PIL.ImageDraw.text関数で文字を書き込み

いよいよ文字を書き込んでいきます。上記のdraw変数に含まれるtext関数を使用します。

各引数は次の通りです。尚、座標は左上位置をX=0、Y=0として計算されます。

draw.text((文字書き込みX座標, 文字書き込みY座標), 書き込む文字列, font=フォントファイルパス, fill=(文字の色R, 同G, 同B, 同A))

Python
#書き込むタイトル文字列を表示する行ごとに区切ったもの
text_lines = ['【ClosedXML操作まとめ】', 'C#でエクセル操作ならClosedXML', 'がオススメ~ その理由も含めて解説']
#文字書き込みの初期位置のy座標
y_offset = 100
#上記プロセスで用意したフォントttfファイルパス
font = 'GenShinGothic-Bold.ttf' 
#書き込む文字のフォントサイズ
font_size = 62

#行ごとに書き込み処理
for text_line in text_lines:
    draw.text((80, offset_to_y), text_line, font=font, fill=(64, 64, 64, 0))
    #Y位置を移動(下方向にずらして改行を表現する)
    y_offset += 77

上記コードを見れば分かる通り、改行に関しては手動で計算する形となっています。

行の長さ、フォントサイズ、改行後の位置などは、実際にコードを実行しながら各数値を調整して決めてください。

書き込みした画像を保存

上記コードの実行により、draw変数の元となったimg変数にtext関数の処理結果が反映されています。

RGBを適切に処理してnumpy、cv2を経由してPILで保存しています。

(cv2で直接保存しても良いのですが、日本語入りパスに対応するために下記のような実装となりました。)

Python
img = np.array(img)
img = cv2.cvtColor(img, cv2.COLOR_RGB2BGR)
Image.fromarray(img).save('result.png')

生成結果。尚、細かいフォントサイズや位置は、上記コード以外にもう少し細かい調整を加えています。
生成結果

生成した画像をSNSリンクに表示する手順

詳しいOGPのセッティングは、詳しい記事が多いので他に譲りますが、下記のようにHTMLのhead部に絶対パスで指定します。

OGPについては、その他の要素(og:url、og:title等)も設定する必要があります。ご注意ください。

HTML
<meta property="og:image" content="https://it.sakai-sc.co.jp/og-images/closedxml.png">

【社内PR】チーム・ウォーク

当ブログで使用しているコード全体

当ブログをビルドするコード全容は私のGithubに公開しています。(↓リンク)

このうち、og-imageを生成する箇所だけを抜粋すると以下の通りです。

上記コードよりも細かい調整や、ベーステキストに対して文字数の計算を行っていることが分かるかと思います。

Python
def generate_og_image(self):
    img = cv2.imread(OG_IMAGE_BASE)
    encode = 'utf-8'
    line_max_chars = 40
    article_title_fulltext_base = self._meta_infomation_map['article_title'].replace('&', '&')

    msg_lines = []
    msg_line_builder = ''
    for i in range(len(article_title_fulltext_base)):
        char = article_title_fulltext_base[i]
        msg_line_builder += char
        if char == '】' or ((char == ')' or char == '-' or char == '、') and len(msg_line_builder)) > 10:
            msg_lines.append(msg_line_builder)
            if char == '】':
                msg_lines.append('')
            msg_line_builder = ''
        elif len(msg_line_builder) >= line_max_chars / 2:
            msg_lines.append(msg_line_builder)
            msg_line_builder = ''
        elif len(msg_line_builder) >= line_max_chars / 2 - 5 and len(article_title_fulltext_base) > i + 1 and (article_title_fulltext_base[i + 1] == '?' or article_title_fulltext_base[i + 1] == '、'  or article_title_fulltext_base[i + 1] == '。'):
            msg_lines.append(msg_line_builder)
            msg_line_builder = ''
    if msg_lines != '':
        msg_lines.append(msg_line_builder)

    img = Image.fromarray(img)
    draw = ImageDraw.Draw(img)

    for i in range(len(msg_lines)):
        font_size = 50
        if i == 0:
            offset_to_y = 100 
            if '【' in msg_lines[i] and len(msg_lines[i].encode(encode)) < line_max_chars:
                font_size = 62
        elif i == 1 and '】' in msg_lines[i]:
            font_size = 62
            offset_to_y += 77
        else:
            offset_to_y += 60
        font = ImageFont.truetype(OG_IMAGE_FONT_FILE, font_size)
        draw.text((80, offset_to_y), msg_lines[i], font=font, fill=(64, 64, 64, 0))
    img = np.array(img)

    return cv2.cvtColor(img, cv2.COLOR_RGB2BGR)

結び

お目通し有難うございました。

この記事の情報により、あなたのサイトへより多いSNS流入がもたらされることをお祈りしております。

記事筆者へのお問い合わせ、仕事のご依頼

当社では、IT活用をはじめ、業務効率化やM&A、管理会計など幅広い分野でコンサルティング事業・IT開発事業を行っております。

この記事をご覧になり、もし相談してみたい点などがあれば、ぜひ問い合わせフォームまでご連絡ください。

皆様のご投稿をお待ちしております。

記事筆者へ問い合わせする

※ご相談は無料でお受けいたします。

この記事へのコメント

ニックネーム(任意)

返信通知先Emailアドレス(任意)

本文


* 感想やご意見等、お気軽にコメントください。但し、公序良俗に反するコメントはお控えください。
* 管理者が承認したコメントはこの箇所に公開させていただく可能性がございます。
* 返信通知先Emailアドレスは、筆者のみに通知され、公開されることはありません。返信通知先Emailを入力された場合は、コメントへの返信をこちらに掲載した際に通知させていただきます。その他の目的には使用いたしません。
* スパム対策のため、コメントは日本語のみ受け付けております。

堺財経電算合同会社 小規模IT構築サービス