#!/usr/bin/env python3 """ Resize all assets to EXACT multiples of 32px tile size Rename files to include dimensions: filename_WxH.png """ import os from pathlib import Path from PIL import Image import shutil # Exact tile-aligned sizes (multiples of 32) TILE_SIZE = 32 RESIZE_CONFIG = { 'terrain': 32, # 1×1 tile 'crops': 32, # 1×1 tile 'buildings': 32, # 1×1 tile (tent) 'items': 16, # 0.5×0.5 tile (inventory items) 'ui': None, # Keep original 'effects': 32, # 1×1 tile (changed from 24) 'environment': { 'campfire': 32, # 1×1 tile 'dead_tree': (32, 64), # 1×2 tiles (changed from 32×48) 'rock': 32 # 1×1 tile (changed from 24×16) }, 'characters': 32, # 1×1 tile 'enemies': 32 # 1×1 tile } def resize_and_rename(input_path: Path, output_dir: Path, size, backup=True): """Resize image and rename with dimensions""" try: img = Image.open(input_path) # Backup original if requested if backup and input_path.parent == output_dir: backup_path = input_path.parent / "originals" / input_path.name backup_path.parent.mkdir(exist_ok=True) if not backup_path.exists(): shutil.copy2(input_path, backup_path) # Keep original if size is None if size is None: return True # Resize if isinstance(size, tuple): resized = img.resize(size, Image.Resampling.LANCZOS) new_width, new_height = size else: resized = img.resize((size, size), Image.Resampling.LANCZOS) new_width, new_height = size, size # Generate new filename with dimensions stem = input_path.stem # Remove old dimensions if present if '_' in stem: parts = stem.rsplit('_', 1) if 'x' in parts[-1] or parts[-1].replace('x', '').replace('style', '').isdigit(): # Keep it as is for style suffixes base_name = stem else: base_name = stem else: base_name = stem # New filename: originalname_WxH.png new_filename = f"{base_name}_{new_width}x{new_height}.png" output_path = output_dir / new_filename # Save resized.save(output_path, 'PNG', optimize=True) # Delete old file if different name if output_path != input_path and input_path.exists(): input_path.unlink() print(f" ✅ {input_path.name} → {new_filename} ({img.size} → {resized.size})") return True except Exception as e: print(f" ❌ {input_path.name}: {e}") return False def get_target_size(category: str, filename: str): """Get target size for category""" config = RESIZE_CONFIG.get(category) if config is None: return None if isinstance(config, dict): for key, size in config.items(): if key in filename: return size return 32 # Default return config def process_category(base_dir: Path, category: str): """Process all images in category""" category_path = base_dir / category if not category_path.exists(): return 0 print(f"\n📁 {category}/") png_files = list(category_path.glob('*.png')) if not png_files: return 0 count = 0 for png_file in png_files: # Skip already processed files with dimensions if any(x in png_file.stem for x in ['_32x32', '_16x16', '_32x64', '_24x24']): continue size = get_target_size(category, png_file.stem) if resize_and_rename(png_file, category_path, size): count += 1 return count def main(): print("=" * 70) print("📏 TILE-ALIGNED RESIZE & RENAME (Multiples of 32px)") print("=" * 70) demo_dir = Path('assets/slike') print(f"\n📦 Processing: {demo_dir}") total = 0 for category in RESIZE_CONFIG.keys(): if category != 'environment': total += process_category(demo_dir, category) total += process_category(demo_dir, 'environment') # White BG originals orig_dir = Path('assets/slike_originals_with_white_bg') if orig_dir.exists(): print(f"\n📦 Processing: {orig_dir}") for category in RESIZE_CONFIG.keys(): if category != 'environment': total += process_category(orig_dir, category) total += process_category(orig_dir, 'environment') print("\n" + "=" * 70) print(f"✅ COMPLETE! Processed {total} images") print("=" * 70) print("\n📐 All sizes now multiples of 32px!") print("📝 All files renamed with dimensions!") print("\n🎮 Perfect for Tiled!") if __name__ == "__main__": main()