P01yH3dr0n commited on
Commit
d696794
1 Parent(s): 4debf12

Create pnginfo.py

Browse files
Files changed (1) hide show
  1. pnginfo.py +127 -0
pnginfo.py ADDED
@@ -0,0 +1,127 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from PIL import Image
2
+ import piexif
3
+ import json
4
+ import html
5
+ import re
6
+
7
+ re_param_code = r'\s*([\w ]+):\s*("(?:\\.|[^\\"])+"|[^,]*)(?:,|$)'
8
+ re_param = re.compile(re_param_code)
9
+ re_imagesize = re.compile(r"^(\d+)x(\d+)$")
10
+ IGNORED_INFO_KEYS = {
11
+ 'jfif', 'jfif_version', 'jfif_unit', 'jfif_density', 'dpi', 'exif',
12
+ 'loop', 'background', 'timestamp', 'duration', 'progressive', 'progression',
13
+ 'icc_profile', 'chromaticity', 'photoshop',
14
+ }
15
+
16
+ def plaintext_to_html(text, classname=None):
17
+ content = "<br>\n".join(html.escape(x) for x in text.split('\n'))
18
+
19
+ return f"<p class='{classname}'>{content}</p>" if classname else f"<p>{content}</p>"
20
+
21
+ def to_digit(v):
22
+ try:
23
+ return float(v)
24
+ except:
25
+ return v
26
+
27
+ def read_info_from_image(image) -> tuple[str | None, dict]:
28
+ if image is None:
29
+ return '', {}
30
+ elif type(image) == str:
31
+ image = Image.open(image)
32
+ items = (image.info or {}).copy()
33
+ info =''
34
+ if "exif" in items:
35
+ exif = piexif.load(items["exif"])
36
+ exif_comment = (exif or {}).get("Exif", {}).get(piexif.ExifIFD.UserComment, b'')
37
+ try:
38
+ exif_comment = piexif.helper.UserComment.load(exif_comment)
39
+ except ValueError:
40
+ exif_comment = exif_comment.decode('utf8', errors="ignore")
41
+
42
+ if exif_comment:
43
+ items['exif comment'] = exif_comment
44
+ geninfo = exif_comment
45
+
46
+ for field in IGNORED_INFO_KEYS:
47
+ items.pop(field, None)
48
+
49
+ if items.get("Software", None) == "NovelAI":
50
+ json_info = json.loads(items["Comment"])
51
+
52
+ geninfo = f"""{items["Description"]}
53
+ Negative prompt: {json_info["uc"]}
54
+ Steps: {json_info["steps"]}, Sampler: {json_info['sampler']}, CFG scale: {json_info["scale"]}, Seed: {json_info["seed"]}, Size: {image.width}x{image.height}, Clip skip: 2, ENSD: 31337"""
55
+
56
+ items = {**{'parameters': geninfo}, **items}
57
+
58
+ for key, text in items.items():
59
+ info += f"""
60
+ <div>
61
+ <p><b>{plaintext_to_html(str(key))}</b></p>
62
+ <p>{plaintext_to_html(str(text))}</p>
63
+ </div>
64
+ """.strip()+"\n"
65
+
66
+ if len(info) == 0:
67
+ message = "Nothing found in the image."
68
+ info = f"<div><p>{message}<p></div>"
69
+ elif 'parameters' in items:
70
+ res = {}
71
+
72
+ prompt = ""
73
+ negative_prompt = ""
74
+
75
+ done_with_prompt = False
76
+
77
+ *lines, lastline = items['parameters'].strip().split("\n")
78
+ if len(re_param.findall(lastline)) < 3:
79
+ lines.append(lastline)
80
+ lastline = ''
81
+
82
+ for line in lines:
83
+ line = line.strip()
84
+ if line.startswith("Negative prompt:"):
85
+ done_with_prompt = True
86
+ line = line[16:].strip()
87
+ if done_with_prompt:
88
+ negative_prompt += ("" if negative_prompt == "" else "\n") + line
89
+ else:
90
+ prompt += ("" if prompt == "" else "\n") + line
91
+
92
+ res["prompt"] = prompt
93
+ res["negative prompt"] = negative_prompt
94
+
95
+ for k, v in re_param.findall(lastline):
96
+ try:
97
+ if v[0] == '"' and v[-1] == '"':
98
+ v = to_digit(json.loads(v))
99
+
100
+ m = re_imagesize.match(v)
101
+ if m is not None:
102
+ res[f"{k.lower()}-1"] = to_digit(m.group(1))
103
+ res[f"{k.lower()}-2"] = to_digit(m.group(2))
104
+ else:
105
+ res[k.lower()] = v
106
+ except Exception:
107
+ print(f"Error parsing \"{k}: {v}\"")
108
+
109
+ return items['parameters'], res
110
+ else:
111
+ return info, {}
112
+ return info, json.loads(items['Comment'])
113
+
114
+
115
+ def send_paras(*args):
116
+ if len(args[0]) == 0:
117
+ return args[1:]
118
+ items, prompt, quality_tags, neg_prompt, seed, scale, width, height, steps, sampler, scheduler, smea, dyn, dyn_threshold, cfg_rescale = args
119
+ paras = [prompt, quality_tags, neg_prompt, seed, scale, width, height, steps, sampler, scheduler, smea, dyn, dyn_threshold, cfg_rescale]
120
+ for i, keys in enumerate([('prompt',), ('',), ('uc', 'negative prompt'), ('seed',), ('scale', 'cfg scale'), ('width', 'size-1'), ('height', 'size-2'), ('steps',), ('sampler',), ('noise_schedule',), ('sm',), ('sm_dyn',), ('dynamic_thresholding',), ('cfg_rescale',)]):
121
+ for key in keys:
122
+ if key in items:
123
+ paras[i] = items[key]
124
+ prompt, quality_tags, neg_prompt, seed, scale, width, height, steps, sampler, scheduler, smea, dyn, dyn_threshold, cfg_rescale = paras
125
+ if prompt.endswith(', ' + quality_tags):
126
+ prompt = prompt[:-(len(quality_tags) + 2)]
127
+ return prompt, quality_tags, neg_prompt, seed, scale, width, height, steps, sampler, scheduler, smea, dyn, dyn_threshold, cfg_rescale