以下は『浄玻璃鏡』のソースコード全文です:
import os
import tkinter as tk
from tkinter import filedialog, ttk
from PIL import Image, ImageTk
from reportlab.lib.pagesizes import A4, landscape, portrait
from reportlab.pdfgen import canvas
from reportlab.lib.utils import ImageReader
class ContactSheetApp:
def __init__(self, root):
self.root = root
self.root.title("コンタクトシート作成ツール - 浄玻璃鏡")
# 初期変数
self.image_list = []
self.folder_path = ""
self.rows = tk.IntVar(value=4)
self.cols = tk.IntVar(value=3)
self.orientation = tk.StringVar(value="portrait")
# GUI構築
self.build_gui()
def build_gui(self):
frame = ttk.Frame(self.root, padding=10)
frame.grid()
# フォルダ選択
ttk.Button(frame, text="フォルダ選択", command=self.select_folder).grid(row=0, column=0, columnspan=2, sticky="ew")
# 行列選択
ttk.Label(frame, text="行数:").grid(row=1, column=0, sticky="e")
ttk.Combobox(frame, textvariable=self.rows, values=list(range(1, 11)), width=5).grid(row=1, column=1)
ttk.Label(frame, text="列数:").grid(row=2, column=0, sticky="e")
ttk.Combobox(frame, textvariable=self.cols, values=list(range(1, 11)), width=5).grid(row=2, column=1)
# 向き選択
ttk.Label(frame, text="用紙の向き:").grid(row=3, column=0, sticky="e")
ttk.Radiobutton(frame, text="縦 (A4)", variable=self.orientation, value="portrait").grid(row=3, column=1, sticky="w")
ttk.Radiobutton(frame, text="横 (A4)", variable=self.orientation, value="landscape").grid(row=4, column=1, sticky="w")
# プレビューと作成ボタン
ttk.Button(frame, text="プレビュー表示", command=self.preview).grid(row=5, column=0, sticky="ew")
ttk.Button(frame, text="PDF作成", command=self.generate_pdf).grid(row=5, column=1, sticky="ew")
# キャンバス
self.canvas_frame = ttk.Frame(self.root)
self.canvas_frame.grid(row=0, column=1)
self.canvas_label = ttk.Label(self.canvas_frame)
self.canvas_label.pack()
def select_folder(self):
folder = filedialog.askdirectory()
if folder:
self.folder_path = folder
self.image_list = [f for f in os.listdir(folder) if f.lower().endswith((".png", ".jpg", ".jpeg", ".bmp", ".gif"))]
self.image_list.sort()
def preview(self):
if not self.folder_path or not self.image_list:
return
preview_img = self.create_contact_sheet_image()
preview_img.thumbnail((600, 800))
img = ImageTk.PhotoImage(preview_img)
self.canvas_label.configure(image=img)
self.canvas_label.image = img
def generate_pdf(self):
if not self.folder_path or not self.image_list:
return
output_path = filedialog.asksaveasfilename(defaultextension=".pdf", filetypes=[("PDFファイル", "*.pdf")])
if not output_path:
return
page_size = portrait(A4) if self.orientation.get() == "portrait" else landscape(A4)
c = canvas.Canvas(output_path, pagesize=page_size)
width, height = page_size
rows, cols = self.rows.get(), self.cols.get()
cell_width = width / cols
cell_height = height / rows
images_per_page = rows * cols
for i, image_name in enumerate(self.image_list):
if i % images_per_page == 0 and i != 0:
c.showPage()
img_path = os.path.join(self.folder_path, image_name)
img = Image.open(img_path)
img.thumbnail((cell_width - 10, cell_height - 30))
row = (i % images_per_page) // cols
col = (i % images_per_page) % cols
x = col * cell_width + 5
y = height - ((row + 1) * cell_height) + 30
img_temp_path = "temp_img.jpg"
img.convert("RGB").save(img_temp_path)
c.drawImage(ImageReader(img), x, y, width=img.width, height=img.height)
c.setFont("Helvetica", 8)
c.drawString(x, y - 10, image_name)
c.save()
os.remove("temp_img.jpg")
def create_contact_sheet_image(self):
page_size = portrait(A4) if self.orientation.get() == "portrait" else landscape(A4)
width, height = [int(x) for x in page_size]
rows, cols = self.rows.get(), self.cols.get()
cell_width = width // cols
cell_height = height // rows
sheet = Image.new("RGB", (width, height), "white")
for i, image_name in enumerate(self.image_list[:rows * cols]):
img_path = os.path.join(self.folder_path, image_name)
img = Image.open(img_path)
img.thumbnail((cell_width - 10, cell_height - 30))
thumb = Image.new("RGB", (cell_width, cell_height), "white")
thumb.paste(img, ((cell_width - img.width) // 2, 5))
# ファイル名追加
from PIL import ImageDraw, ImageFont
draw_ctx = ImageDraw.Draw(thumb)
font = ImageFont.load_default()
draw_ctx.text((5, cell_height - 20), image_name, font=font, fill="black")
row = i // cols
col = i % cols
sheet.paste(thumb, (col * cell_width, row * cell_height))
return sheet
if __name__ == "__main__":
root = tk.Tk()
app = ContactSheetApp(root)
root.mainloop()