Skip to content

Commit 991ed8a

Browse files
committed
Add sprite padding and clipping
1 parent de74909 commit 991ed8a

File tree

2 files changed

+65
-15
lines changed

2 files changed

+65
-15
lines changed

spritesheetExporter/spritesheet_exporter.py

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,11 @@ class SpritesheetExporter:
2727
start: int
2828
end: int
2929

30+
pad_left: int
31+
pad_top: int
32+
pad_right: int
33+
pad_bottom: int
34+
3035
export_frame_sequence: bool
3136
custom_frames_dir: Optional[Path]
3237
base_name: str
@@ -172,8 +177,11 @@ def _copy_frames(self, src: Document, dest: Document):
172177
"""
173178

174179
root = dest.rootNode()
175-
width = src.width()
176-
height = src.height()
180+
181+
x = -self.pad_left
182+
y = -self.pad_top
183+
w = src.width() - x + self.pad_right
184+
h = src.height() - y + self.pad_bottom
177185

178186
pixel_set: Optional[set[QByteArray]] = set() if self.unique_frames else None
179187

@@ -185,14 +193,16 @@ def _copy_frames(self, src: Document, dest: Document):
185193

186194
# Export each visible layer
187195
for i, layer in enumerate(visible_layers):
196+
pixel_data = layer.pixelData(x, y, w, h)
197+
188198
if pixel_set is not None:
189-
pixel_data = layer.pixelData(0, 0, width, height)
190199
if pixel_data in pixel_set:
191200
continue # Got a non-unique frame
192201
pixel_set.add(pixel_data)
193202

194-
clone_layer = dest.createCloneLayer(str(i), layer)
195-
root.addChildNode(clone_layer, None)
203+
new_layer = dest.createNode(str(i), "paintlayer")
204+
new_layer.setPixelData(0, 0, w, h, pixel_data)
205+
root.addChildNode(new_layer, None)
196206
else:
197207
if self.end == DEFAULT_TIME or self.start == DEFAULT_TIME:
198208
self._set_frame_times(src)
@@ -206,15 +216,15 @@ def _copy_frames(self, src: Document, dest: Document):
206216

207217
# Ensure the time has been set before copying the pixel data
208218
src.waitForDone()
209-
pixel_data = src.pixelData(0, 0, width, height)
219+
pixel_data = src.pixelData(x, y, w, h)
210220

211221
if pixel_set is not None:
212222
if pixel_data in pixel_set:
213223
continue # Got a non-unique frame
214224
pixel_set.add(pixel_data)
215225

216226
layer = dest.createNode(str(i), "paintlayer")
217-
layer.setPixelData(pixel_data, 0, 0, width, height)
227+
layer.setPixelData(pixel_data, 0, 0, w, h)
218228
root.addChildNode(layer, None)
219229

220230
src.setCurrentTime(initial_time) # reset time
@@ -228,8 +238,8 @@ def _process_frames(self, src: Document, dest: Document):
228238
@param dest The document to contain the exported spritesheet
229239
"""
230240

231-
width = src.width()
232-
height = src.height()
241+
width = src.width() + self.pad_left + self.pad_right
242+
height = src.height() + self.pad_top + self.pad_bottom
233243

234244
frames_dir = self._make_frames_dir() if self.export_frame_sequence else None
235245
texture_atlas = {"frames": []} if self.write_texture_atlas else None
@@ -287,8 +297,8 @@ def export(self, debug=False):
287297
print("spritesheetExporter: Export spritesheet start.")
288298

289299
# Current document info to use for the new document
290-
width = doc.width()
291-
height = doc.height()
300+
width = doc.width() + self.pad_left + self.pad_right
301+
height = doc.height() + self.pad_top + self.pad_bottom
292302

293303
if debug:
294304
print(

spritesheetExporter/ui.py

Lines changed: 44 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -230,24 +230,59 @@ def apply_settings(self, exporter: SpritesheetExporter):
230230
exporter.step = self.step.value()
231231

232232

233+
class EdgePadding(QFormLayout):
234+
"""
235+
Sets the padding (or clipping) of sprites.
236+
"""
237+
238+
def __init__(self):
239+
super().__init__()
240+
241+
self.left = self._make_spin_box("left")
242+
self.top = self._make_spin_box("top")
243+
self.right = self._make_spin_box("right")
244+
self.bottom = self._make_spin_box("bottom")
245+
246+
self.addRow("Padding left:", self.left)
247+
self.addRow("Padding top:", self.top)
248+
self.addRow("Padding right:", self.right)
249+
self.addRow("Padding bottom:", self.bottom)
250+
251+
def apply_settings(self, exp: SpritesheetExporter) -> None:
252+
exp.pad_left = self.left.value()
253+
exp.pad_top = self.top.value()
254+
exp.pad_right = self.right.value()
255+
exp.pad_bottom = self.bottom.value()
256+
257+
@staticmethod
258+
def _make_spin_box(edge: str) -> QSpinBox:
259+
spin_box = QSpinBox(value=0, minimum=-99, maximum=99)
260+
spin_box.setSuffix("px")
261+
spin_box.setToolTip(
262+
f"Pads the {edge} edge of each sprite, or clips it if negative"
263+
)
264+
return spin_box
265+
266+
233267
class UISpritesheetExporter:
234268
exporter = SpritesheetExporter()
235269
dialog = QDialog() # the main window
236270

237271
common_settings = CommonSettings()
238272
frames = FramesExport()
273+
edges = EdgePadding()
239274

240275
# Extra settings group
241276
layers_as_animation = QCheckBox("Use layers as animation frames")
242277
placement = SpritePlacement()
243-
spin_boxes = SpinBoxes()
278+
frame_times = SpinBoxes()
244279

245280
dialog_buttons = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
246281

247282
def __init__(self):
248283
self.dialog.setWindowTitle(i18n("SpritesheetExporter"))
249284
self.dialog.setWindowModality(Qt.NonModal) # Don't block input to other windows
250-
self.dialog.setMinimumSize(425, 450)
285+
self.dialog.setMinimumSize(425, 480)
251286
self.dialog.setSizeGripEnabled(True)
252287

253288
self.common_settings.change_dir.clicked.connect(self.change_export_dir)
@@ -264,6 +299,10 @@ def __init__(self):
264299
self.dialog_buttons.rejected.connect(self.dialog.close)
265300

266301
# Setup layouts
302+
spin_boxes = QHBoxLayout()
303+
spin_boxes.addLayout(self.frame_times)
304+
spin_boxes.addLayout(self.edges)
305+
267306
extra_settings = QGroupBox("Extra Settings")
268307
extra_settings.setCheckable(True)
269308
extra_settings.setChecked(False)
@@ -273,7 +312,7 @@ def __init__(self):
273312
extras.addSpacing(10)
274313
extras.addLayout(self.placement)
275314
extras.addSpacing(10)
276-
extras.addLayout(self.spin_boxes)
315+
extras.addLayout(spin_boxes)
277316

278317
root_layout = QVBoxLayout(self.dialog) # the box holding everything
279318
root_layout.addLayout(self.common_settings)
@@ -342,7 +381,8 @@ def confirm_button(self):
342381
self.common_settings.apply_settings(self.exporter)
343382
self.frames.apply_settings(self.exporter)
344383
self.placement.apply_settings(self.exporter)
345-
self.spin_boxes.apply_settings(self.exporter)
384+
self.frame_times.apply_settings(self.exporter)
385+
self.edges.apply_settings(self.exporter)
346386
self.exporter.layers_as_animation = self.layers_as_animation.isChecked()
347387

348388
self.exporter.export()

0 commit comments

Comments
 (0)