-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathunpacker.py
71 lines (52 loc) · 2.45 KB
/
unpacker.py
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
from typing import List, Tuple
import cv2
from pathlib import Path
from tqdm import tqdm
import plistlib
from colorama import Fore, Style
from datetime import datetime
def process_frame(name: str, value: dict, img, out_dir: Path) -> None:
bounds_str = value["frame"] if "frame" in value else value["textureRect"]
bounds = [int(x) for x in bounds_str.translate({ord(c): None for c in "{} "}).split(",")]
rotated = value["rotated"] if "rotated" in value else value["textureRotated"]
if rotated:
bounds[2], bounds[3] = bounds[3], bounds[2]
bounds[2] += bounds[0]
bounds[3] += bounds[1]
cropped = img[bounds[1]:bounds[3], bounds[0]:bounds[2]]
if rotated:
cropped = cv2.rotate(cropped, cv2.ROTATE_90_COUNTERCLOCKWISE)
output_path = out_dir.joinpath(name)
success = cv2.imwrite(str(output_path), cropped)
if not success:
print(f"{Fore.RED}cv2.imwrite returned False for {output_path}!{Style.RESET_ALL}")
if not output_path.exists():
print(f"{Fore.RED}File does not exist after writing: {output_path}!{Style.RESET_ALL}")
def unpack(inputs: List[Path], output: Path) -> None:
for file in inputs:
out_dir = output.joinpath(file.stem)
print(f"Unpacking {file.name} => {out_dir}")
with open(file, "rb") as f:
plist = plistlib.load(f)
image_path = plist["metadata"]["textureFileName"]
img_path = file.parent.joinpath(image_path)
if not img_path.exists():
print(f"{Fore.RED}Image file not found: {img_path}!{Style.RESET_ALL}")
continue
img = cv2.imread(str(img_path), cv2.IMREAD_UNCHANGED)
if img is None:
print(f"{Fore.RED}Failed to load image: {img_path}!{Style.RESET_ALL}")
continue
out_dir.mkdir(exist_ok=True, parents=True)
skipped = []
for name, value in tqdm(plist["frames"].items(), ascii=" ▁▂▃▄▅▆▇█", bar_format=file.stem + ": {percentage:1.0f}% {bar} [{n_fmt}/{total_fmt}]"):
if name == "." or name == ".." or Path(name).suffix != ".png":
skipped.append(name)
continue
try:
process_frame(name, value, img, out_dir)
except Exception as e:
print(f"{Fore.RED}Error processing frame {name}: {str(e)}{Style.RESET_ALL}")
continue
if skipped:
print(f'{Fore.YELLOW}Skipped frames: {", ".join(skipped)}{Style.RESET_ALL}')