P01yH3dr0n commited on
Commit
d0aabb2
1 Parent(s): 1f2d4f1

read stealth image info

Browse files
Files changed (2) hide show
  1. app.py +1 -1
  2. 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]