Menu
VWArtclub
Search
VWArtclub
VWArtclub is a community of thought, a shared 3d art gallery, a thirst to know how 3d design will evolve worldwide, a respect for this way of art and a decision to record this fact visually.
Projects. Club. Studios. Learning. News. Inspiration. Xfree3D. Contests. Forum. Profile & Contact. Shop. Login.
xfree3d
Bundle
Daylight
Dusk
Exterior
Interior

Atlas Extractor: Texture

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

Be A *Member.
Be A *Supporter.
Be A *Wanderer.
Be A *Studio.