昨年くらいから、このブログArrownのアイキャッチ画像は、ほぼ統一されたフォーマットで作成するようになりました。
具体的には、
- 青系の背景色の上に
- 白文字のテキストを配置する
というシンプルなデザインです。
これまではFigmaにベースフォーマットデザインをおいておき、記事ごとに「テキストを書き換え」→「画像に書き出す」という処理を繰り返していました。
が…!人間とはなんと怠惰な生き物なのか、毎度毎度画像で書き出すのも面倒だなと思うようになってしまったのです。笑
そこで今回は、このシンプルなフォーマットを活かして、Pythonで自動的にアイキャッチ画像を生成する仕組みを作ってみましたので、ブログ記事で紹介させていただきたいと思います!
アイキャッチ画像に載せるテキストのルール
まず、アイキャッチ画像に載せるテキストのルールを考えました。
具体的に考えた内容は以下の通りです。
- テキストの配置ルール
- ほとんどの場合、1行では収まらない
- 4行以上になると読みづらく、ブログタイトルとしても適切ではな
- そのため、2-3行での表示を想定
2. テキストの配置ルール
- 文字サイズは動的に調整可能にする
- 改行位置は「\n」で明示的に指定できるようにする
文字ごとにテキストサイズを変更することは要件として今回は含めないことにしました。
使用したPythonモジュール・Pillow
それでは具体的な実装面に言及していきます!
実装には、Pythonの画像処理ライブラリ「Pillow」を使用しています。
Pillowは画像のサイズ変更、トリミング、明るさ調整など、基本的な画像処理が簡単に行えるライブラリです。
Pythonを使って用いたロジックと実装内容
では、今回の実装ロジックについて言及します。
簡単にいうと、上図のように行ごとにテキストを描画していくというものです。
実装のロジックは至ってシンプルです。
- テキストを改行文字(\n)で分割して配列にする
- 分割したテキストを1行ずつ画像に描画していく
では次に、実際のコードを掲載していきます!なお、今回もArrownではおなじみPythonのフレームワークでFast APIを使っていますが、Fast APIが必須というわけではないので悪しからず。
初期設定部分
まずは、アプリケーションの基本設定を行います。FastAPIを使用していますが、これは必須ではありません。
まず初期設定として、必要なモジュールをインポートし、基本的なパラメータを設定します。
PILというのはPillowモジュールのことです。Pythonコード上ではPILという表記になります。
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
from PIL import Image, ImageDraw, ImageFont
import io
from fastapi.responses import StreamingResponse
app = FastAPI()
次に、アイキャッチ画像の生成に必要なパラメータを定義します。
ブログのアイキャッチ画像には一般的な規格があるため、よく使う値を初期値として設定しています。
class EyecatchRequest(BaseModel):
title: str # タイトルテキスト
width: int = 1200 # 画像の幅(ピクセル)
height: int = 630 # 画像の高さ(ピクセル)
background_color: str = "#3498db" # 背景色(青系)
text_color: str = "#ffffff" # テキスト色(白)
font_size: int = 60 # フォントサイズ
line_spacing: float = 1.75 # 行間
画像生成の本体部分は、create_eyecatch関数として実装します。
この関数では、以下の手順で画像を生成します:
- 指定されたサイズと背景色で空の画像を作成
- テキストを改行文字で分割
- 画像の中央に各行のテキストを配置
def create_eyecatch(request: EyecatchRequest):
# 背景画像の作成
image = Image.new('RGB', (width, height), color=background_color)
draw = ImageDraw.Draw(image)
# フォントの設定
font = ImageFont.truetype("fonts/NotoSansCJKjp-Bold.ttf", font_size)
# タイトルを改行で分割
lines = title.split('\n')
# テキスト全体の高さを計算(行間を含む)
total_text_height = request.font_size * (len(lines) - 1) * request.line_spacing + request.font_size
# 開始位置を計算(垂直方向の中央)
text_line_y = (height - total_text_height) / 2
# 各行を描画
for line in lines:
# 中央揃え(anchor="mm")で描画
draw.text(
(width/2, text_line_y),
line,
font=font,
fill=text_color,
anchor="mm" # 中央揃えの指定
)
# 次の行の位置へ移動
text_line_y += font_size * line_spacing
return image
最後に、APIエンドポイントを設定して、画像生成処理を呼び出せるようにします:
@app.post("/generate_eyecatch")
async def generate_eyecatch(request: EyecatchRequest):
try:
# 画像を生成
image = create_eyecatch(request)
# 画像をバイナリデータとして保存
img_byte_arr = io.BytesIO()
image.save(img_byte_arr, format='PNG')
img_byte_arr.seek(0)
# 画像を返す
return StreamingResponse(img_byte_arr, media_type="image/png")
except ValueError as e:
raise HTTPException(status_code=400, detail=f"Invalid input: {str(e)}")
except Exception as e:
raise HTTPException(status_code=500, detail=f"Image generation failed: {str(e)}")
これで、APIにPOSTリクエストを送ることで、自動的にアイキャッチ画像を生成できるようになりました!
例えば以下のようなJSONデータを送信します。
{ "title": "Pythonで作る\nブログアイキャッチ自動生成の仕組み", "background_color": "#3498db", "text_color": "#ffffff" }
すると、自動的に2行のテキストが中央揃えで配置された画像が生成されるというわけですね!
まとめ
ということで、今回はPython(Pillowモジュール使用)で作るブログアイキャッチ自動生成の仕組みを書かせていただきました!
デスクトップアプリにするなど色々な工夫もできると思うので、引き続きこのアプリは改善して多機能にしていきたいと思います!
とりあえず画像書き出しが手間だったので!笑
これが改善されるだけでもGoodでした!