p / Client /Scripts /novelai.py
q6's picture
windows semo
d457e07
import gzip
import json
import os
import sys
import numpy as np
from PIL import Image, PngImagePlugin
def byteize(alpha):
alpha = alpha.T.reshape((-1,))
alpha = alpha[: (alpha.shape[0] // 8) * 8]
alpha = np.bitwise_and(alpha, 1)
alpha = alpha.reshape((-1, 8))
return np.packbits(alpha, axis=1)
class LSBExtractor:
def __init__(self, alpha):
self.data = byteize(alpha)
self.pos = 0
def get_next_n_bytes(self, n):
n_bytes = self.data[self.pos : self.pos + n]
self.pos += n
return bytearray(n_bytes)
def read_32bit_integer(self):
bytes_list = self.get_next_n_bytes(4)
if len(bytes_list) != 4:
return None
return int.from_bytes(bytes_list, byteorder="big")
def extract_stealth_png(path):
with Image.open(path) as image:
if "A" not in image.getbands():
raise ValueError("image has no alpha channel")
alpha = np.array(image.getchannel("A"))
reader = LSBExtractor(alpha)
magic = "stealth_pngcomp"
read_magic = reader.get_next_n_bytes(len(magic)).decode("utf-8")
if read_magic != magic:
raise ValueError("magic number mismatch")
read_len_bits = reader.read_32bit_integer()
if read_len_bits is None:
raise ValueError("missing payload length")
read_len = read_len_bits // 8
payload = reader.get_next_n_bytes(read_len)
json_bytes = gzip.decompress(payload)
try:
json_data = json.loads(json_bytes.decode("utf-8"))
if "Comment" in json_data and isinstance(json_data["Comment"], str):
json_data["_CommentRaw"] = json_data["Comment"]
json_data["Comment"] = json.loads(json_data["Comment"])
except json.JSONDecodeError:
return {"WebUI": json_bytes.decode("utf-8", errors="replace")}
return json_data
def main() -> int:
path = sys.argv[1] if len(sys.argv) > 1 else "21_138614363.png"
if not os.path.exists(path):
print(f"File not found: {path}")
return 1
data = extract_stealth_png(path)
print(json.dumps(data, indent=2, ensure_ascii=True, sort_keys=True))
if isinstance(data, dict) and "Comment" in data:
comment_json = data.get("_CommentRaw")
if not isinstance(comment_json, str):
if isinstance(data["Comment"], str):
comment_json = data["Comment"]
else:
comment_json = json.dumps(
data["Comment"],
ensure_ascii=True,
separators=(",", ":"),
)
reply = input("Create 1x1 metadata PNG? [y/N] ").strip().lower()
if reply in ("y", "yes"):
base, _ = os.path.splitext(path)
out_path = f"{base}_meta.png"
img = Image.new("RGBA", (1, 1), (0, 0, 0, 0))
meta = PngImagePlugin.PngInfo()
meta.add_text("Comment", comment_json)
img.save(out_path, pnginfo=meta)
print(f"Wrote {out_path}")
input()
return 0
if __name__ == "__main__":
raise SystemExit(main())