164 lines
5.0 KiB
Python
164 lines
5.0 KiB
Python
#!/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/images/demo')
|
||
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/images/demo_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()
|