Automate Sprite Slicing and Packing in GIMP Python
This article demonstrates how to automate the slicing and packing of 2D character animation frames using GIMP's built-in Python-Fu environment. By scripting this workflow, you can programmatically divide animation sheets into uniform cells, trim excess transparent pixels, and repack the frames into optimized texture layouts. This pipeline eliminates tedious manual alignment and ensures consistent frame dimensions for game development.
Understanding GIMP Python-Fu
GIMP provides a built-in Python 2.7 scripting interface known as Python-Fu, which interacts directly with the Procedural Database (PDB). This allows scripts to execute almost any native action available in the UI, such as selecting regions, cropping, copying layers, and transforming canvases.
Scripts must be placed inside your local GIMP plug-ins directory:
- Windows:
C:\Users\<Username>\AppData\Roaming\GIMP\2.10\plug-ins - Linux:
~/.config/GIMP/2.10/plug-ins - macOS:
~/Library/Application Support/GIMP/2.10/plug-ins
Ensure script files have executable permissions
(chmod +x script_name.py on Linux and macOS).
The Slicing and Packing Logic
Automating the process requires three steps:
- Slicing: Iterating through a grid-based source image using known frame widths and heights, then extracting each cell into its own layer.
- Trimming (Optional): Removing transparent margins around the character while storing offsets to keep registration intact.
- Packing: Calculating the dimensions required for a new destination canvas (such as a horizontal strip or a square power-of-two texture) and rendering each frame onto it sequentially.
The Automation Script
The following script defines a Python plugin that slices a character sheet based on specified rows and columns, then repacks all extracted frames horizontally into a new sprite sheet.
#!/usr/bin/env python
from gimpfu import *
def slice_and_pack_frames(image, drawable, frame_width, frame_height, cols, rows):
gimp.context_push()
image.undo_group_start()
total_frames = cols * rows
frames = []
# 1. Slice frames from the source image
for r in range(rows):
for c in range(cols):
x = c * frame_width
y = r * frame_height
# Select frame region
pdb.gimp_image_select_rectangle(image, CHANNEL_OP_REPLACE, x, y, frame_width, frame_height)
# Copy the selection
if pdb.gimp_edit_copy(drawable):
# Paste into a temporary floating layer
floating_sel = pdb.gimp_edit_paste(drawable, True)
# Create a new layer from selection
new_layer = pdb.gimp_layer_new_from_visible(image, image, "Frame_{}_{}".format(r, c))
image.add_layer(new_layer, 0)
pdb.gimp_floating_sel_remove(floating_sel)
frames.append(new_layer)
pdb.gimp_selection_none(image)
# 2. Create the target canvas for repacking (horizontal strip)
packed_width = frame_width * total_frames
packed_height = frame_height
packed_image = pdb.gimp_image_new(packed_width, packed_height, RGB)
# 3. Pack frames into the new image
for index, frame in enumerate(frames):
# Copy layer to packed image
packed_layer = pdb.gimp_layer_new(packed_image, frame_width, frame_height,
RGBA_IMAGE, "Frame_{}".format(index), 100, NORMAL_MODE)
pdb.gimp_image_insert_layer(packed_image, packed_layer, None, 0)
# Position layer
offset_x = index * frame_width
pdb.gimp_layer_set_offsets(packed_layer, offset_x, 0)
# Copy pixel data from original frame
pdb.gimp_edit_copy(frame)
floating = pdb.gimp_edit_paste(packed_layer, True)
pdb.gimp_floating_sel_anchor(floating)
# Remove temporary layer from original image
image.remove_layer(frame)
# Display the packed sprite sheet
pdb.gimp_display_new(packed_image)
image.undo_group_end()
gimp.context_pop()
register(
"python_fu_slice_and_pack",
"Slice and Pack Character Animation Frames",
"Splits a grid-based sheet into frames and repacks them into a horizontal atlas.",
"Author",
"Open Source",
"2024",
"<Image>/Filters/Animation/Slice and Pack...",
"RGB*, GRAY*",
[
(PF_INT, "frame_width", "Frame Width (px)", 64),
(PF_INT, "frame_height", "Frame Height (px)", 64),
(PF_INT, "cols", "Columns", 4),
(PF_INT, "rows", "Rows", 4),
],
[],
slice_and_pack_frames
)
main()Running the Script
- Save the code as
slice_and_pack.pyand place it in the GIMP plug-ins folder. - Restart GIMP so the new plugin is indexed.
- Open your character animation image.
- Navigate to Filters > Animation > Slice and Pack... from the top menu.
- Enter the target frame width, height, and grid dimensions, then click OK.
A new window will open containing the repacked animation sequence aligned as a continuous horizontal strip, ready to be exported to PNG or loaded directly into an animation engine.