Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
UncertainProd
GitHub Repository: UncertainProd/FnF-Spritesheet-and-XML-Maker
Path: blob/master/src/framedata.py
254 views
1
from PIL import Image
2
from utils import g_settings, imghashes, spritesheet_split_cache
3
4
class FrameData:
5
def __init__(self, impath, from_single_png, pose_name, **xmlinfo):
6
# get imgpath
7
# get img from imgpath and ?xmlinfo
8
# set appropriate frame stuff: depending on from_single_png
9
# hash img
10
# other stuff...
11
# needed in XML table window
12
self.imgpath = impath
13
self.tx = None
14
self.ty = None
15
16
# w, h needed to crop img
17
self.tw = None
18
self.th = None
19
self.from_single_png = from_single_png
20
21
img = Image.open(impath).convert('RGBA')
22
self.framex = 0
23
self.framey = 0
24
self.framew = img.width
25
self.frameh = img.height
26
should_clip = g_settings['isclip'] != 0
27
cached_hash = None
28
if not self.from_single_png:
29
self.tx = xmlinfo.get("tx", 0)
30
self.ty = xmlinfo.get("ty", 0)
31
self.tw = xmlinfo.get("tw", 0)
32
self.th = xmlinfo.get("th", 0)
33
# impath, tex_coords (, clip) -> img
34
# if clip == True here, then skip clip step ("if should_clip:...")
35
# check if this img is in cache
36
cached_hash = spritesheet_split_cache[impath].get((self.tx, self.ty, self.tw, self.th, should_clip))
37
if not cached_hash:
38
# crop the image
39
img = img.crop((self.tx, self.ty, self.tx + self.tw, self.ty + self.th))
40
else:
41
# print("[DEBUG] Img found in cache!")
42
img = imghashes.get(cached_hash)
43
# set frame properties from xml
44
self.framex = xmlinfo.get("framex", 0)
45
self.framey = xmlinfo.get("framey", 0)
46
self.framew = xmlinfo.get("framew", 0)
47
self.frameh = xmlinfo.get("frameh", 0)
48
49
# clipping the image if i didn't already find it in the cache
50
if not cached_hash and should_clip:
51
imbbox = img.getbbox()
52
if imbbox:
53
# crop img
54
img = img.crop(imbbox)
55
# adjust frame properties such that image can be reconstructed from them
56
x1, y1, _, _ = imbbox
57
self.framex -= x1
58
self.framey -= y1
59
# Note: frame width and height stay the same
60
else:
61
print("Unable to crop image!")
62
63
# storing some img properties here for efficiency(kinda)
64
self.img_width = img.width
65
self.img_height = img.height
66
67
# get hash
68
self.img_hash = cached_hash if cached_hash else hash(img.tobytes())
69
# if hash isnt in imghashes then add it
70
if self.img_hash not in imghashes:
71
imghashes[self.img_hash] = img
72
# cache image for re-use (only imgs from xmls are cached this way)
73
if not self.from_single_png:
74
spritesheet_split_cache[impath][(self.tx, self.ty, self.tw, self.th, should_clip)] = self.img_hash
75
elif cached_hash:
76
pass
77
else:
78
img.close()
79
80
self.pose_name = pose_name
81
self.xml_pose_name = ""
82
83
def change_img(self, newimg):
84
# this method will mostly only be called when flipping the images
85
# so frame data will be unaltered
86
self.img_width = newimg.width
87
self.img_height = newimg.height
88
89
self.img_hash = hash(newimg.tobytes())
90
if self.img_hash not in imghashes:
91
imghashes[self.img_hash] = newimg
92
else:
93
newimg.close()
94
95
# not used as of now
96
class FrameImgData:
97
def __init__(self, imgpath, from_single_png, **texinfo):
98
self.imgpath = imgpath
99
self.from_single_png = from_single_png
100
if self.from_single_png:
101
self.img = Image.open(imgpath)
102
self.img_width = self.img.width
103
self.img_height = self.img.height
104
else:
105
im = Image.open(imgpath)
106
self.tx = int(texinfo.get("tx", 0))
107
self.ty = int(texinfo.get("ty", 0))
108
self.tw = int(texinfo.get("tw", 0))
109
self.th = int(texinfo.get("th", 0))
110
self.img_width = self.tw
111
self.img_height = self.th
112
self.img = im.crop((self.tx, self.ty, self.tx + self.tw, self.ty + self.th))
113
im.close()
114
115
self.img_hash = hash(self.img.tobytes())
116
self.img.close()
117
self.is_flip_x = False
118
self.is_flip_y = False
119
120
def __str__(self):
121
return f"""Frame Image data:
122
Image path: {repr(self.imgpath)}
123
From single png: {repr(self.from_single_png)}
124
Width: {repr(self.img_width)}
125
Height: {repr(self.img_height)}
126
Flip-X: {repr(self.is_flip_x)}
127
Flip-Y: {repr(self.is_flip_y)}
128
"""
129
130
def modify_image_to(self, im):
131
# modifies PIL image object itself (does not change imgpath though)
132
self.img = im
133
self.img_width = im.width
134
self.img_height = im.height
135
136
# not used as of now
137
# class FrameXMLData:
138
# def __init__(self, pose_name, x, y, w, h, framex, framey, framew, frameh, flipx=False, flipy=False):
139
# self.pose_name = pose_name
140
# self.x = x
141
# self.y = y
142
# self.w = w
143
# self.h = h
144
# self.framex = framex
145
# self.framey = framey
146
# self.framew = framew
147
# self.frameh = frameh
148
# self.is_flip_x = flipx
149
# self.is_flip_y = flipy
150
# self.xml_posename = None
151
# # not exactly relevant to the xml but still
152
# self.from_single_png = False
153
154
# def convert_to_dict(self):
155
# attribs = {
156
# "name": self.pose_name,
157
# "x": self.x,
158
# "y": self.y,
159
# "width": self.w,
160
# "height": self.h
161
# }
162
163
# if self.framex:
164
# attribs.update({
165
# "frameX": self.framex,
166
# "frameY": self.framey,
167
# "frameWidth": self.framew,
168
# "frameHeight": self.frameh,
169
# })
170
171
# return attribs
172
173
# def __str__(self):
174
# return f"""Frame XML data:
175
# FrameX: {repr(self.framex)}
176
# FrameY: {repr(self.framey)}
177
# FrameWidth: {repr(self.framew)}
178
# FrameHeight: {repr(self.frameh)}
179
# """
180