import json from PIL import Image from pathlib import Path def extract_atlas(atlas_path: str, metadata_path: str, output_dir: str): atlas = Image.open(atlas_path) with open(metadata_path, 'r') as f: data = json.load(f)
"frames": "player_idle_01.png": "frame": "x": 2, "y": 10, "w": 64, "h": 64, "rotated": false, "trimmed": false, "spriteSourceSize": "x": 0, "y": 0, "w": 64, "h": 64, "sourceSize": "w": 64, "h": 64
output_path = Path(output_dir) output_path.mkdir(exist_ok=True) texture atlas extractor
For most practical needs, using an existing tool with metadata support is recommended. When metadata is absent, a connected‑component based blind extractor provides a good starting point.
for name, info in frames.items(): frame = info['frame'] x, y, w, h = frame['x'], frame['y'], frame['w'], frame['h'] # Extract sub-image sprite = atlas.crop((x, y, x+w, y+h)) # Handle rotation (example for 90° clockwise) if info.get('rotated', False): sprite = sprite.rotate(-90, expand=True) # Handle trimming: embed into sourceSize canvas if info.get('trimmed', False): src_w = info['sourceSize']['w'] src_h = info['sourceSize']['h'] offset_x = info['spriteSourceSize']['x'] offset_y = info['spriteSourceSize']['y'] new_img = Image.new('RGBA', (src_w, src_h), (0,0,0,0)) new_img.paste(sprite, (offset_x, offset_y)) sprite = new_img # Save safe_name = Path(name).stem sprite.save(output_path / f"safe_name.png") import json from PIL import Image from pathlib
This naive method works for atlases with transparent gaps between sprites.
from PIL import Image import numpy as np from scipy import ndimage def blind_extract(atlas_path, min_size=8): img = Image.open(atlas_path).convert('RGBA') alpha = np.array(img.getchannel('A')) labels, num = ndimage.label(alpha > 0) for i in range(1, num+1): ys, xs = np.where(labels == i) if len(ys) < min_size: continue x1, x2 = xs.min(), xs.max() y1, y2 = ys.min(), ys.max() sprite = img.crop((x1, y1, x2+1, y2+1)) sprite.save(f"sprite_i.png") from PIL import Image import numpy as np
frames = data.get('frames', data) # handle different JSON structures