『欠片幻彩』は、指定したフォルダ内の画像を縮小・ランダムに配置して、モザイクアート風の1枚画像を作成するツールです。
>>GUI外観 >>使い方以下は『欠片幻彩』のソースコード全文です:
import os
import random
from datetime import datetime
import tkinter as tk
from tkinter import filedialog, colorchooser, messagebox
from PIL import Image, ImageTk, ImageOps
class ToolTip:
def __init__(self, widget, text=""):
self.widget = widget
self.text = text
self.tip_window = None
widget.bind("<Enter>", self.show_tip)
widget.bind("<Leave>", self.hide_tip)
def show_tip(self, event=None):
if self.tip_window or not self.text:
return
x, y, cx, cy = self.widget.bbox("insert") if self.widget.bbox("insert") else (0,0,0,0)
x = self.widget.winfo_rootx() + 20
y = self.widget.winfo_rooty() + 20
self.tip_window = tw = tk.Toplevel(self.widget)
tw.wm_overrideredirect(True)
tw.wm_geometry(f"+{x}+{y}")
label = tk.Label(tw, text=self.text, justify="left",
background="#ffffe0", relief="solid", borderwidth=1,
font=("Noto Sans JP", 9))
label.pack(ipadx=4, ipady=2)
def hide_tip(self, event=None):
if self.tip_window:
self.tip_window.destroy()
self.tip_window = None
class MosaicApp:
def __init__(self, root):
self.root = root
self.root.title("フォトモザイクメーカー - 欠片幻彩")
# 各種設定
self.width_var = tk.IntVar(value=1920)
self.height_var = tk.IntVar(value=1080)
self.scale_var = tk.DoubleVar(value=0.1)
self.bg_color = "#ffffff"
self.folder_path = ""
self.generated_img = None
# メインフレーム
main_frame = tk.Frame(root, padx=10, pady=10)
main_frame.pack(fill="both", expand=True)
# 左側:設定パネル
left_frame = tk.LabelFrame(main_frame, text="設定", padx=10, pady=10)
left_frame.pack(side="left", fill="y")
# 画像サイズ
tk.Label(left_frame, text="画像サイズ:").grid(row=0, column=0, sticky="w")
tk.Entry(left_frame, textvariable=self.width_var, width=6).grid(row=0, column=1)
tk.Label(left_frame, text="x").grid(row=0, column=2)
tk.Entry(left_frame, textvariable=self.height_var, width=6).grid(row=0, column=3)
# 背景色
tk.Label(left_frame, text="背景色:").grid(row=1, column=0, sticky="w")
tk.Button(left_frame, text="選択", command=self.choose_color).grid(row=1, column=1, sticky="w")
self.color_preview = tk.Label(left_frame, bg=self.bg_color, width=4, relief="sunken")
self.color_preview.grid(row=1, column=2, columnspan=2, sticky="w")
# フォルダ選択
tk.Button(left_frame, text="フォルダ選択", command=self.choose_folder).grid(row=2, column=0, columnspan=4, pady=(5, 0), sticky="w")
self.folder_label = tk.Label(left_frame, text="未選択", wraplength=220, fg="gray", anchor="w", justify="left")
self.folder_label.grid(row=3, column=0, columnspan=4, sticky="w", pady=(2, 5))
self.folder_tooltip = ToolTip(self.folder_label, "")
# 縮小率
tk.Label(left_frame, text="縮小率:").grid(row=4, column=0, sticky="w")
tk.Entry(left_frame, textvariable=self.scale_var, width=6).grid(row=4, column=1, sticky="w")
# ボタン
tk.Button(left_frame, text="生成", command=self.generate, width=10).grid(row=5, column=0, columnspan=2, pady=5)
tk.Button(left_frame, text="保存", command=self.save, width=10).grid(row=5, column=2, columnspan=2, pady=5)
# 右側:プレビュー
right_frame = tk.LabelFrame(main_frame, text="プレビュー", padx=10, pady=10)
right_frame.pack(side="right", fill="both", expand=True)
self.preview_label = tk.Label(right_frame)
self.preview_label.pack(expand=True)
def choose_color(self):
color = colorchooser.askcolor(title="背景色を選択")
if color[1]:
self.bg_color = color[1]
self.color_preview.config(bg=self.bg_color)
def choose_folder(self):
self.folder_path = filedialog.askdirectory()
if self.folder_path:
self.folder_label.config(text=self.folder_path, fg="black")
self.folder_tooltip.text = self.folder_path
else:
self.folder_label.config(text="未選択", fg="gray")
self.folder_tooltip.text = ""
def generate(self):
if not self.folder_path:
messagebox.showwarning("警告", "画像フォルダを選択してください。")
return
W, H = self.width_var.get(), self.height_var.get()
scale = self.scale_var.get()
# 背景生成
mosaic = Image.new("RGB", (W, H), self.bg_color)
# 画像リスト取得
files = [f for f in os.listdir(self.folder_path) if f.lower().endswith((".png",".jpg",".jpeg",".bmp"))]
if not files:
messagebox.showwarning("警告", "フォルダに画像がありません。")
return
# シャッフルして一度ずつ配置
random.shuffle(files)
for file in files:
img = Image.open(os.path.join(self.folder_path, file))
img = ImageOps.exif_transpose(img).convert("RGB") # ★ 回転補正
img = img.resize((int(img.width * scale), int(img.height * scale)))
if img.width == 0 or img.height == 0:
continue # 無効サイズはスキップ
# ランダム座標
x = random.randint(0, max(0, W - img.width))
y = random.randint(0, max(0, H - img.height))
mosaic.paste(img, (x, y))
self.generated_img = mosaic
# プレビュー表示
preview = mosaic.copy()
preview.thumbnail((500, 500))
self.tk_img = ImageTk.PhotoImage(preview)
self.preview_label.config(image=self.tk_img)
def save(self):
if self.generated_img is None:
messagebox.showwarning("警告", "まず画像を生成してください。")
return
filename = datetime.now().strftime("%Y%m%d_%H%M%S.png")
path = os.path.join(os.path.expanduser("~/Desktop"), filename)
self.generated_img.save(path)
messagebox.showinfo("保存完了", f"デスクトップに保存しました:\n{filename}")
if __name__ == "__main__":
root = tk.Tk()
##タイトルバーアイコン表示用
data = '''R0lGODlhEAAQAIYAAAAAAEJYafpzWVJVVvNqTkW36j5UY/8AAP9/AKpVVVWq/+5pU///APtxWD2q2fFxUgB/f0Gq20hhc/ZuVENVZUBWZv9/f/9VVeRrUOdFRfxpTMFmWNpkTft1Wn//////f3ubsX9///9yTknB9vtyV0W26UKx40ey4P98YUCr2/WTSEeo01Wqqv+qVVVVqv+yM0JbbPi5O0FWZv/EOkFSYv/KPi2y6j+////KPjpYai5SZj1VZDxUZP//Mz9VVT9OXSRISD8/fz8/SwD//3VbXwZdhhxKYgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAQAi0AAEIHEgQgAeCAwAYCMAwAAUOGlAIEEDggAUAQQBQkCDDB4AIBUZEAHCjYEIjGyY+wFHjBYIDBQEkBMBCoAMFBYE0DPDjRAEbAhMgBFBBAo8GAh4saEAAwMWCEAoyiClwpsAQVAXSMCDQBQAHJVIMwVmVKEMYQkwUKLACAdmEC3cWAUGABAYACMruYKhDxIQFEwUsAHBBYNQBOYhMmKgiBoAWMYUS6JChx4ysAxNcOMDgQ8GAADs='''
root.tk.call('wm', 'iconphoto', root._w, tk.PhotoImage(data=data))
####
app = MosaicApp(root)
root.mainloop()