Skip to content

Commit

Permalink
Added option to not merge identical frames + some bufixes
Browse files Browse the repository at this point in the history
  • Loading branch information
UncertainProd committed Jul 15, 2022
1 parent a70e938 commit da51146
Show file tree
Hide file tree
Showing 6 changed files with 124 additions and 72 deletions.
16 changes: 13 additions & 3 deletions src/SpritesheetGenSettings.ui
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,14 @@
<rect>
<x>0</x>
<y>0</y>
<width>611</width>
<height>520</height>
<width>603</width>
<height>552</height>
</rect>
</property>
<property name="windowTitle">
<string>Spritesheet Generation Settings</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_3" stretch="0,0,0,0,0,0,0">
<layout class="QVBoxLayout" name="verticalLayout_3" stretch="0,0,0,0,0,0,0,0">
<item>
<widget class="QCheckBox" name="clip_checkbox">
<property name="font">
Expand Down Expand Up @@ -137,6 +137,16 @@ Before Animation Prefix</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="no_merge_checkbox">
<property name="text">
<string>Do not merge look-alike frames
(WARNING: Can cause extremely large spritesheets which may cause windows to
refuse to open them.
May also cause crashes!)</string>
</property>
</widget>
</item>
<item>
<widget class="QFrame" name="frame_4">
<property name="frameShape">
Expand Down
7 changes: 4 additions & 3 deletions src/engine/icongridutils.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,10 +68,11 @@ def appendIconToGrid(icongrid_path, iconpaths, iconsize=150):

try:
# icongrid = Image.open(icongrid_path)
with Image.open(icongrid_path) as icongrid:
with Image.open(icongrid_path).convert('RGBA') as icongrid:
# icongrid = icongrid.convert('RGBA')
for iconpath in iconpaths:
# icon_img = Image.open(iconpath)
with Image.open(iconpath) as icon_img:
with Image.open(iconpath).convert('RGBA') as icon_img:
# check if icon_img is 150x150
can_fit = _check_icon_size(icon_img)
if can_fit == ICON_BIGGER_THAN_AREA:
Expand Down Expand Up @@ -113,7 +114,7 @@ def makePsychEngineIconGrid(iconpaths, savepath, img_size=150):
good_icons = []
for iconpath in iconpaths:
try:
icon = Image.open(iconpath)
icon = Image.open(iconpath).convert('RGBA')
except Exception as e:
exception_msg = f"{e.__class__.__name__} : {str(e)}"
continue
Expand Down
81 changes: 56 additions & 25 deletions src/engine/xmlpngengine.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ def make_png_xml(frames, save_dir, character_name="Result", progressupdatefn=Non
must_use_prefix = settings.get('must_use_prefix', 0) != 0 # use the custom prefix even if frame is from existing spritesheet
padding_pixels = settings.get('frame_padding', 0)
packing_algorithm = settings.get('packing_algo', 0) # 0 = Growing Packer, 1 = Ordered Packer
no_merge = settings.get('no_merge', 0) != 0 # no merging lookalike frames

# print(len(imghashes))
# print(len(frames))
Expand Down Expand Up @@ -53,14 +54,23 @@ def make_png_xml(frames, save_dir, character_name="Result", progressupdatefn=Non
frame_dict_arr = []
current_img_hashes = set([x.data.img_hash for x in frames])

# add the padding to width and height, then actually padding the images (kind of a hack but it works TODO: work out a better way to do this)
for imhash, img in imghashes.items():
if imhash in current_img_hashes:
if no_merge:
for f in frames:
frame_dict_arr.append({
"id": imhash,
"w": img.width + 2*padding_pixels,
"h": img.height + 2*padding_pixels
"id": f.data.img_hash,
"w": imghashes.get(f.data.img_hash).width + 2*padding_pixels,
"h": imghashes.get(f.data.img_hash).height + 2*padding_pixels,
"frame": f # this comes in handy later on
})
else:
# add the padding to width and height, then actually padding the images (kind of a hack but it works TODO: work out a better way to do this)
for imhash, img in imghashes.items():
if imhash in current_img_hashes:
frame_dict_arr.append({
"id": imhash,
"w": img.width + 2*padding_pixels,
"h": img.height + 2*padding_pixels
})

if packing_algorithm == 1:
packer = OrderedPacker()
Expand All @@ -84,26 +94,47 @@ def make_png_xml(frames, save_dir, character_name="Result", progressupdatefn=Non
prgs += 1
progressupdatefn(prgs, "Adding images to spritesheet...")

if no_merge:
for framedict in frame_dict_arr:
frame = framedict['frame']
subtexture_element = ET.Element("SubTexture")
subtexture_element.tail = linesep
w, h = imghashes.get(frame.data.img_hash).size
subtexture_element.attrib = {
"name" : frame.data.xml_pose_name,
"x": str(framedict['fit']['x']),
"y": str(framedict['fit']['y']),
"width": str(w + 2*padding_pixels),
"height": str(h + 2*padding_pixels),
"frameX": str(frame.data.framex),
"frameY": str(frame.data.framey),
"frameWidth": str(frame.data.framew),
"frameHeight": str(frame.data.frameh),
}
root.append(subtexture_element)
prgs += 1
progressupdatefn(prgs, f"Saving {frame.data.xml_pose_name} to XML...")
else:
# convert frame_dict_arr into a dict[image_hash -> position in spritesheet]:
imghash_dict = { rect['id']: (rect['fit']['x'], rect['fit']['y']) for rect in frame_dict_arr }
for frame in frames:
subtexture_element = ET.Element("SubTexture")
subtexture_element.tail = linesep
w, h = imghashes.get(frame.data.img_hash).size
subtexture_element.attrib = {
"name" : frame.data.xml_pose_name,
"x": str(imghash_dict[frame.data.img_hash][0]),
"y": str(imghash_dict[frame.data.img_hash][1]),
"width": str(w + 2*padding_pixels),
"height": str(h + 2*padding_pixels),
"frameX": str(frame.data.framex),
"frameY": str(frame.data.framey),
"frameWidth": str(frame.data.framew),
"frameHeight": str(frame.data.frameh),
}
root.append(subtexture_element)
prgs += 1
progressupdatefn(prgs, f"Saving {frame.data.xml_pose_name} to XML...")
imghash_dict = { rect['id']: (rect['fit']['x'], rect['fit']['y']) for rect in frame_dict_arr }
for frame in frames:
subtexture_element = ET.Element("SubTexture")
subtexture_element.tail = linesep
w, h = imghashes.get(frame.data.img_hash).size
subtexture_element.attrib = {
"name" : frame.data.xml_pose_name,
"x": str(imghash_dict[frame.data.img_hash][0]),
"y": str(imghash_dict[frame.data.img_hash][1]),
"width": str(w + 2*padding_pixels),
"height": str(h + 2*padding_pixels),
"frameX": str(frame.data.framex),
"frameY": str(frame.data.framey),
"frameWidth": str(frame.data.framew),
"frameHeight": str(frame.data.frameh),
}
root.append(subtexture_element)
prgs += 1
progressupdatefn(prgs, f"Saving {frame.data.xml_pose_name} to XML...")
# im.close()
print("Saving XML...")
xmltree = ET.ElementTree(root)
Expand Down
80 changes: 40 additions & 40 deletions src/framedata.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ def __init__(self, impath, from_single_png, pose_name, **xmlinfo):
self.th = None
self.from_single_png = from_single_png

img = Image.open(impath)
img = Image.open(impath).convert('RGBA')
self.framex = 0
self.framey = 0
self.framew = img.width
Expand Down Expand Up @@ -134,46 +134,46 @@ def modify_image_to(self, im):
self.img_height = im.height

# not used as of now
class FrameXMLData:
def __init__(self, pose_name, x, y, w, h, framex, framey, framew, frameh, flipx=False, flipy=False):
self.pose_name = pose_name
self.x = x
self.y = y
self.w = w
self.h = h
self.framex = framex
self.framey = framey
self.framew = framew
self.frameh = frameh
self.is_flip_x = flipx
self.is_flip_y = flipy
self.xml_posename = None
# not exactly relevant to the xml but still
self.from_single_png = False
# class FrameXMLData:
# def __init__(self, pose_name, x, y, w, h, framex, framey, framew, frameh, flipx=False, flipy=False):
# self.pose_name = pose_name
# self.x = x
# self.y = y
# self.w = w
# self.h = h
# self.framex = framex
# self.framey = framey
# self.framew = framew
# self.frameh = frameh
# self.is_flip_x = flipx
# self.is_flip_y = flipy
# self.xml_posename = None
# # not exactly relevant to the xml but still
# self.from_single_png = False

def convert_to_dict(self):
attribs = {
"name": self.pose_name,
"x": self.x,
"y": self.y,
"width": self.w,
"height": self.h
}
# def convert_to_dict(self):
# attribs = {
# "name": self.pose_name,
# "x": self.x,
# "y": self.y,
# "width": self.w,
# "height": self.h
# }

if self.framex:
attribs.update({
"frameX": self.framex,
"frameY": self.framey,
"frameWidth": self.framew,
"frameHeight": self.frameh,
})
# if self.framex:
# attribs.update({
# "frameX": self.framex,
# "frameY": self.framey,
# "frameWidth": self.framew,
# "frameHeight": self.frameh,
# })

return attribs
# return attribs

def __str__(self):
return f"""Frame XML data:
FrameX: {repr(self.framex)}
FrameY: {repr(self.framey)}
FrameWidth: {repr(self.framew)}
FrameHeight: {repr(self.frameh)}
"""
# def __str__(self):
# return f"""Frame XML data:
# FrameX: {repr(self.framex)}
# FrameY: {repr(self.framey)}
# FrameWidth: {repr(self.framew)}
# FrameHeight: {repr(self.frameh)}
# """
3 changes: 3 additions & 0 deletions src/settingswindow.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ def restoreToNormal(self):
self.ui.insist_prefix_checkbox.setCheckState(self.must_use_prefix)
self.ui.frame_padding_spinbox.setValue(self.frame_padding)
self.ui.packingalgo_combobox.setCurrentIndex(self.packing_algo)
self.ui.no_merge_checkbox.setCheckState(self.no_merge)
self.close()

def saveSettings(self, shouldclose=True):
Expand All @@ -55,13 +56,15 @@ def saveSettings(self, shouldclose=True):
self.must_use_prefix = self.ui.insist_prefix_checkbox.checkState()
self.frame_padding = self.ui.frame_padding_spinbox.value()
self.packing_algo = self.ui.packingalgo_combobox.currentIndex()
self.no_merge = self.ui.no_merge_checkbox.checkState()
# saving to global settings obj
g_settings['isclip'] = self.isclip
g_settings['prefix_type'] = self.prefix_type
g_settings['custom_prefix'] = self.custom_prefix
g_settings['must_use_prefix'] = self.must_use_prefix
g_settings['frame_padding'] = self.frame_padding
g_settings['packing_algo'] = self.packing_algo
g_settings['no_merge'] = self.no_merge
if shouldclose:
self.close()

Expand Down
9 changes: 8 additions & 1 deletion src/spritesheetgensettings.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ class Ui_Form(object):
def setupUi(self, Form):
Form.setObjectName("Form")
Form.setWindowModality(QtCore.Qt.ApplicationModal)
Form.resize(611, 520)
Form.resize(603, 552)
self.verticalLayout_3 = QtWidgets.QVBoxLayout(Form)
self.verticalLayout_3.setObjectName("verticalLayout_3")
self.clip_checkbox = QtWidgets.QCheckBox(Form)
Expand Down Expand Up @@ -78,6 +78,9 @@ def setupUi(self, Form):
self.insist_prefix_checkbox.setFont(font)
self.insist_prefix_checkbox.setObjectName("insist_prefix_checkbox")
self.verticalLayout_3.addWidget(self.insist_prefix_checkbox)
self.no_merge_checkbox = QtWidgets.QCheckBox(Form)
self.no_merge_checkbox.setObjectName("no_merge_checkbox")
self.verticalLayout_3.addWidget(self.no_merge_checkbox)
self.frame_4 = QtWidgets.QFrame(Form)
self.frame_4.setFrameShape(QtWidgets.QFrame.StyledPanel)
self.frame_4.setFrameShadow(QtWidgets.QFrame.Raised)
Expand Down Expand Up @@ -146,6 +149,10 @@ def retranslateUi(self, Form):
self.label_2.setText(_translate("Form", "Custom Prefix:"))
self.no_prefix_radiobtn.setText(_translate("Form", "Don\'t use any prefix (what you type in the prefix box is exactly what will show up in the XML)"))
self.insist_prefix_checkbox.setText(_translate("Form", "Use Prefix even if frame is imported from existing XML"))
self.no_merge_checkbox.setText(_translate("Form", "Do not merge look-alike frames\n"
"(WARNING: Can cause extremely large spritesheets which may cause windows to\n"
"refuse to open them.\n"
"May also cause crashes!)"))
self.frame_padding_spinbox.setSuffix(_translate("Form", "px"))
self.frame_padding_label.setText(_translate("Form", "Frame Padding (use this to add empty pixels to the edge of each frame, helps prevent \n"
" sprites clipping into each other)"))
Expand Down

0 comments on commit da51146

Please sign in to comment.