Last active
April 11, 2024 04:53
-
-
Save kennedy0/29eac8cd827edc9c1d0f056316f43e9c to your computer and use it in GitHub Desktop.
sprite_packer
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import json | |
from pathlib import Path | |
from PIL import Image | |
# Build sprite list | |
sprites_folder = Path("./sprites") | |
sprites = [] | |
for file in sprites_folder.iterdir(): | |
if file.suffix == ".png": | |
sprite = Image.open(file) | |
sprites.append(sprite) | |
# Sort sprites from largest to smallest area | |
sprites.sort(key=lambda s: s.height * s.width, reverse=True) | |
# Create atlas | |
atlas_size = (512, 512) | |
while True: | |
atlas = Image.new(mode="RGBA", size=atlas_size) | |
sprite_data = {} | |
packing_failed = False | |
# Empty areas in the atlas | |
area = (0, 0, atlas_size[0], atlas_size[1]) # (x, y, w, h) | |
areas = [area] | |
# Pack sprites using the Guillotine algorithm | |
for sprite in sprites: | |
# Find an empty area | |
area = None | |
for a in areas: | |
x, y, w, h = a | |
if sprite.width <= w and sprite.height <= h: | |
# Add the sprite to the atlas | |
atlas.paste(sprite, box=(x, y)) | |
sprite_name = Path(sprite.filename).name | |
sprite_data[sprite_name] = {'x': x, 'y': y, 'w': sprite.width, 'h': sprite.height} | |
area = a | |
break | |
# Area not found | |
if area is None: | |
packing_failed = True | |
atlas_size = (atlas_size[0] + 64, atlas_size[1] + 64) | |
print(f"Resizing atlas size to {atlas_size}") | |
break | |
# Split the area into new top and bottom areas | |
x, y, w, h = area | |
top = (x + sprite.width, y, w - sprite.width, sprite.height) | |
bottom = (x, y + sprite.height, w, h - sprite.height) | |
# Update the area list with the two new areas | |
areas.remove(area) | |
areas.append(top) | |
areas.append(bottom) | |
# Break the loop if we placed all the sprites | |
if not packing_failed: | |
print(f"Finished packing {len(sprites)} sprites") | |
break | |
# Save the atlas file | |
atlas_file = Path("./atlas.png") | |
atlas.save(atlas_file) | |
# Save the sprite data file | |
sprite_data_file = Path("./data.json") | |
with open(sprite_data_file, 'w') as fp: | |
json.dump(sprite_data, fp, indent=True) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment