twitterカード画像自動生成機能を記事ごとに動かす twitterカード画像自動生成機能④

· ☕ 2
🏷️
  • #Python
  • #bash
  • #hugo
  • 朝作ったスクリプトをいい感じで自動で動かす方法を考える!

    朝の記事は こちら

    引数を渡す

    まずは、引数渡せるようにして、いい感じのファイルを作れるようにする。

    とりあえずファイル名を指定できるようにする。

    import sys
    
    target = sys.argv[1]
    print(f"target:{target}")
    

    で、

    img.save(f"content/posts/meta_image/{target}.png")
    

    これで、対象の記事に対してスクリプトが動く

    targetのmdからタイトルと内容を取得

    で、マークダウンを読み取る

    もしかしたら、もっといいベストプラクティスがあるのかもしれないけど…。

    とりあえず、テキストとして読み取って、ヘッダー部分をyamlとして読み込み直す

    こんな感じ?

    import yaml
    
    with open(f'content/posts/{target}.md') as f:
        md = f.read().split("---")
        header_yaml = md[1]
        body = md[2]
        header = yaml.load(header_yaml)
        title = header["title"]
    
    

    で、タイトルと、内容を取得

    引数に設定

    実行

    内容設定

    おおお!いいね

    完成(ㅅ´ ˘ `)♡

    ちょっと細かいリファクタリングとか、バグ取りとかして、こんな感じ

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    
    from PIL import ImageFont, ImageDraw, Image
    import sys
    import yaml
    
    
    def add_text_to_image(img, base_text, font_path, font_size, font_color, height, width, line=1, max_length=800, max_height=420):
        font = ImageFont.truetype(font_path, font_size)
        draw = ImageDraw.Draw(img)
        lineCnt = 1
        base_text = base_text.strip()
        base_text = base_text.replace("\n\n", "\n")
        base_text = base_text[0:150]
        break_flg = False
        for lineCnt in range(line):
            text = base_text.split("\n")[0]
            position = (width, height)
            if len(text) == 0:
                break
            if lineCnt == line - 1 or \
                    height + draw.textsize(text, font=font)[1] > max_height:
                if draw.textsize(text, font=font)[0] > max_length:
                    # テキストの長さがmax_lengthより小さくなるまで、1文字ずつ削っていく
                    while draw.textsize(text + '', font=font)[0] > max_length:
                        text = text[:-1]
                    text = text + ''
                    break_flg = True
            else:
                while draw.textsize(text, font=font)[0] > max_length:
                    text = text[:-1]
            base_text = base_text.replace(text, "")
            base_text = base_text.strip()
            height = height + draw.textsize(text, font=font)[1]
            draw.text(position, text, font_color, font=font)
            print(f"draw:{text}")
            if break_flg:
                break
    
        return img, height
    
    
    target = sys.argv[1]
    print(f"target:{target}")
    
    with open(f'content/posts/{target}.md') as f:
        md = f.read().split("---")
        header_yaml = md[1]
        body = md[2]
        header = yaml.load(header_yaml)
        title = header["title"]
    
    base_img_path = "content/posts/meta_image/base.png"
    base_img = Image.open(base_img_path).copy()
    font_path = "content/posts/meta_image/meiryo.ttc"
    font_color = (88, 110, 117)
    height = 155
    width = 30
    
    font_size = 57
    line = 3
    img, height = add_text_to_image(
        base_img, title, font_path, font_size, font_color, height, width, line)
    
    font_size = 35
    height = height + 20
    line = 6
    img, height = add_text_to_image(
        img, body, font_path, font_size, font_color, height, width, line)
    img.save(f"content/posts/meta_image/{target}.png")
    
    

    このまま投稿してみる!

    投稿画面

    出来たヾ(●´∇`●)ノ

    残タスク

    • 今はmdのテキストをそのまま出力しているので、リンクの中身を臭力しないようにするとか♯をいい感じにするとか。
    • shでラッピングして、ビルド時にいい感じに自動生成するようにする。
    • 既にイメージができている時は作りなおさずにスキップする

    とか

    とりあえず、今日はこんなもん。

    よし、夜鳴きそば食べて来ようwww


    るな
    るな
    エンジニア