Spaces:
Paused
Paused
P01yH3dr0n
commited on
Commit
•
d0aabb2
1
Parent(s):
1f2d4f1
read stealth image info
Browse files- app.py +1 -1
- pnginfo.py +127 -3
app.py
CHANGED
@@ -205,7 +205,7 @@ def util_ui():
|
|
205 |
with gr.Blocks():
|
206 |
with gr.Row(equal_height=False):
|
207 |
with gr.Column(variant='panel'):
|
208 |
-
image = gr.Image(label="上传图片", sources=["upload"], interactive=True, type="pil")
|
209 |
with gr.Column(variant='panel'):
|
210 |
info = gr.HTML('')
|
211 |
items = gr.JSON(value={}, visible=False)
|
|
|
205 |
with gr.Blocks():
|
206 |
with gr.Row(equal_height=False):
|
207 |
with gr.Column(variant='panel'):
|
208 |
+
image = gr.Image(label="上传图片", image_mode="RGBA", sources=["upload"], interactive=True, type="pil")
|
209 |
with gr.Column(variant='panel'):
|
210 |
info = gr.HTML('')
|
211 |
items = gr.JSON(value={}, visible=False)
|
pnginfo.py
CHANGED
@@ -1,7 +1,9 @@
|
|
1 |
from PIL import Image
|
|
|
2 |
import json
|
3 |
import html
|
4 |
import re
|
|
|
5 |
|
6 |
re_param_code = r'\s*([\w ]+):\s*("(?:\\.|[^\\"])+"|[^,]*)(?:,|$)'
|
7 |
re_param = re.compile(re_param_code)
|
@@ -9,7 +11,7 @@ re_imagesize = re.compile(r"^(\d+)x(\d+)$")
|
|
9 |
IGNORED_INFO_KEYS = {
|
10 |
'jfif', 'jfif_version', 'jfif_unit', 'jfif_density', 'dpi', 'exif',
|
11 |
'loop', 'background', 'timestamp', 'duration', 'progressive', 'progression',
|
12 |
-
'icc_profile', 'chromaticity', 'photoshop',
|
13 |
}
|
14 |
|
15 |
def plaintext_to_html(text, classname=None):
|
@@ -22,7 +24,114 @@ def to_digit(v):
|
|
22 |
return float(v)
|
23 |
except:
|
24 |
return v
|
25 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
26 |
def read_info_from_image(image):
|
27 |
if image is None:
|
28 |
return '', {}
|
@@ -34,6 +143,21 @@ def read_info_from_image(image):
|
|
34 |
for field in IGNORED_INFO_KEYS:
|
35 |
items.pop(field, None)
|
36 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
37 |
if items.get("Software", None) == "NovelAI":
|
38 |
json_info = json.loads(items["Comment"])
|
39 |
|
@@ -101,7 +225,7 @@ Steps: {json_info["steps"]}, Sampler: {json_info['sampler']}, CFG scale: {json_i
|
|
101 |
|
102 |
|
103 |
def send_paras(*args):
|
104 |
-
if len(args[0]) == 0:
|
105 |
return args[1:]
|
106 |
items, prompt, quality_tags, neg_prompt, seed, scale, width, height, steps, sampler, scheduler, smea, dyn, dyn_threshold, cfg_rescale, variety = args
|
107 |
paras = [prompt, quality_tags, neg_prompt, seed, scale, width, height, steps, sampler, scheduler, smea, dyn, dyn_threshold, cfg_rescale, variety]
|
|
|
1 |
from PIL import Image
|
2 |
+
import piexif
|
3 |
import json
|
4 |
import html
|
5 |
import re
|
6 |
+
import gzip
|
7 |
|
8 |
re_param_code = r'\s*([\w ]+):\s*("(?:\\.|[^\\"])+"|[^,]*)(?:,|$)'
|
9 |
re_param = re.compile(re_param_code)
|
|
|
11 |
IGNORED_INFO_KEYS = {
|
12 |
'jfif', 'jfif_version', 'jfif_unit', 'jfif_density', 'dpi', 'exif',
|
13 |
'loop', 'background', 'timestamp', 'duration', 'progressive', 'progression',
|
14 |
+
'icc_profile', 'chromaticity', 'photoshop', 'srgb', 'gamma', 'dpi'
|
15 |
}
|
16 |
|
17 |
def plaintext_to_html(text, classname=None):
|
|
|
24 |
return float(v)
|
25 |
except:
|
26 |
return v
|
27 |
+
|
28 |
+
def read_stealth_info(image):
|
29 |
+
width, height = image.size
|
30 |
+
pixels = image.load()
|
31 |
+
|
32 |
+
has_alpha = True if image.mode == 'RGBA' else False
|
33 |
+
mode = None
|
34 |
+
compressed = False
|
35 |
+
binary_data = ''
|
36 |
+
buffer_a = ''
|
37 |
+
buffer_rgb = ''
|
38 |
+
index_a = 0
|
39 |
+
index_rgb = 0
|
40 |
+
sig_confirmed = False
|
41 |
+
confirming_signature = True
|
42 |
+
reading_param_len = False
|
43 |
+
reading_param = False
|
44 |
+
read_end = False
|
45 |
+
for x in range(width):
|
46 |
+
for y in range(height):
|
47 |
+
if has_alpha:
|
48 |
+
r, g, b, a = pixels[x, y]
|
49 |
+
buffer_a += str(a & 1)
|
50 |
+
index_a += 1
|
51 |
+
else:
|
52 |
+
r, g, b = pixels[x, y]
|
53 |
+
buffer_rgb += str(r & 1)
|
54 |
+
buffer_rgb += str(g & 1)
|
55 |
+
buffer_rgb += str(b & 1)
|
56 |
+
index_rgb += 3
|
57 |
+
if confirming_signature:
|
58 |
+
if index_a == len('stealth_pnginfo') * 8:
|
59 |
+
decoded_sig = bytearray(int(buffer_a[i:i + 8], 2) for i in
|
60 |
+
range(0, len(buffer_a), 8)).decode('utf-8', errors='ignore')
|
61 |
+
if decoded_sig in {'stealth_pnginfo', 'stealth_pngcomp'}:
|
62 |
+
confirming_signature = False
|
63 |
+
sig_confirmed = True
|
64 |
+
reading_param_len = True
|
65 |
+
mode = 'alpha'
|
66 |
+
if decoded_sig == 'stealth_pngcomp':
|
67 |
+
compressed = True
|
68 |
+
buffer_a = ''
|
69 |
+
index_a = 0
|
70 |
+
else:
|
71 |
+
read_end = True
|
72 |
+
break
|
73 |
+
elif index_rgb == len('stealth_pnginfo') * 8:
|
74 |
+
decoded_sig = bytearray(int(buffer_rgb[i:i + 8], 2) for i in
|
75 |
+
range(0, len(buffer_rgb), 8)).decode('utf-8', errors='ignore')
|
76 |
+
if decoded_sig in {'stealth_rgbinfo', 'stealth_rgbcomp'}:
|
77 |
+
confirming_signature = False
|
78 |
+
sig_confirmed = True
|
79 |
+
reading_param_len = True
|
80 |
+
mode = 'rgb'
|
81 |
+
if decoded_sig == 'stealth_rgbcomp':
|
82 |
+
compressed = True
|
83 |
+
buffer_rgb = ''
|
84 |
+
index_rgb = 0
|
85 |
+
elif reading_param_len:
|
86 |
+
if mode == 'alpha':
|
87 |
+
if index_a == 32:
|
88 |
+
param_len = int(buffer_a, 2)
|
89 |
+
reading_param_len = False
|
90 |
+
reading_param = True
|
91 |
+
buffer_a = ''
|
92 |
+
index_a = 0
|
93 |
+
else:
|
94 |
+
if index_rgb == 33:
|
95 |
+
pop = buffer_rgb[-1]
|
96 |
+
buffer_rgb = buffer_rgb[:-1]
|
97 |
+
param_len = int(buffer_rgb, 2)
|
98 |
+
reading_param_len = False
|
99 |
+
reading_param = True
|
100 |
+
buffer_rgb = pop
|
101 |
+
index_rgb = 1
|
102 |
+
elif reading_param:
|
103 |
+
if mode == 'alpha':
|
104 |
+
if index_a == param_len:
|
105 |
+
binary_data = buffer_a
|
106 |
+
read_end = True
|
107 |
+
break
|
108 |
+
else:
|
109 |
+
if index_rgb >= param_len:
|
110 |
+
diff = param_len - index_rgb
|
111 |
+
if diff < 0:
|
112 |
+
buffer_rgb = buffer_rgb[:diff]
|
113 |
+
binary_data = buffer_rgb
|
114 |
+
read_end = True
|
115 |
+
break
|
116 |
+
else:
|
117 |
+
# impossible
|
118 |
+
read_end = True
|
119 |
+
break
|
120 |
+
if read_end:
|
121 |
+
break
|
122 |
+
if sig_confirmed and binary_data != '':
|
123 |
+
# Convert binary string to UTF-8 encoded text
|
124 |
+
byte_data = bytearray(int(binary_data[i:i + 8], 2) for i in range(0, len(binary_data), 8))
|
125 |
+
try:
|
126 |
+
if compressed:
|
127 |
+
decoded_data = gzip.decompress(bytes(byte_data)).decode('utf-8')
|
128 |
+
else:
|
129 |
+
decoded_data = byte_data.decode('utf-8', errors='ignore')
|
130 |
+
geninfo = decoded_data
|
131 |
+
except:
|
132 |
+
pass
|
133 |
+
return json.loads(geninfo)
|
134 |
+
|
135 |
def read_info_from_image(image):
|
136 |
if image is None:
|
137 |
return '', {}
|
|
|
143 |
for field in IGNORED_INFO_KEYS:
|
144 |
items.pop(field, None)
|
145 |
|
146 |
+
if len(items) == 0:
|
147 |
+
items = read_stealth_info(image)
|
148 |
+
|
149 |
+
if "exif" in items:
|
150 |
+
exif = piexif.load(items["exif"])
|
151 |
+
exif_comment = (exif or {}).get("Exif", {}).get(piexif.ExifIFD.UserComment, b'')
|
152 |
+
try:
|
153 |
+
exif_comment = piexif.helper.UserComment.load(exif_comment)
|
154 |
+
except ValueError:
|
155 |
+
exif_comment = exif_comment.decode('utf8', errors="ignore")
|
156 |
+
|
157 |
+
if exif_comment:
|
158 |
+
items['exif comment'] = exif_comment
|
159 |
+
geninfo = exif_comment
|
160 |
+
|
161 |
if items.get("Software", None) == "NovelAI":
|
162 |
json_info = json.loads(items["Comment"])
|
163 |
|
|
|
225 |
|
226 |
|
227 |
def send_paras(*args):
|
228 |
+
if args[0] is None or len(args[0]) == 0:
|
229 |
return args[1:]
|
230 |
items, prompt, quality_tags, neg_prompt, seed, scale, width, height, steps, sampler, scheduler, smea, dyn, dyn_threshold, cfg_rescale, variety = args
|
231 |
paras = [prompt, quality_tags, neg_prompt, seed, scale, width, height, steps, sampler, scheduler, smea, dyn, dyn_threshold, cfg_rescale, variety]
|