plist图集拆出小图

plist图集拆出小图

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
import os
import re
from PIL import Image

def parse_plist(content):
"""
精准解析 plist 格式,只匹配真正的图片项
"""
# 更加精确的匹配:寻找嵌套在 dict 里的 key,且 key 必须以 .png 结尾
# 排除掉外层的 <key>frames</key>
frames = {}

# 1. 先定位到 <key>frames</key> 之后的内容,避免抓到头部的 frames 标签
frames_block_match = re.search(r"<key>frames</key>\s*<dict>(.*?)</dict>\s*<key>metadata</key>", content, re.DOTALL)
if not frames_block_match:
# 如果没找到特定的块,尝试全局搜索
block = content
else:
block = frames_block_match.group(1)

# 2. 匹配具体的图片条目
pattern = re.compile(r"<key>(.*?\.png)</key>\s*<dict>(.*?)</dict>", re.DOTALL)
items = pattern.findall(block)

for name, data in items:
# 清洗文件名:去掉可能存在的路径、换行符或空格
clean_name = os.path.basename(name.strip())

# 提取 frame: {{x,y},{w,h}}
frame_match = re.search(r"<key>frame</key>\s*<string>\{(.*?)\}</string>", data)
# 提取 rotated
rotated_match = re.search(r"<key>rotated</key>\s*<(true|false)/>", data)

if frame_match:
# 提取数字
coords = [int(n) for n in re.findall(r"\d+", frame_match.group(1))]
is_rotated = (rotated_match.group(1) == "true") if rotated_match else False

frames[clean_name] = {
"x": coords[0],
"y": coords[1],
"w": coords[2],
"h": coords[3],
"rotated": is_rotated
}
return frames

def split_atlas(img_path, plist_path, output_dir):
if not os.path.exists(output_dir):
os.makedirs(output_dir)

with open(plist_path, 'r', encoding='utf-8') as f:
content = f.read()

frames = parse_plist(content)

if not frames:
print("未能解析到任何有效图片信息,请检查 plist 格式。")
return

try:
atlas_img = Image.open(img_path)
except Exception as e:
print(f"无法打开图片文件: {e}")
return

for name, info in frames.items():
# TexturePacker 逻辑:如果旋转了,plist 里的 w/h 是原始尺寸,
# 但在合图中它是倒下来的,所以裁剪框的宽高要交换。
if info['rotated']:
rect_w, rect_h = info['h'], info['w']
else:
rect_w, rect_h = info['w'], info['h']

# 裁剪 (left, upper, right, lower)
box = (info['x'], info['y'], info['x'] + rect_w, info['y'] + rect_h)
sub_img = atlas_img.crop(box)

# 旋转恢复
if info['rotated']:
sub_img = sub_img.rotate(90, expand=True)

# 保存
try:
output_path = os.path.join(output_dir, name)
sub_img.save(output_path)
print(f"成功保存: {name}")
except Exception as e:
print(f"保存 {name} 失败: {e}")

if __name__ == "__main__":
split_atlas("menu/menu.png", "menu/menu.plist", "menu/output_fish")