WordPressのOGPを自動生成したい

python,wordpress

どうも。

僕のブログは全部wordpressなんですが、OGP画像を毎回GIMPなりで作っているわけなんですが、(めんどくさくてパチンコフォントメーカーですませてますが)いいかげんだるいのでPythonでそれっぽいOGPをつくるコードを書きました。

まあ生成っていうよりは特定の画像に文字を書き込むだけです。
まいかいブログタイトルコピペして生成ボタンを押すだけでできるようになったんですよ。今まで行ってたgimpで生成→squooshで圧縮&webp化を楽にするだけのあれです。自動ではないけどね。

ついでにPyinstallerでexeもつくったのでpython使えない人もかってに使ってよいです。自己責任で。

せっかくなのでコードとか共有しておきます。

WordPressのOGPを自動生成()するコード

from PIL import Image, ImageDraw, ImageFont
import PySimpleGUI as sg
import pickle
import os
import re
import itertools
import unicodedata

#フォントのパス
up = r"C:/Users/" + os.getlogin() + r"/AppData/Local/Microsoft/Windows/Fonts"

#画像を生成する関数
def gen(fp,op,t,x,y,s,k,o,b,a):
    #フォントを指定したい
    font = ImageFont.truetype(fp, s)
    #台紙となる画像を指定したい
    im = Image.open(op)
    #画像をこれからいじるよって奴だと思う
    draw = ImageDraw.Draw(im)
    #テキストを指定した文字数で改行したい
    
    #aがTrueなら中央ぞろえしたい
    if a:
        anchor = "ma"
        x = (im.width)/2
        align = "center"
    #ちがうなら左に寄せたい    
    else:
        anchor = "la"
        align = "left"

    #テキストに改行があるなら改行の値は無視したい
    if "\n" in t :
        text = t
    #テキストに改行がないなら改行の値を適応したい
    else:
        text = gentext(k,t,font)
    
    #文字を書き込み処理をしたい
    draw.text((x, y), text, 'black' ,font=font,anchor=anchor,align=align)
    #boldがないフォントでもむりやり太字にしたい
    if b:
        draw.text((x+1,y+1),text,font=font,fill='black',anchor=anchor,align=align)
        draw.text((x-1,y-1),text,font=font,fill='black',anchor=anchor,align=align)
        draw.text((x+1,y-1),text,font=font,fill='black',anchor=anchor,align=align)
        draw.text((x-1,y+1),text,font=font,fill='black',anchor=anchor,align=align)
    else:pass
    #指定した場所にwebpで画像を書き出したい
    im.convert('RGB').save(o+"/gen.webp",quality=75)   

#改行処理
def gentext(k,t,font):
    #テキストを描画した場合の横幅のサイズを特定する
    def tetsize(x):
        draw = ImageDraw.Draw(Image.new("RGB", (1, 1)))
        text_bbox = draw.multiline_textbbox((0, 0), x, font=font)
        return text_bbox[2] - text_bbox[0]

    #テキストを日本語と英語で分割してリストを作る
    def split_text(text):
        tl =  [str(i).split() for i in re.findall(r'[^\u0020-\u007E]+|[\u0020-\u007E]+', text)]
        return list(itertools.chain.from_iterable(tl))

    #指定した文字数分日本語で書いた時の横幅を割り出すための処理
    widthtext = ""
    for i in range(k):
        widthtext += "あ"
    max_width = tetsize(widthtext)
    #テキスト全部の横幅を出す
    text_width = tetsize(t)
        
    if text_width <= max_width:
        # 幅が指定した幅以下の場合、なんもしない
        return t
    else:
        # 幅が指定した幅を超える場合、改行が必要
        
        line = []
        textb = ""
        textlist = split_text(t)

        for i in textlist:
            #textbと今見てるやつの合計幅が最大値を超えてないか確認する
            if  tetsize(textb+i)<=max_width:
                #超えてない場合textbの末にiを足す
                if not len(textb) == 0:
                    #textbの末とiの頭がローマ字だったらスペースを足す
                    if  unicodedata.east_asian_width(textb[-1]) == unicodedata.east_asian_width(i[0]):
                        textb += " "
                textb += i
            #iがローマ字だったらやる処理
            elif unicodedata.east_asian_width(i) == "Na":
                #lineにtexbを追加してtextbをiで上書きする
                line.append(textb)
                textb = i
            else:
                #何でもない場合は一文字づつ足してって最大値を超えたらLineにtextbを加える。
                for w in i:
                    if tetsize(textb+w)>=max_width:
                        line.append(textb)
                        textb = w
                    else:
                        textb += w
        # 一番最後にこれやらんと最後の行が反映されない(それはそう)
        line.append(textb)

    return "\n".join(line)


#前回の値を外部から読み込みたい
try:
        with open('info.pickle', mode='rb') as f:
            mylist = pickle.load(f)
#無理だったら以下のを読みたい
except:mylist = ["","63","252","63","17","","JKG-L_3.ttf","False","False"]

# GUIのレイアウト
layout = [
    [sg.Text('台紙のパス',font=('Meiryo UI',20)),sg.InputText(font=('Meiryo UI',18),size=(25,1),default_text=mylist[0],key="daishi"), sg.FileBrowse(button_text="select...",file_types=("一般な画像ファイル","*.*"))],
    [sg.Text('テキスト',font=('Meiryo UI',20)),sg.Multiline(font=('Meiryo UI',18),size=(25,5),key="text")],
    [sg.Text('フォントのパス',font=('Meiryo UI',20)),sg.InputText(font=('Meiryo UI',18),size=(25,1),default_text=mylist[6],key="font"), sg.FileBrowse(button_text="select...",initial_folder=up)],
    [sg.Text('疑似太字',font=('Meiryo UI',20)),sg.Checkbox("有効化", default=mylist[7],key="bold")],
    [sg.Text('文字の座標(X,Y)',font=('Meiryo UI',20)),sg.InputText(font=('Meiryo UI',18),size=(5,1),key="x",default_text=mylist[1]),sg.InputText(font=('Meiryo UI',18),size=(5,1),key="y",default_text=mylist[2])],
    [sg.Text('中央ぞろえ',font=('Meiryo UI',20)),sg.Checkbox("有効化", default=mylist[8],key="chuoh")],
    [sg.Text('文字のサイズ',font=('Meiryo UI',20)),sg.InputText(font=('Meiryo UI',18),size=(25,1),key="size",default_text=mylist[3])],
    [sg.Text('何文字で改行するか',font=('Meiryo UI',20)),sg.InputText(font=('Meiryo UI',18),size=(25,1),key="kaigyo",default_text=mylist[4])],
    [sg.Text('出力先',font=('Meiryo UI',20)),sg.InputText(font=('Meiryo UI',18),size=(25,1),key="output",default_text=mylist[5]), sg.FolderBrowse(button_text="select...")],
    [sg.Button('生成する',font=('Meiryo UI',20),key='ok')],
    ]
    
# GUIを開く処理をしていると思う
window = sg.Window('OGP GEN', layout, default_element_size=(12, 1))
while True:
    event, values = window.read()
    # ×で閉じる
    if event in (None, 'Quit'):
        window.close()
        break
    # OK押したときの処理
    elif event == 'ok':
        #guiからデータを引っ張りたい
        ogppath = values['daishi']
        txt = values['text']
        font_path = values["font"]
        x = int(values["x"])
        y = int(values["y"])
        size = int(values["size"])
        kaigyo = int(values["kaigyo"])
        output = values["output"]
        bold = values["bold"]
        chuoh = values["chuoh"]
        
        #今回引っ張ったデータをリスト化したい
        mylist = [ogppath,x,y,size,kaigyo,output,font_path,bold,chuoh]
        # 今回入力した値を外部ファイルに書き出しておきたい。
        with open('info.pickle', mode='wb') as f:
            pickle.dump(mylist, f)
        
        gen(font_path,ogppath,txt,x,y,size,kaigyo,output,bold,chuoh)

        window.close()

#πインストーラーのメモ      
#pyinstaller ogp.py --onefile --noconsole

解説

とくになし。

pillowってライブラリをインストールしてpysimpleguiで雑なGUIを作っただけです。

使い方

  1. 台紙のパスで文字を書き込みたい画像を指定する(ドロップできるようにすればよかったわ)
  2. 書き込みたいテキストを入力する。改行が含まれているとそれ通りに改行される。改行無い場合は設定した文字数で自動で改行することができる。
  3. フォントのパスのセレクトを押すと自分がインストールしたフォントを選択できる。PC内臓のフォントを選択する方法がわからんかった。初期値は再配布可能っぽいフリーフォントになってます。exeにはzipで同梱した。exeなりpyなりがおいてある同じ階層にあると使えるとおもいます。
  4. 疑似太文字は、boldのファイルが無いフォントでも疑似的にBOLDにすることができます。boldのフォントがあるならそれを指定した方がいいかも。
  5. 文字を書き込みたい座標を決める
  6. 中央ぞろえしたかったら有効にします。
  7. 文字サイズを決める
  8. 指定した文字を超えると勝手に改行するようになってます。テキスト自体に改行が含まれて場合はそっちが優先されます。
  9. 出力先を指定します。
  10. 生成するを押すと出力先にwebpで吐きます。
  11. パイソンとかexeの同じ階層にinfo.pickelみたいなファイルが生成されます。今回入力した情報を出力して次回以降(同じ階層にあれば)自動で読み込みます。
  12. 初期値は俺のOGPに最適化された値です。
  13. 文字数改行するときに、ローマ字は文字数にカウントしないように変更しました。ローマ字は幅が狭いので、いい感じになるようにしました。ただ単語の途中で改行がはいっちゃうときは、その前に改行します。20230302追加

exe

ついでにワイのOGPの素材(gimpのデータ)も上げとくからロゴとか変えてつかってもいいよ。
あとフリーのフォントデータも突っ込んでるのでダウンロードしたの解凍したらすぐ使えると思います。

あとがき

ためしにこの記事のOGP吐いたんですけど、文字数カウントで改行すると英数字は詰まるので改行がきもくてないたね。スペースでむりやり文字数増やしていい感じに改行したけど(いい感じになったとは言っていない

中央揃えとか改行を認識するようにつくるべきでしたかね。気が向いたらなおします。

偉いから実装した。偉いので。

PHPとかでJavascriptとか使えたらWordpress上で自動生成したりできそうだけどとりあえず手持ちの知識だけでつくりました。

そういうwordpressのプラグイン売ってたけど貧民なので買えないのでこんな感じです。かなしいね。

新人声優ユニットの「CLU+CH」とは? いま沸きたい声系オタクに一番おすすめしたいの現場
ol_pst0590_21

python,wordpress