p
File size: 3,092 Bytes
25bba63
 
 
 
 
 
9c62058
25bba63
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2cefecf
 
 
9c62058
25bba63
2cefecf
94844d3
25bba63
 
 
 
d457e07
25bba63
 
 
 
 
 
9c62058
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
c6e1e0f
25bba63
 
 
 
9c62058
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
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())