PNG Infoã£ãœãèªåçšããŒã«ãäœã£ãã¡ã¢
2025幎8æ5æ¥è¿œèš
æ°ããã®ãäœã£ããã¡ã¢
https://note.com/nullpolab/n/n0fca2e4edc47
å眮ã
pythonç¥ãã人ãChatGPTãCopilotãGeminiã䜿ã£ãŠäœã£ããã®ã§ãã
ãã°ãäºæãã¬ããšãèµ·ãããããããŸããã®ã§äœ¿çšã¯ååæ³šæããŠèªå·±è²¬ä»»ã§ãé¡ãããŸãã
ãœãŒã¹ã³ãŒãã¯å¥œãã«ããŠããã§ãã
äžã®äžã«ã¯äŸ¿å©ãªããŒã«ãããã®ã§pngã«åã蟌ãŸããŠãããã³ãããèŠããªã SD Prompt Reader ãªã©ã䜿ãã®ããããšæããŸãã
æ¬é¡
ããŒã«ã®ãµã³ãã«ç»å
Stable diffusion WebUIã«ããPNG Infoã£ãœãèªåçšããŒã«ã§ãã
ãããªæãã«ããã³ãããèŠããŸã

å®è¡ç°å¢ã®æºåãšå®è¡
ä»®æ³ç°å¢äžã§åãããŸãã
ãããªããªã£ãããã€ããšããã°ãããããšããçç±ãšä»®æ³ç°å¢ã®æ§ç¯ã«ä¿ºãæ
£ããæå³ã§ãããããŠãããŸãã
pythonã®ããŒãžã§ã³ã¯ 3.11.7 ã§ããä»ã®ããŒãžã§ã³ã§ã¯è©ŠããŠãŸããã
ãŸãèªåã§ãããããããã©ã«ãã«ä»¥äžã®ãœãŒã¹ã³ãŒããèšè¿°ãã"PngInfoViewer.py"ãã¡ã€ã«ã眮ããŠãããŸãã
ãã¡ã€ã«åã¯èªåããããã°äœã§ãããã§ãã
é·ãã§ãã
import tkinter as tk
from tkinterdnd2 import TkinterDnD, DND_FILES
from PIL import (Image, ImageTk, PngImagePlugin, JpegImagePlugin,
WebPImagePlugin, GifImagePlugin, ExifTags, UnidentifiedImageError)
import piexif
from iptcinfo3 import IPTCInfo
import os
import re
from screeninfo import get_monitors
import datetime
import sys
import threading
# 2025.02.14
# åäœã«å¿
èŠãªãã®
# python 3.11.7 ã§å®è¡ãã¹ã
# pip install iptcinfo3==2.1.4
# pip install piexif==1.1.3
# pip install pillow==11.1.0
# pip install screeninfo==0.8.1
# pip install tkinterdnd2==0.4.2
# PngInfoã£ãœãããŒã«
# èªå·±è²¬ä»»ã§ãé¡ãããŸã
# ãœãŒã¹ã¯èªç±ã«ããŠãã ãã
# â»ãã ãè²¬ä»»ã¯æããªã
# 9å²9åAIã§äœã£ããã®ã§ã
# äœ¿ãæ¹
# ç»åããã©ãã°&ãããããã
# ããŒããŒãã®ç¢å°ããŒå·Šå³ã§æ»ãã»é²ã
# ç»åã®äžã§ããŠã¹ãã€ãŒã«ã®äžäžã§æ»ãé²ã
# Copyãã¿ã³ã§ã¯ãªããããŒãã«ã¡ã¿ããŒã¿ãã³ããŒ
# SaveTextãã¿ã³ã§"ç»åãã¡ã€ã«å.txt"ã§åãå Žæã«ä¿å
# 泚æ
# ç»åãã¢ãã¿ãŒãã倧ãããšçž®å°è¡šç€ºãããŸã
# ããã§ããŠã£ã³ããŠãã¢ãã¿ãŒããã¯ã¿åºãŸã
# äžå¿ãŠã£ã³ããŠãšç»åã®ãµã€ãºèª¿æŽã¯ããŠã¿ããã©ã¯ã¿åºãŸã
# ãã¡ã€ã«ã«ãã£ãŠã¯å€ãªæååãåºãŸã
#
# IPTCã¿ã°çªå·ãšå¯Ÿå¿ããé
ç®åã®ãããã³ã°
IPTC_TAG_MAPPING = {
5: "Title", # Object Name
7: "Edit Status",
10: "Priority",
15: "Category",
20: "Supplemental Category",
22: "Fixture Identifier",
25: "Keywords",
30: "Release Date",
35: "Release Time",
40: "Special Instructions",
45: "Reference Service",
47: "Reference Date",
50: "Reference Number",
55: "Date Created",
60: "Time Created",
65: "Digital Creation Date",
70: "Digital Creation Time",
75: "Originating Program",
80: "Author", # By-line
85: "By-line Title",
90: "City",
95: "Sub-location",
100: "Province/State",
101: "Country Code",
103: "Country",
105: "Original Transmission Reference",
110: "Headline",
115: "Credit",
116: "Source",
118: "Copyright Notice",
120: "Caption", # Caption/Abstract
122: "Local Caption",
125: "Special Instructions"
}
# ç»åãªã¹ããšã€ã³ããã¯ã¹
image_files = []
current_index = 0
img_tk = None
original_img = None
frames = []
delay = 100
animation_running = False
# ã¡ã¿ããŒã¿è¡šç€ºãšãªã¢ã®åºå®å¹
metadata_width = 300
# ãªãµã€ãºåŠçãã©ã°ãšã¿ã€ããŒ
resize_pending = False
resize_delay = 200 # 200ms
# TkinterãŠã£ã³ããŠïŒTkinterDnDã䜿çšïŒ
root = TkinterDnD.Tk()
root.title("Image Viewer with Metadata")
root.update_idletasks()
# ãŠã£ã³ããŠã®æå°ãµã€ãºãèšå®
min_window_width = 800
min_window_height = 600
root.geometry(f"{min_window_width}x{min_window_height}")
root.minsize(min_window_width, min_window_height)
# ã°ãªããã®éã¿ãèšå®
root.grid_rowconfigure(0, weight=1)
root.grid_rowconfigure(1, weight=0)
root.grid_rowconfigure(2, weight=0)
root.grid_columnconfigure(0, weight=1)
root.grid_columnconfigure(1, weight=0)
# ã¡ã¿ããŒã¿è¡šç€ºãšãªã¢ïŒåºå®å¹
ïŒ
metadata_frame = tk.Frame(root)
metadata_frame.grid(row=0, column=1, rowspan=3, sticky="ns")
metadata_frame.grid_rowconfigure(0, weight=1)
metadata_frame.grid_columnconfigure(0, weight=1)
metadata_text = tk.Text(metadata_frame, width=40, font=("Arial", 16))
metadata_text.grid(row=0, column=0, sticky="nsew")
# ã¡ã¿ããŒã¿é åã®ã¹ã¯ããŒã«èšå®
metadata_scroll = tk.Scrollbar(metadata_frame, orient="vertical",
command=metadata_text.yview)
metadata_scroll.grid(row=0, column=1, sticky="ns")
metadata_text.config(yscrollcommand=metadata_scroll.set)
# ç»å衚瀺ãšãªã¢
image_frame = tk.Frame(root)
image_frame.grid(row=0, column=0, sticky="nsew")
image_frame.grid_rowconfigure(0, weight=1)
image_frame.grid_columnconfigure(0, weight=1)
# ç»åã©ãã«
image_label = tk.Label(image_frame)
image_label.grid(row=0, column=0, padx=0, pady=0, sticky="")
# ãã¡ã€ã«åã衚瀺ããã©ãã«ã远å
filename_label = tk.Label(root, text="", font=("Arial", 12))
filename_label.grid(row=1, column=0, padx=5, pady=5, sticky="w")
# ãã¿ã³ãã¬ãŒã ãäœæ
button_frame = tk.Frame(root)
button_frame.grid(row=2, column=0, padx=5, pady=5, sticky="ew")
# ãã¿ã³ãã¬ãŒã ã®åã®éã¿ãèšå®
for i in range(4):
button_frame.columnconfigure(i, weight=1)
# ãã¿ã³ãé
眮
# åã®ç»å
# æåã®ãã¡ã€ã«ã ã£ãå ŽåæåŸã®ç»åã衚瀺
prev_button = tk.Button(button_frame, text="Previous",
command=lambda: previous_image(), font=("Arial", 14))
prev_button.grid(row=0, column=0, padx=5, sticky="ew")
# ã¯ãªããããŒãã«ã³ããŒ
copy_button = tk.Button(button_frame, text="Copy",
command=lambda: copy_metadata(), font=("Arial", 14))
copy_button.grid(row=0, column=1, padx=5, sticky="ew")
# ããã¹ããã¡ã€ã«ã«ã¡ã¿ããŒã¿ãç»åãã¡ã€ã«åã§ä¿å
save_button = tk.Button(button_frame, text="SaveText",
command=lambda: save_metadata(), font=("Arial", 14))
save_button.grid(row=0, column=2, padx=5, sticky="ew")
# 次ã®ç»å
# æåŸã®ç»åã ã£ãå Žåæåã®ç»åã衚瀺
next_button = tk.Button(button_frame, text="Next",
command=lambda: next_image(), font=("Arial", 14))
next_button.grid(row=0, column=3, padx=5, sticky="ew")
# gifæå°ã®é
å»¶æéïŒããªç§ïŒ é«éåç鲿¢çš
# gifã¯1ãã¬ãŒã ããšã«durationãããããã ãããã¯èããªã
# ãã¡ããšãããªã1ãã¬ãŒã ããšååŸãã
# ãªãapngã圱é¿ãåããæš¡æ§
min_delay = 80
# `after()` ã®IDãåŠçããšã«ç®¡çããèŸæž
# root.afterçš
after_ids = {}
# ç»åã衚瀺ãã颿°
def show_image(img_path):
global current_index, img_tk, original_img, frames, delay, animation_running
try:
img = Image.open(img_path)
original_img = img.copy()
frames = []
delay = img.info.get('duration', min_delay) # èšå®ãããŠãªãå Žåmin_delayãå
¥ã
if delay < min_delay:
delay = 80
animation_running = False
# çŸåšã¢ãã¡ãŒã·ã§ã³gifã衚瀺ãããŠããã° `after()` ããã£ã³ã»ã«ïŒããŒ: "gif_key"ïŒ
if "gif_key" in after_ids:
root.after_cancel(after_ids["gif_key"])
del after_ids["gif_key"] # IDãèŸæžããåé€
# ãã¬ãŒã æ°ããã§ãã¯
if getattr(img, "is_animated", False):
frame_count = img.n_frames
else:
frame_count = 1
# ã¢ãã¿ãŒãµã€ãºãååŸïŒget_monitorsã䜿çšïŒ
monitor = get_monitors()[0] # ã¡ã€ã³ã¢ãã¿ãŒãååŸ
screen_width = monitor.width
screen_height = monitor.height
# ãŠã£ã³ããŠã®è£
食ããã¿ã³ãã¡ã¿ããŒã¿ãšãªã¢ã®ãµã€ãºãèæ
®
window_decor_width = 200
window_decor_height = 150
img_margin = 20 # ç»åã©ãã«ã®ããŒãžã³
# ç»åãµã€ãº
img_width, img_height = img.size
# å¿
èŠãªãŠã£ã³ããŠãµã€ãºãèšç®
required_window_width = img_width + metadata_width + window_decor_width + img_margin
required_window_height = img_height + window_decor_height + img_margin
aspect_ratio = img_width / img_height
# ç»åãã¢ãã¿ãŒããå°ããå Žå
if required_window_width <= screen_width and required_window_height <= screen_height:
# ç»åãå
ã®ãµã€ãºã§è¡šç€º
new_width, new_height = img_width, img_height
else:
# ãŠã£ã³ããŠãã¢ãã¿ãŒãµã€ãºãè¶
ããå Žåãç»åãçž®å°
available_width = screen_width - metadata_width - window_decor_width - img_margin
available_height = screen_height - window_decor_height - img_margin
# å©çšå¯èœãªå¹
ãšé«ãã«åºã¥ããŠãã¢ã¹ãã¯ãæ¯ãç¶æããŠæ°ãããµã€ãºãèšç®
width_ratio = img_width / available_width
height_ratio = img_height / available_height
if width_ratio > height_ratio:
new_width = available_width
new_height = int(available_width / aspect_ratio)
else:
new_height = available_height
new_width = int(available_height * aspect_ratio)
# ãã¬ãŒã ããªãµã€ãºããŠãªã¹ãã«æ ŒçŽ
if frame_count > 1:
target_size = (int(new_width), int(new_height))
img.seek(0)
for frame in range(frame_count):
try:
img.seek(frame)
except EOFError:
print("frame EOFerror")
continue
frame_img = img.convert("RGBA").copy()
if target_size != img.size:
frame_img = frame_img.resize(target_size, Image.LANCZOS)
frames.append(ImageTk.PhotoImage(frame_img))
animation_running = True
animate(0)
else:
if (int(new_width), int(new_height)) != img.size:
img = img.resize((int(new_width), int(new_height)), Image.LANCZOS)
img_tk = ImageTk.PhotoImage(img)
image_label.config(image=img_tk)
image_label.image = img_tk
# ãŠã£ã³ããŠãµã€ãºã調æŽ
total_width = new_width + metadata_width + window_decor_width + img_margin
total_height = max(new_height + window_decor_height + img_margin, min_window_height)
root.geometry(f"{int(total_width)}x{int(total_height)}")
# ãã¡ã€ã«åã衚瀺
filename = os.path.basename(img_path)
filename_label.config(text=f"ãã¡ã€ã«å: {filename}")
# ã¡ã¿ããŒã¿è¡šç€º
show_metadata(img_path)
except Exception as e:
print(f"Error loading image: {e}")
image_label.config(image=None)
metadata_text.delete(1.0, tk.END)
metadata_text.insert(tk.END, f"Error loading image: {e}\n")
filename_label.config(text="ãã¡ã€ã«å: ãšã©ãŒ")
# GIFã¢ãã¡ãŒã·ã§ã³ã衚瀺ãã颿°
def animate(frame_index):
global frames, delay, animation_running
if not animation_running:
return
# frame_indexãç¯å²å€ã®å Žåã¯0ã«ãªã»ãããã
if frame_index >= len(frames):
frame_index = 0
frame = frames[frame_index]
image_label.config(image=frame)
image_label.image = frame
next_frame = (frame_index + 1) % len(frames)
after_ids["gif_key"] = root.after(int(delay), animate, next_frame)
# ãŠã£ã³ããŠãªãµã€ãºæã®åŠç
def on_resize(event):
global resize_pending
if resize_pending:
return
resize_pending = True
after_ids["resize_key"] = root.after(int(resize_delay), resize_image)
# ãªãµã€ãºåŠç
def resize_image():
global resize_pending, frames, animation_running
margin_size = 10
if original_img:
window_width = image_frame.winfo_width() - margin_size # äœçœãèæ
®
window_height = image_frame.winfo_height() - margin_size # äœçœãèæ
®
img_width, img_height = original_img.size
aspect_ratio = img_width / img_height
if img_width > window_width or img_height > window_height:
if img_width / window_width > img_height / window_height:
new_width = window_width
new_height = int(new_width / aspect_ratio)
else:
new_height = window_height
new_width = int(new_height * aspect_ratio)
else:
new_width, new_height = img_width , img_height
# ã¢ãã¡ãŒã·ã§ã³GIFã®å Žå
# ã®ã¯ãã ãimg.copy()ã ãšgifã®ãã¬ãŒã ãã¹ãŠãã³ããŒãããããããªãã£ãœãã®ã§å®éã«ãã®åŠçã«å
¥ãããšã¯ãªãæš¡æ§
# 察åŠããã®ãªãã°ãã¬ãŒã ãäžã€äžã€ã³ããŒããŠæ°ããªGIFãäœãã£ãœã
if frames and getattr(original_img, "is_animated", False):
animation_running = False
# çŸåšã¢ãã¡ãŒã·ã§ã³gifã衚瀺ãããŠããã° `after()` ããã£ã³ã»ã«ïŒããŒ: "gif_key"ïŒ
if "gif_key" in after_ids:
root.after_cancel(after_ids["gif_key"])
del after_ids["gif_key"] # IDãèŸæžããåé€
print("gif")
frames.clear()
frame_count = original_img.n_frames
target_size = (int(new_width), int(new_height))
img.seek(0)
for frame in range(frame_count):
try:
original_img.seek(frame)
except EOFError:
print("Frame EOF Error")
continue
frame_img = original_img.convert("RGBA").copy()
frame_img = frame_img.resize(target_size, Image.LANCZOS)
frames.append(ImageTk.PhotoImage(frame_img))
animation_running = True
animate(0)
else:
display_img = original_img.resize((int(new_width ), int(new_height)), Image.LANCZOS)
img_tk = ImageTk.PhotoImage(display_img)
image_label.config(image=img_tk)
image_label.image = img_tk
resize_pending = False
# ãªãµã€ãºåŠçã«ãã root.after `after()` ããã£ã³ã»ã«ïŒããŒ: "resize_key"ïŒ
if "resize_key" in after_ids:
root.after_cancel(after_ids["resize_key"])
del after_ids["resize_key"] # IDãèŸæžããåé€
# IPTCã¡ã¿ããŒã¿ååŸ
def extract_iptc_metadata(image_path):
try:
img = Image.open(image_path)
if img.format != "JPEG":
# print("jpegãããªãã")
return
# Falseã®ã»ããåŠçã軜ããªã
# æšæºãšã©ãŒåºåãäžç¬ã ãç¡å¹å
# No IPTC data found in ïœãªã©ãåºåãããã®ãæå¶ãã
sys.stderr = open(os.devnull, 'w')
try:
info = IPTCInfo(image_path,force=False)
finally:
sys.stderr = sys.__stderr__ # 確å®ã«å
ã«æ»ã
# å
éšããŒã¿ã«ã¢ã¯ã»ã¹
if not hasattr(info, '_data') or not info._data:
print("No IPTC metadata found.")
return
# print("IPTC Metadata:")
metadata_text.insert(tk.END, "\n=== IPTC ã¡ã¿ããŒã¿ ===\n")
for key, value in info._data.items():
# ããŒã None ã®å Žåã¯ã¹ããã
if key is None:
continue
# ãããã³ã°èŸæžãããã¬ã³ããªãªé
ç®åãååŸ
tag_name = IPTC_TAG_MAPPING.get(key, f"Unknown ({key})")
# valueã空ã®å Žåã¯è¡šç€ºããªã
if value is None:
continue
# å€ããªã¹ãã®å Žåã¯åèŠçŽ ããã³ãŒãããŠçµå
if isinstance(value, list):
decoded_list = []
for item in value:
if isinstance(item, bytes):
try:
item = item.decode('utf-8')
except UnicodeDecodeError:
item = item.decode('latin-1', 'ignore')
decoded_list.append(str(item))
value_str = ', '.join(decoded_list).strip()
if not value_str:
continue
value = value_str
# å€ãbytesåã®å Žåã¯ãã³ãŒã
elif isinstance(value, bytes):
try:
value = value.decode('utf-8')
except UnicodeDecodeError:
value = value.decode('latin-1', 'ignore')
if not value.strip():
continue
# æååã®å Žåã空æååã¯ã¹ããã
elif isinstance(value, str):
if not value.strip():
continue
# print(f"{tag_name}: {value}")
metadata_text.insert(tk.END,tag_name + ": " + value + "\n")
if value == []:
metadata_text.delete(1.0, tk.END)
except Exception:
pass # ååŸã§ããªãå Žåã¯ç¡èŠ
def decodeXP(t):
b = bytes(t)
return b[:-2].decode('utf-16-le')
# ã¡ã¿ããŒã¿ã衚瀺ãã颿°
def show_metadata(img_path):
try:
image = Image.open(img_path)
metadata_text.delete(1.0, tk.END) # æ¢åã®ããã¹ããã¯ãªã¢
# ã¡ã¿ããŒã¿å€æ°ã®åæå
metadata = {}
# === EXIFæ
å ±ã®ååŸ ===
exif_bytes = image.info.get("exif")
if exif_bytes:
try:
exif_dict = piexif.load(exif_bytes) # ãã€ããªãèŸæžåœ¢åŒã«å€æ
metadata_text.insert(tk.END, "=== EXIF æ
å ± ===\n")
for ifd_name in exif_dict:
if isinstance(exif_dict[ifd_name], dict):
for tag_id, value in exif_dict[ifd_name].items():
tag_name = piexif.TAGS[ifd_name].get(tag_id, {}).get("name", f"Unknown-{tag_id}")
if tag_name.startswith("XP"):
value = decodeXP(value)
else:
# ãã€ããªããŒã¿ã¯ãã³ãŒããã
if isinstance(value, bytes):
try:
value = value.decode("utf-8", errors="ignore")
except Exception:
value = "[ãã€ããªããŒã¿]"
metadata_text.insert(tk.END, f"{tag_name}: {value}\n")
# 確èª
# print(f"tag_name = {tag_name}")
# ãŠãŒã¶ãŒã³ã¡ã³ã & ç»åã®èª¬æ
user_comment = exif_dict["Exif"].get(37510) # UserComment
image_description = exif_dict["0th"].get(270) # ImageDescription
if user_comment:
# ãŠãŒã¶ãŒã³ã¡ã³ãããã€ããªããŒã¿ (b'UNICODE\x00') ã ã£ãå ŽåãNULLãã€ããé€å»ããŠãããã³ãŒã
if isinstance(user_comment, bytes):
# NULLãã€ããé€å»
user_comment = user_comment.replace(b'\x00', b'').decode("utf-8", errors="ignore")
metadata_text.insert(tk.END, f"\n=== ãŠãŒã¶ãŒã³ã¡ã³ã ===\n{user_comment}\n")
if image_description:
metadata_text.insert(tk.END, f"\n=== ç»åã®èª¬æ ===\n{image_description}\n")
except Exception as e:
metadata_text.insert(tk.END, f"\nEXIF ãã³ãŒããšã©ãŒ: {e}\n")
# === IPTCã¡ã¿ããŒã¿ã®ååŸ ===
extract_iptc_metadata(img_path) # ãã£ã¡ã«åŠçãç§»è¡ãäžèšã¯è©³çްãªãã®ã¯åºãªã
"""
try:
with open(img_path, "rb") as f:
img_data = f.read()
iptc_start = img_data.find(b"Photoshop 3.0\x00")
if iptc_start != -1:
metadata_text.insert(tk.END, "\n=== IPTC ã¡ã¿ããŒã¿ ===\n")
iptc_data = img_data[iptc_start:iptc_start + 512] # IPTCããŒã¿ã®äžéšãååŸ
metadata_text.insert(tk.END, iptc_data.decode("utf-8", errors="ignore") + "\n")
except Exception:
pass # ååŸã§ããªãå Žåã¯ç¡èŠ
"""
# === XMP ã¡ã¿ããŒã¿ã®ååŸ ===
try:
with open(img_path, "rb") as f:
img_data = f.read()
xmp_start = img_data.find(b"<x:xmpmeta")
xmp_end = img_data.find(b"</x:xmpmeta>") + len(b"</x:xmpmeta>")
if xmp_start != -1 and xmp_end != -1:
metadata_text.insert(tk.END, "\n=== XMP ã¡ã¿ããŒã¿ ===\n")
xmp_data = img_data[xmp_start:xmp_end].decode("utf-8", errors="ignore")
metadata_text.insert(tk.END, re.sub(r'>\s+<', '>\n<', xmp_data) + "\n")
except Exception:
pass # ååŸã§ããªãå Žåã¯ç¡èŠ
# === ç»åãã©ãŒãããåºæã®ã¡ã¿ããŒã¿ ===
if isinstance(image, PngImagePlugin.PngImageFile):
metadata = image.text # PNGã®ããã¹ãæ
å ±
elif isinstance(image, (JpegImagePlugin.JpegImageFile, WebPImagePlugin.WebPImageFile, GifImagePlugin.GifImageFile)):
metadata = image.info # äžè¬çãªã¡ã¿ããŒã¿æ
å ±
if metadata:
if not metadata_text.get("1.0", "end-1c").strip() == "": # 空ãããªãã£ãå Žå äžåæ¹è¡ãæã
metadata_text.insert(tk.END,"\n")
metadata_text.insert(tk.END, "=== ç»åãã©ãŒãããåºæã®ã¡ã¿ããŒã¿ ===\n")
for key, value in metadata.items():
metadata_text.insert(tk.END, f"{key}: {value}\n")
# ã¡ã¿ããŒã¿ãäœããªãå Žå
if not exif_bytes and not metadata:
metadata_text.insert(tk.END, "ã¡ã¿ããŒã¿ã¯ãããŸãã\n")
except Exception as e:
metadata_text.delete(1.0, tk.END)
metadata_text.insert(tk.END, f"ã¡ã¿ããŒã¿ã®èªã¿èŸŒã¿ãšã©ãŒ: {e}\n")
# ã¡ã¿ããŒã¿ãã¯ãªããããŒãã«ã³ããŒãã颿°
def copy_metadata():
metadata = metadata_text.get(1.0, tk.END)
root.clipboard_clear()
root.clipboard_append(metadata)
print("ã¡ã¿ããŒã¿ãã¯ãªããããŒãã«ã³ããŒããŸããã")
# ã¡ã¿ããŒã¿ããã¡ã€ã«ã«ä¿åãã颿° (åçç¡çšã§äžæžã)
def save_metadata_old():
if image_files:
img_path = image_files[current_index]
base_name = os.path.splitext(os.path.basename(img_path))[0]
directory = os.path.dirname(img_path)
output_path = os.path.join(directory, f"{base_name}.txt")
metadata = metadata_text.get(1.0, tk.END)
try:
with open(output_path, 'w', encoding='utf-8') as f:
f.write(metadata)
print(f"ã¡ã¿ããŒã¿ããã¡ã€ã«ã«ä¿åããŸãã: {output_path}")
except Exception as e:
print(f"ã¡ã¿ããŒã¿ã®ä¿åã«å€±æããŸãã: {e}")
# ã¡ã¿ããŒã¿ããã¡ã€ã«ã«ä¿åãã颿° (ååãã¡ã€ã«ããã£ãå Žåé£çªãã€ããŠä¿å)
# ã©ã£ã¡ããããã¯åŒã³åºããŠããšãããæžãå€ãã
def save_metadata():
if image_files:
img_path = image_files[current_index]
base_name = os.path.splitext(os.path.basename(img_path))[0]
directory = os.path.dirname(img_path)
# é£çªãèæ
®ãããã¡ã€ã«åçæ
output_path = os.path.join(directory, f"{base_name}.txt")
counter = 2
while os.path.exists(output_path): # ãã¡ã€ã«ããã§ã«ååšããå Žå
output_path = os.path.join(directory, f"{base_name} ({counter}).txt")
counter += 1 # é£çªãå¢ãã
# ã¡ã¿ããŒã¿ååŸ
metadata = metadata_text.get(1.0, tk.END)
# ãã¡ã€ã«ã«æžã蟌ã
try:
with open(output_path, 'w', encoding='utf-8') as f:
f.write(metadata)
print(f"ã¡ã¿ããŒã¿ããã¡ã€ã«ã«ä¿åããŸãã: {output_path}")
except Exception as e:
print(f"ã¡ã¿ããŒã¿ã®ä¿åã«å€±æããŸãã: {e}")
# é²ã颿°
def next_image(event=None):
global current_index, animation_running
if image_files:
animation_running = False
current_index = (current_index + 1) % len(image_files)
show_image(image_files[current_index])
# æ»ã颿°
def previous_image(event=None):
global current_index, animation_running
if image_files:
animation_running = False
current_index = (current_index - 1) % len(image_files)
show_image(image_files[current_index])
# åæå
def init():
if "dd_key" in after_ids:
root.after_cancel(after_ids["dd_key"])
del after_ids["dd_key"] # IDãèŸæžããåé€
if "gif_key" in after_ids:
root.after_cancel(after_ids["gif_key"])
del after_ids["gif_key"] # IDãèŸæžããåé€
if "resize_key" in after_ids:
root.after_cancel(after_ids["resize_key"])
del after_ids["resize_key"] # IDãèŸæžããåé€
image_files = [] # åæå
image_label.config(image='') # åæå
image_label.image = None # åæå
# ãã©ãã°&ããããèšå®
def drop(event):
global image_files, current_index, animation_running
init() #åæå
# event.data ã Tcl ãªã¹ã圢åŒã®æååãšããŠåå²ã㊠Python ã®ã¿ãã«ã«å€æ
# æåã®ãã¡ã€ã«ãã¹ãååŸïŒãã¹ã«ç©ºçœããã£ãŠãæ£ããæ±ããïŒ
file_list = root.tk.splitlist(event.data)
# print(f"{file_list}")
img_path = file_list[0] # è€æ°ãããããããæãæåã®ãã®ã ããæœåº äžèšã¯äžã€ã ãã®å
¥åã®åæ®
# img_path = re.sub(r"{|}", "", img_path)
img_path = os.path.abspath(img_path)
# ã¹ã¬ããã§ç»åãã¡ã€ã«åŠçãå®è¡
thread = threading.Thread(target=process_images, args=(img_path,))
thread.start()
def process_images(img_path):
global image_files, current_index, animation_running
# ç»åãã¡ã€ã«åŠçã®ã³ãŒã (å
ã® drop 颿°ããç§»å)
directory = os.path.dirname(img_path)
image_files = []
current_index = -1
for f in os.listdir(directory):
file_path = os.path.join(directory, f)
# **ãã¡ã€ã«ãã¹ããã¡ã€ã«ã§ããããã§ã㯠(ãã©ã«ããé€å€)**
if not os.path.isfile(file_path):
# print(f"ã¹ããã: '{f}' ã¯ãã©ã«ãã§ãããããåŠçãã¹ãããããŸãã")
continue # ãã©ã«ãã®å Žåã¯æ¬¡ã®ãã¡ã€ã«ãž
try:
# Pillow ã§ç»åãã¡ã€ã«ãšããŠéããã詊ã (倿Žãªã)
Image.open(file_path)
# ãšã©ãŒãªãéããå Žåã¯ç»åãã¡ã€ã«ãšã¿ãªã (倿Žãªã)
image_files.append(file_path)
except FileNotFoundError:
# ãã¡ã€ã«ãèŠã€ãããªãå Žåã¯ã¹ããã (倿Žãªã)
continue
except UnidentifiedImageError:
# ç»åãã¡ã€ã«ãšããŠèªèã§ããªãå Žåã¯ã¹ããã (倿Žãªã)
# print(f"ã¹ããã: '{f}' ã¯ãµããŒããããŠããªãç»å圢åŒããŸãã¯ç»åãã¡ã€ã«ãšããŠèªèã§ããŸããã§ããã")
continue
except Exception as e:
# ãã®ä»ã®äºæãã¬ãšã©ãŒ (倿Žãªã)
print(f"ã¹ããã: '{f}' åŠçäžã«ãšã©ãŒãçºçããŸãã: {e}")
continue
image_files.sort()
try:
current_index = image_files.index(img_path)
except ValueError:
current_index = -1
# GUIã®æŽæ°ã¯ã¡ã€ã³ã¹ã¬ããã§è¡ãå¿
èŠãããããã`after` ã䜿çš
after_ids["dd_key"] = root.after(0, update_gui, image_files, current_index,img_path) # `root` 㯠Tk() ã€ã³ã¹ã¿ã³ã¹
def update_gui(partial_image_files, current_index_param,img_path):
global image_files, current_index, animation_running
image_files = partial_image_files # ã°ããŒãã«å€æ°ãæŽæ° (å¿
èŠã«å¿ããŠ)
current_index = current_index_param # ã°ããŒãã«å€æ°ãæŽæ° (å¿
èŠã«å¿ããŠ)
if current_index != -1:
animation_running = False
show_image(image_files[current_index])
else:
init() #åæå
print(f"ãšã©ãŒ: ããããããããã¡ã€ã« '{img_path}' ã¯æå¹ãªç»åãã¡ã€ã«ã§ã¯ãããŸããã")
metadata_text.delete(1.0, tk.END)
metadata_text.insert(tk.END, f"ãšã©ãŒ: ããããããããã¡ã€ã« '{img_path}' ã¯æå¹ãªç»åãã¡ã€ã«ã§ã¯ãããŸãã")
# ããŒããŒãã·ã§ãŒãã«ãã
root.bind("<Right>", next_image)
root.bind("<Left>", previous_image)
root.bind("<Escape>", lambda event: root.quit())
# ããŠã¹ãã€ãŒã«ã§ç»åãåãæ¿ãã
def on_mousewheel(event):
if event.delta > 0:
previous_image()
else:
next_image()
# ç»å衚瀺ãšãªã¢ã§ã®ããŠã¹ãã€ãŒã«ã€ãã³ãããã€ã³ã
image_label.bind("<MouseWheel>", on_mousewheel)
image_label.bind("<Button-4>", on_mousewheel)
image_label.bind("<Button-5>", on_mousewheel)
# ãŠã£ã³ããŠãªãµã€ãºã€ãã³ã
root.bind("<Configure>", on_resize)
# ãã©ãã°&ãããããæå¹å
root.drop_target_register(DND_FILES)
root.dnd_bind('<<Drop>>', drop)
# å®è¡
root.mainloop()
次ã«ãã®ãã©ã«ãã§ä»®æ³ç°å¢ãæ§ç¯ããŸãã
PowerShellãéããŠæ¬¡ã®ã³ãã³ããæã¡ãŸãã
python -m venv venv次ã«ä»®æ³ç°å¢ãæå¹åããŸãã
.\venv\Scripts\activate次ã«å¿ èŠãªããã±ãŒãžãã€ã³ã¹ããŒã«ããŸãã
pip install iptcinfo3==2.1.4
pip install piexif==1.1.3
pip install pillow==11.1.0
pip install screeninfo==0.8.1
pip install tkinterdnd2==0.4.2ããŒãžã§ã³æå®ããŠãã®ã¯ä»ã®æç¹ã§åããŠãããŒãžã§ã³ãæç¢ºã«ããŠããããããã§ãã
ããŒãžã§ã³æå®ãªããããããŒãïŒã£ãŠäººã¯ä»¥äžã®ã³ãã³ãã§
pip install iptcinfo3 piexif pillow screeninfo tkinterdnd2ããããå®è¡ããŸãã
python PngInfoViewer.pyèµ·åïŒ
ããŠããšãããªã䜿ãããšãã人ãã
â€â¢â€â¢â€â¢â€â¢â€â¢â€â¢â€â¢â€â¢â€â¢â€â¢
äœ¿ãæ¹ãšæ³šæ!!
â€â¢â€â¢â€â¢â€â¢â€â¢â€â¢â€â¢â€â¢â€â¢â€â¢
ã»ã©ããããã°ããããããããªãã®ã§èŠæããã人ã ã䜿çšããŠãã ãã
ã»å€§éã«ãã¡ã€ã«ããããã©ã«ãã®ç»åã¯èªã¿èŸŒãŸãªãã§ãã ãã
ã»ç»åãã¡ã€ã«ã"1ã€ã ã"ãã©ãã°&ããããããŠãã ãã
ã»å€§ããç»åã ãšãŠã£ã³ããŠãã¢ãã¿ãŒããã¯ã¿åºãŸã
ã»ã¢ãã¿ãŒãã倧ããç»åã ãšãªãµã€ãºã®é¢ä¿ã§ç»åãã¡ãã£ãšåããŸã
ã»èªã¿èŸŒãã ç»åã®ãã©ã«ãã«ããèªã¿èŸŒããç»åãã¡ã€ã«ãåãæ¿ããŠè¡šç€ºã§ããŸã
ã»ESCããŒã§çµäºããŸã
ã»ããŒããŒãã®ç¢å°ããŒã®å·Šå³ã§æ»ãã»é²ãã§ã
ã»"ç»åäžã ã"ã§ããŠã¹ãã€ãŒã«ã®äžäžã§æ»ãã»é²ããå¹ããŸã
ã»"Copy"ãã¿ã³ã¯ã¯ãªããããŒãã«å³åŽã«è¡šç€ºãããŠãããã¹ããã³ããŒããŸã
ã»"SaveText"ã¯"[ç»åã®ãã¡ã€ã«å].txt"ã§å³åŽã«è¡šç€ºãããŠããããã¹ããä¿åããŸã
ã»ååãã¡ã€ã«ãããå Žåã¯é£çªãä»å ãããŠä¿åãããŸãã
é©åœã«ç»åãèªã¿èŸŒãã§ãããšããããã©ãºã©ãºã©ãšããããããæåãåºãããšããããã©ç¡èŠããŠãã ããã
ã¢ãã¡ãŒã·ã§ã³GIFãAPNGãçž®å°ããããšãããšç»åãèŠåããŸãã
ããã³ããã衚瀺ããã以å€ã¯ããŸãã§ãã
( ΊÏΊ)ÏïŒ ããã³ããã衚瀺ãããŠãã®ã§ãšã·ïŒ
ä»®æ³ç°å¢ããã¡ãã¡ã¢ã¯ãã£ãã«ããŠèµ·åããã®ããã©ãããŒã£ãŠäººã¯
@echo off
cd /d %~dp0
call .\venv\Scripts\activate
python PngInfoViewer.py
deactivate
pauseã£ãŠèšè¿°ããããã¹ããã¡ã€ã«ã"run.bat"ã¿ãããªååã«ããŠä»®æ³ç°å¢ãšã»ããã«ããŠçœ®ããŠããPngInfoViewer.pyããããã©ã«ãã«ãããŠå®è¡ãããšãããã
ãããChatGPTã«èããŠäœããŸãã
ChatGPTã«èãã説æ
@echo off ââ ããããã¡ã€ã«å®è¡æã«ã³ãã³ããã®ãã®ã衚瀺ããªãããã«ããèšå®
cd /d %~dp0 ââ ããããã¡ã€ã«ã®å®è¡ãã£ã¬ã¯ããªããã®ããããã¡ã€ã«ããããã©ã«ãã«å€æŽãã
call .\venv\Scripts\activate ââ ä»®æ³ç°å¢ïŒvenvïŒãã¢ã¯ãã£ãã«ãã
ã»call ã䜿ããšãå®è¡åŸã«å
ã®ããããã¡ã€ã«ã«æ»ã£ãŠåŠçãç¶ããããšãã§ããŸããšã®ããš
以äžçç¥
以äžã§ãã
å¶äœæ¥èšã£ãœããã®(èªåã®æãåºãçšãé·ã)
è©°ãŸã£ããšããæç²
ã»ãã©ãã°&ããããã§ãã¡ã€ã«ãèªã¿èŸŒããšãã¹ããã¡ã€ã«åã«åè§ã¹ããŒã¹(å
šè§ã¹ããŒã¹ã¯æ€èšŒããŠãªã)ããããšèªåçã«"{}"ãã€ããããŠããŸãã®ã§ãã¡ããšåãé€ãåŠçãå
¥ããã
ã»ã¢ãã¿ãŒã®è§£ååºŠãæ£ç¢ºã«ç¥ãããæã¯"get_monitors"ã䜿ã
ã»Exifã¯è€éæªå¥ãªã®ã§çŽ äººãæãåºããã®ã§ã¯ãªã
ã»ICCãããã¡ã€ã«ã«ãæãåºããŠã¯ãããªã
ãã£ããã¯pnginfoããµã¯ããšèŠããããã®ããªãããªãšæã£ãããšã
å®éããã Stable Diffusion Prompt Reader ã£ãŠãã®ããä»ã«ãããã€ãããã
ãŸããã£ããpythonç°å¢ããããChatGPTãCopilotãGeminiããããèãã°äœããããããïŒãšæã£ãã
ãšããããèããŠã¿ããã£ãŠããšã§ChatGPTã«èããŠã¿ãã
ãStable Diffusion ã® "png info"ãšããæ©èœãç¥ã£ãŠããŸããïŒã
ãããã ãããããããšæ©èœã®èª¬æãããŠãããã
ãããã£ãŠããšã§
ããã®æ©èœãšåããã®ãpythonããã°ã©ã ã§äœæããŠãã ããããã©ã«ãã«ããpngç»åãèªã¿èŸŒã¿ãã¡ã¿ããŒã¿ãpngç»åã®ãã¡ã€ã«åãšåãååã®ããã¹ãã§åºåãããã®ããé¡ãããŸãã
ãŠèšã£ãããµã¯ããšã³ãã³ãã©ã€ã³ã§äœ¿ããââ
ã»input_images ãã©ã«ãã« PNG ç»åãå
¥ãã
ã»ã¹ã¯ãªãããå®è¡ãããšãoutput_metadata ãã©ã«ãã«ç»åããšã®ã¡ã¿ããŒã¿ãå«ãããã¹ããã¡ã€ã«ãçæããã
ã»åããã¹ããã¡ã€ã«ã«ã¯ tEXt ã iTXt ã«ä¿åãããããã³ããããã©ã¡ãŒã¿ãèšé²ããã
ãšããããã°ã©ã ãäœã£ãŠãããã
ããïœãããŒãšæããªããã³ããããŠå®è¡ã
ãããã€âŠâŠåããïŒã
ãããªãã£ãŠãã§æ¬¡ã¯
ãã€ã³ããããã©ã«ãã¯ã³ãã³ãã©ã€ã³åŒæ°ã§åãåããããã«ããŠãã ããã
ãããã§ãããšããã«èŠæã¯ãšã¹ã«ã¬ãŒãããŠãã
âç»åãéããŠå·ŠåŽã«ç»åã衚瀺ãå³åŽã«ããã³ããæ
å ±
âãã©ãã°&ããããããŠç»åã衚瀺
ãã»è²ã
èªã¿èŸŒãŸããŠã¿ããšãããã¹ããã¡ã€ã«åã«ç©ºçœãå
¥ããã®ã ãšè¡šç€ºã§ããªãããšã«æ°ã¥ã
ãã»ç©ºçœãå
¥ããšé§ç®ã ããçŽããŠãšã¢ããŠãã«äœåèšã£ãŠãçŽããªã
ãã»printã§åºåããŠèª¿ã¹ããšã©ããããã¹ããã¡ã€ã«åã«ç©ºçœãå
¥ããšèªåã§"{}"倧æ¬åŒ§ãã€ã仿§ã®ããã ã£ã
ãã»èªã¿èŸŒãã§ãã®åŸã«åãåãæååã«"{}"ãå
¥ã£ãŠãå Žåãããé€å»ããããã«å
·äœçã«æç€ºãããšçŽããŠããã
ãã»å
·äœçã«æç€ºããã®ã倧äºã®ããã
ãã»ã ãçµå±æåŸã¯éãæ¹æ³"ã¿ãã«å"ãšãããã®ã«ãªã£ã
ãã»ãªããªãè€æ°ãããããããæã®åŠçã远å ããããã§æåã®ãã¡ã€ã«ã®ã¿åç
§ããŠãã
âgifç»åããããïŒãšèããŠgifç»åã衚瀺ã§ããããã«(gifã¯ããŸãæ€èšŒããŠãªã)
âç»åã®å
ã®è§£å床ã§è¡šç€ºããããã«
âç»åãã¢ãã¿ãŒãã倧ããå Žåã¯çž®å°ããŠè¡šç€º(ãŠã£ã³ããŠãã¢ãã¿ãŒããã¯ã¿åºãéãªçž®å°è¡šç€º)
ãã»windowsã®èšå®ã§ãã£ã¹ãã¬ã€ãæ¡å€§çž®å°ãšã¬ã€ã¢ãŠãã§150%(DPI ã¹ã±ãŒãªã³ã°)ã«ããŠããšç»åèªäœã®è§£å床ããã倧ãã衚瀺ãããåé¡ã®å¯ŸåŠ
ãã»ã¢ãã¿ãŒèªäœã®è§£å床ãååŸããã®ã«ã¯ get_monitors ã§ååŸããã°ããã£ãœãã®ã§ããã䜿ãããã«æç€ºãã
âgifç»åããããïŒãšèããŠgifç»åã衚瀺ã§ããããã«(gifã¯ããŸãæ€èšŒããŠãªã)
âç»åã®å
ã®è§£å床ã§è¡šç€ºããããã«
âç»åãã¢ãã¿ãŒãã倧ããå Žåã¯çž®å°ããŠè¡šç€º(ãŠã£ã³ããŠãã¢ãã¿ãŒããã¯ã¿åºãéãªçž®å°è¡šç€º)
ãã»windowsã®èšå®ã§ãã£ã¹ãã¬ã€ãæ¡å€§çž®å°ãšã¬ã€ã¢ãŠãã§150%(DPI ã¹ã±ãŒãªã³ã°)ã«ããŠããšç»åèªäœã®è§£å床ããã倧ãã衚瀺ãããåé¡ã®å¯ŸåŠ
ãã»ã¢ãã¿ãŒèªäœã®è§£å床ãååŸããã®ã«ã¯ get_monitors ã§ååŸããã°ããã£ãœãã®ã§ããã䜿ãããã«æç€ºãã
âã¡ã¿ããŒã¿è¡šç€ºãšãªã¢ãèæ
®ã«å
¥ããŠç»åã衚瀺
âç»åãèªã¿èŸŒãã ããã®ç»åãšåããã©ã«ãã«ããç»åãé çªã«è¡šç€ºã§ããããã«
âæ»ãã»é²ããã¿ã³ã®è¿œå
âããŒããŒãã®ç¢å°ããŒã®å·Šå³ã§æ»ãé²ãã远å
âã¡ã¿ããŒã¿ã®ã¯ãªããããŒããžã®ã³ããŒãã¿ã³ã远å
âã¡ã¿ããŒã¿ã®ããã¹ããã¡ã€ã«ãžã®æžãåºããã¿ã³ã远å
âãŠã£ã³ããŠãçž®å°æ¡å€§ãããšåŠçãéããªã£ãŠãã®ã§è»œæžããããã«æç€º(ããã ãã§ãã£ãŠããããã ããåãã)
ãã»200msç§åŸ
ã€åŠç
ãã»ãã£ãšé
ããããå Žåã¯æžãå€ãã
ãã®æç¹ã§ä¿®æ£ãããç®æãšããŠãç»åãéããæã¡ã¿ããŒã¿è¡šç€ºãšãªã¢ãéåããç¶æ
ã§ãŠã£ã³ããŠãåºãŠããŠãã
ãŠã£ã³ããŠãèªåã§å€§ããããã°ãããããã¯ãããããã
ããã®ä¿®æ£ãæç€ºãããšãä»åºŠã¯ç»åãçž®å°ãããŠè¡šç€ºããããããŠã©ãã«ãããŸããããªãã£ã
ChatGPTã®ç¡ææ ã ããããªãšæã£ãŠããããCopilotã¯ã©ãã ããïŒãšæããœãŒã¹å
šéšãCopilotã«æããŠãç»åãšãªã¢ãšããã¹ããšãªã¢ãæåããå
šéšè¡šç€ºãããããã«ããŠãšèŠæãããäžçºã§ãã¡ãã®æå³éãã«çŽããŠããã
Copilotã®ä»æ§ãå€ãã£ãŠãã䜿ãã«ãããšæã£ãŠäœ¿ã£ãŠãªãã£ããã©ä»å䜿ã£ãŠã¿ãŠãããããªãããããã
ããã«Copilotããã«ã¢ãã¿ãŒãã倧ããç»åãå
¥åãããå Žåã®åŠçã®æ¹åãèŠæããããã
ããã§ãç»åãã§ãããšãŠã£ã³ããŠãã¢ãã¿ãŒå€ã«ã¯ã¿åºããã ãã©ã
ããã¯ãŸãå¥ã«ããããšåŠ¥åãã
ããã§ããããªãšæã£ããã©ãç»åãèªã¿èŸŒãã§ãã¹ãããŠããšæ°ã«ãªãã ããã¡ã¿ããŒã¿ã®è¬ã®æåå
ExifããŒã£ãŠããšã§ãããé©åã«è¡šç€ºããããã«ã§ããïŒãšèããŠã§ããã£ãœããã§ãã£ãŠããããã¡ã¿ããŒã¿ãå
šéšè¡šç€ºãããšããã¯æªåŠç
webpã«ããªããããã³ããæ
å ±ãããã£ãœãããšãªãããã³ãŒãåŠçãããŠããããããã§å€ãªç©ºçœãçŸãã
èããããããã"NULL"æåã§ãããããš
ããã¯ã¬ããœïŒãã"ãœ"ã¯ãªããã ãããšãããããããåãé€ãåŠçãæç€ºãã
ããã«ããããããããŒã¿ãããã®ã§è²ã
ãã£ãŠãããããXPãªãã¡ããã£ãŠã¿ã°ãããŸãåŠçã§ããªã
ãããçŽãããã«æç€ºããŠãããŸãã§ããªã
ã£ãŠããšã§æ€çŽ¢ããŠåºãŠããã®ããã¡ã
äžèšã®ã³ãŒãã䜿ãããŠããããŸãã
ããããšãããããŸã
def decode(t):
b = bytes(t)
return b[:-2].decode('utf-16-le')ã¿ã°ã®å é ã«XPãåºãŠããããšããããããã䜿ã£ãŠãã³ãŒãããããã«
ãããŠãªãã ããã ã§è²ã
詊ãã€ã€ãªããšãã§ãã
ãºã©ãºã©ãšæå³äžæãªæåãåºãæããããã©"ããã³ããã衚瀺ããã"ãšããç®çã¯éæãããŠãã®ã§ãã®èŸºã§çµäº
ãããŒé¢çœãã£ã
ç»å衚瀺ããã ãã ã£ãæåã®é ã§ãããã°ã©ã ãåããšæ¥œãã
æ®æ®µäœæ°ãªãè²ã
ãªã¢ããªã䜿ã£ãŠããã©ãããèããããŠã§ããŠããã ãªããšæã£ã
SDXLã®ControlNetã®åŠç¿ã®èšäºã ãã§çµãããšæã£ãŠããã©ãŸããã®ïŒã€ç®ã®èšäºã«ãªã£ã
ã¢ãã¡ãšæŒ«ç»ãèŠãªãã§ãã£ãšäœã£ãŠã
ããŠæºãŸã£ãŠããã®ãæ¶åããã

