Skip to content

Commit 8442859

Browse files
committed
Initial commit
0 parents  commit 8442859

13 files changed

+280
-0
lines changed

.gitignore

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
/venv/
2+
/test/
3+
/build/
4+
/dist/

.idea/.gitignore

+8
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.idea/inspectionProfiles/Project_Default.xml

+12
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.idea/inspectionProfiles/profiles_settings.xml

+6
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.idea/misc.xml

+12
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.idea/modules.xml

+8
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.idea/stable-diffusion-prompt-reader.iml

+10
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.idea/vcs.xml

+6
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

hook-tkinterdnd2.py

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
from PyInstaller.utils.hooks import collect_data_files
2+
3+
datas = collect_data_files('tkinterdnd2')

icon.png

160 KB
Loading

main.py

+155
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
from PIL import Image, ImageTk
2+
from tkinter import TOP, Label, Frame, Text, LEFT, Scrollbar, VERTICAL, RIGHT, Y, BOTH, X, Canvas
3+
from tkinterdnd2 import *
4+
5+
6+
def read_info_from_image(image):
7+
items = image.info or {}
8+
geninfo = items.pop('parameters', None)
9+
if "exif" in items:
10+
exif = piexif.load(items["exif"])
11+
exif_comment = (exif or {}).get("Exif", {}).get(piexif.ExifIFD.UserComment, b'')
12+
try:
13+
exif_comment = piexif.helper.UserComment.load(exif_comment)
14+
except ValueError:
15+
exif_comment = exif_comment.decode('utf8', errors="ignore")
16+
17+
if exif_comment:
18+
items['exif comment'] = exif_comment
19+
geninfo = exif_comment
20+
21+
for field in ['jfif', 'jfif_version', 'jfif_unit', 'jfif_density', 'dpi', 'exif',
22+
'loop', 'background', 'timestamp', 'duration']:
23+
items.pop(field, None)
24+
25+
if items.get("Software", None) == "NovelAI":
26+
try:
27+
json_info = json.loads(items["Comment"])
28+
sampler = sd_samplers.samplers_map.get(json_info["sampler"], "Euler a")
29+
30+
geninfo = f"""{items["Description"]}
31+
Negative prompt: {json_info["uc"]}
32+
Steps: {json_info["steps"]}, Sampler: {sampler}, CFG scale: {json_info["scale"]}, Seed: {json_info["seed"]}, Size: {image.width}x{image.height}, Clip skip: 2, ENSD: 31337"""
33+
except Exception:
34+
print("Error parsing NovelAI image generation parameters:", file=sys.stderr)
35+
print(traceback.format_exc(), file=sys.stderr)
36+
37+
return geninfo, items
38+
39+
40+
def image_data(file):
41+
try:
42+
image = Image.open(file)
43+
image.info
44+
textinfo, _ = read_info_from_image(image)
45+
return textinfo, None
46+
except Exception:
47+
pass
48+
49+
try:
50+
text = data.decode('utf8')
51+
assert len(text) < 10000
52+
return text, None
53+
54+
except Exception:
55+
pass
56+
57+
return '', None
58+
59+
60+
def image_info_format(text):
61+
prompt_index = [text.index("\nNegative prompt:"),
62+
text.index("\nSteps:")]
63+
positive = text[:prompt_index[0]]
64+
negative = text[prompt_index[0] + 1 + len("Negative prompt: "):prompt_index[1]]
65+
setting = text[prompt_index[1] + 1:]
66+
return positive, negative, setting
67+
68+
69+
def display_info(event):
70+
global image, image_tk, image_canvas
71+
# clear text
72+
positive_box.delete("1.0", "end")
73+
negative_box.delete("1.0", "end")
74+
setting_box.delete("1.0", "end")
75+
if event.data.endswith(".png"):
76+
with open(event.data, "rb") as f:
77+
text_line, _ = image_data(f)
78+
info = image_info_format(text_line)
79+
# insert prompt
80+
positive_box.insert("end", info[0])
81+
negative_box.insert("end", info[1])
82+
setting_box.insert("end", info[2])
83+
image = Image.open(f)
84+
# resize image to window size
85+
if image.size[0] < image.size[1]:
86+
resized = image.resize((int(image.size[0] / image.size[1] * image_frame.winfo_height()),
87+
image_frame.winfo_height()), Image.LANCZOS)
88+
else:
89+
resized = image.resize((image_frame.winfo_width(),
90+
int(image.size[1] / image.size[0] * image_frame.winfo_width())), Image.LANCZOS)
91+
# display image
92+
image_tk = ImageTk.PhotoImage(resized)
93+
image_canvas.create_image(image_frame.winfo_width() / 2, 0, anchor="n", image=image_tk)
94+
image_canvas.pack(side=LEFT, fill=BOTH, expand=True)
95+
96+
97+
def resize_image(event):
98+
# resize image to window size
99+
global image, image_canvas, image_tk
100+
if image:
101+
if image.size[0] < image.size[1]:
102+
resized = image.resize((int(image.size[0] / image.size[1] * image_frame.winfo_height()),
103+
image_frame.winfo_height()), Image.NEAREST)
104+
else:
105+
resized = image.resize((image_frame.winfo_width(),
106+
int(image.size[1] / image.size[0] * image_frame.winfo_width())), Image.NEAREST)
107+
image_tk = ImageTk.PhotoImage(resized)
108+
image_canvas.create_image(image_frame.winfo_width() / 2, 0, anchor="n", image=image_tk)
109+
# image_canvas.pack(fill=BOTH)
110+
111+
112+
window = TkinterDnD.Tk()
113+
window.title('SD Prompt Reader')
114+
window.geometry("800x400")
115+
# window.attributes('-alpha', 0.95)
116+
# window.config(bg='white')
117+
118+
prompt_frame = Frame(window)
119+
prompt_frame.pack(side=RIGHT, fill=BOTH, expand=True, padx=10, pady=10)
120+
121+
positive_box = Text(prompt_frame, height=10)
122+
positive_box.pack(side=TOP, fill=BOTH, expand=True)
123+
124+
negative_box = Text(prompt_frame, height=10)
125+
negative_box.pack(side=TOP, fill=BOTH, expand=True)
126+
127+
setting_box = Text(prompt_frame, height=5)
128+
setting_box.pack(side=TOP, fill=BOTH, expand=True)
129+
130+
scrollbar_positive = Scrollbar(positive_box, orient=VERTICAL)
131+
scrollbar_positive.pack(side=RIGHT, fill=Y)
132+
positive_box.configure(yscrollcommand=scrollbar_positive.set)
133+
scrollbar_positive.config(command=positive_box.yview)
134+
135+
scrollbar_negative = Scrollbar(negative_box, orient=VERTICAL)
136+
scrollbar_negative.pack(side=RIGHT, fill=Y)
137+
negative_box.configure(yscrollcommand=scrollbar_negative.set)
138+
scrollbar_negative.config(command=negative_box.yview)
139+
140+
image_frame = Frame(window)
141+
image_frame.pack(side=LEFT, fill=BOTH, expand=True, padx=10, pady=10)
142+
image_canvas = Canvas(image_frame)
143+
144+
image = None
145+
image_tk = None
146+
# image = Image.open("dnd.png")
147+
# image_tk = ImageTk.PhotoImage(image)
148+
# image_canvas.create_image(0, 0, anchor="nw", image=image_tk)
149+
# image_canvas.pack(fill=BOTH, expand=True)
150+
151+
window.drop_target_register(DND_FILES)
152+
window.dnd_bind('<<Drop>>', display_info)
153+
window.bind("<Configure>", resize_image)
154+
155+
window.mainloop()

main.spec

+50
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
# -*- mode: python ; coding: utf-8 -*-
2+
3+
4+
block_cipher = None
5+
6+
7+
a = Analysis(
8+
['main.py'],
9+
pathex=[],
10+
binaries=[],
11+
datas=[('dnd.png', '.')],
12+
hiddenimports=["collect_data_files"],
13+
hookspath=['.'],
14+
hooksconfig={},
15+
runtime_hooks=[],
16+
excludes=[],
17+
win_no_prefer_redirects=False,
18+
win_private_assemblies=False,
19+
cipher=block_cipher,
20+
noarchive=False,
21+
)
22+
pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher)
23+
24+
exe = EXE(
25+
pyz,
26+
a.scripts,
27+
a.binaries,
28+
a.zipfiles,
29+
a.datas,
30+
[],
31+
name='main',
32+
debug=False,
33+
bootloader_ignore_signals=False,
34+
strip=False,
35+
upx=True,
36+
upx_exclude=[],
37+
runtime_tmpdir=None,
38+
windowed=True,
39+
disable_windowed_traceback=False,
40+
argv_emulation=False,
41+
target_arch=None,
42+
codesign_identity=None,
43+
entitlements_file=None,
44+
)
45+
app = BUNDLE(
46+
exe,
47+
name='SD Prompt Reader.app',
48+
icon='icon.png',
49+
bundle_identifier=None,
50+
)

requirements.txt

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
altgraph==0.17.3
2+
macholib==1.16.2
3+
Pillow==9.4.0
4+
pyinstaller==5.9.0
5+
pyinstaller-hooks-contrib==2023.1
6+
tkinterdnd2==0.3.0

0 commit comments

Comments
 (0)