アイキャッチを作成するツールがいろいろあるのは知っていますが、
会員登録とかもめんどうだし、自分で作ってみるか・・・というのが、
今回やろうと思ったきっかけです。
一から作るのは大変なので、ChatGPTさんに手伝ってもらい、プログラムを作成しました。
目次
どんなものを作るのか
画像を用意して、その画像内に任意の文字を埋め込み、出力できるようなものを作りました。
基になる画像は、photoshopで適当に作りました。何のこだわりもありません。
プログラムを作る流れ
私が、ChatGPTでプログラムを作るときは、最初から完成品を作ってもらおうとはしません。
土台となるプラグラムを作ってもらい、徐々に機能を追加していきます。
そのほうが、プログラムの構造が理解がしやすく、エラーの対応もスムーズだからです。
STEP
プログラムの基本機能を作成してもらう
pythonのプログラムを作成してください。 もとになる1200×630pxのwebp画像があります。
指定した文字列を上下左右中央にセンタリングして入力し、新しい画像として出力するプログラムです。
STEP
機能の追加・修正
- Fontの変更
- 文字位置の調整
- GUI機能の追加
- 文字数に応じてフォントサイズを調整する機能
- 文字のセンタリングをオン/オフする機能
STEP
作成したプログラムのEXE化
作ったプログラム
そんなこんなで、以下のようなGUIアプリケーションが完成しました。
入力画像、出力先画像パス、埋め込む文字列を入力すると、画像が出力されます。
実際に作られたアイキャッチ画像
最終的なプログラム
import tkinter as tk
from tkinter import ttk, filedialog, messagebox
from ttkthemes import ThemedStyle
from PIL import Image, ImageDraw, ImageFont
import os
import sys
def get_font_path():
if hasattr(sys, '_MEIPASS'):
# PyInstallerの実行時
base_path = sys._MEIPASS
else:
# 通常のPythonスクリプトの実行時
base_path = os.path.dirname(os.path.abspath(__file__))
font_path = os.path.join(base_path, 'ttfファイルのパス')
return font_path
def add_text_to_image(input_image_path, output_image_path, text, centering):
img = Image.open(input_image_path)
width, height = img.size
draw = ImageDraw.Draw(img)
# 使用するフォントと初期サイズを指定
initial_font_size = min(width, height) // 5
font = ImageFont.truetype(get_font_path(), initial_font_size)
# フォントサイズを調整
adjusted_font = adjust_font_size(draw, text, font, width, height)
# 描画開始位置
y = (height - draw.textbbox((0, 0), text, font=adjusted_font)[3]) // 2
# 改行ごとにテキストを描画
for line in text.split('\n'):
line_width, line_height = draw.textbbox((0, 0), line, font=adjusted_font)[2:4]
x = (width - line_width) // 2 if centering else 100
draw.text((x, y), line, font=adjusted_font, fill="black")
y += line_height # 次の行の Y 座標を更新
# 新しい画像を保存
img.save(output_image_path)
def adjust_font_size(draw, text, font, max_width, max_height):
current_font_size = font.size
text_bbox = draw.textbbox((0, 0), text, font=font)
while text_bbox[2] - text_bbox[0] > max_width - 200 or text_bbox[3] - text_bbox[1] > max_height - 200:
current_font_size -= 1
font = ImageFont.truetype(get_font_path(), current_font_size)
text_bbox = draw.textbbox((0, 0), text, font=font)
return font
class ImageTextEmbedderGUI:
def __init__(self, master):
self.master = master
master.title("画像に文字列をいれるやつ")
style = ThemedStyle(master)
style.set_theme("yaru")
# スタイル設定
style.configure("White.TEntry", fieldbackground="white")
style.configure("BlackWhite.TButton", background="white", foreground="black", bordercolor="black")
# ウィンドウサイズ変更を無効化
master.resizable(False, False)
# ウィンドウの背景色を白に設定
master.configure(bg="white")
# ウィンドウのサイズ
master.geometry("570x210")
# ラベルとエントリー (入力画像パス)
self.label_input = ttk.Label(master, text="入力画像パス", background="white")
self.label_input.grid(row=0, column=0, pady=(15, 0), padx=(15, 0), sticky="w")
self.entry_input = ttk.Entry(master, style="White.TEntry") # スタイルを設定
self.entry_input.grid(row=0, column=1, columnspan=2, pady=(15, 0), padx=(5, 5), sticky="ew")
self.entry_input.insert(0, "./thumbnail-base.webp")
self.button_browse_input = ttk.Button(master, text="Browse", command=self.browse_input,
style="BlackWhite.TButton") # スタイルを設定
self.button_browse_input.grid(row=0, column=3, pady=(15, 0), padx=(0, 15))
# ラベルとエントリー (出力画像パス)
self.label_output = ttk.Label(master, text="出力画像パス", background="white")
self.label_output.grid(row=1, column=0, pady=(10, 0), padx=(15, 0), sticky="w")
self.entry_output = ttk.Entry(master, style="White.TEntry") # スタイルを設定
self.entry_output.grid(row=1, column=1, columnspan=2, pady=(10, 0), padx=(5, 5), sticky="ew")
self.button_browse_output = ttk.Button(master, text="Browse", command=self.browse_output,
style="BlackWhite.TButton") # スタイルを設定
self.button_browse_output.grid(row=1, column=3, pady=(10, 0), padx=(0, 15))
# ラベルとエントリー (埋め込む文字列)
self.label_text = ttk.Label(master, text="埋め込む文字列", background="white")
self.label_text.grid(row=2, column=0, pady=(10, 0), padx=(15, 0), sticky="w")
self.text_to_embed = tk.Text(master, wrap=tk.WORD, height=4, width=50, bg="white", fg="black") # 背景色とテキスト色を設定
self.text_to_embed.grid(row=2, column=1, columnspan=2, pady=(10, 0), padx=(5, 5), sticky="ew")
# ラベルとエントリー (センタリングスイッチ)
self.centering_var = tk.BooleanVar()
self.centering_var.set(True)
self.checkbox_centering = tk.Checkbutton(master, variable=self.centering_var, background="white")
self.checkbox_centering.grid(row=2, column=3, columnspan=1, pady=(30, 0), padx=(5, 5), sticky="ew")
self.label_above = ttk.Label(master, text="センタリング", background="white")
self.label_above.grid(row=2, column=3, sticky="n", pady=(15, 0))
# 実行ボタン
self.button_embed = ttk.Button(master, text="画像を出力する", command=self.embed_text,
style="BlackWhite.TButton")
self.button_embed.grid(row=5, column=1, columnspan=2, pady=(10, 0), sticky="ew")
def browse_input(self):
file_path = filedialog.askopenfilename(filetypes=[("Image files", "*.png;*.jpg;*.jpeg;*.gif;*.bmp;*.webp")])
self.entry_input.delete(0, tk.END)
self.entry_input.insert(0, file_path)
def browse_output(self):
file_path = filedialog.asksaveasfilename(defaultextension=".webp", filetypes=[("WebP files", "*.webp")])
self.entry_output.delete(0, tk.END)
self.entry_output.insert(0, file_path)
def embed_text(self):
input_path = self.entry_input.get()
output_path = self.entry_output.get()
text_to_embed = self.text_to_embed.get("1.0", tk.END).strip() # 改行を含むテキストを取得
centering = self.centering_var.get() # スイッチの状態を取得
if input_path and output_path and text_to_embed:
add_text_to_image(input_path, output_path, text_to_embed, centering)
messagebox.showinfo("Success", "画像を出力しました。")
else:
messagebox.showerror("Error", "入力漏れがあります。")
if __name__ == "__main__":
root = tk.Tk()
app = ImageTextEmbedderGUI(root)
root.mainloop()
おまけ
一応、基になる画像は切り替えても動きます。少し前に撮影したレインボーブリッジでやってみた。