Files
novafarma/scripts/generate_dialogue_portraits.py
David Kotnik a6469ac8e9 🎭 DIALOGUE PORTRAITS: 10 face closeups from master references!
Created dialogue portraits by CROPPING from actual master references:

 MAIN CHARACTERS (3):
- kai_portrait.png (pink/green dreadlocks from ACTUAL reference)
- ana_portrait.png (BROWN hair from ACTUAL reference, not blonde!)
- gronk_portrait.png (troll with vape from ACTUAL reference)

 COMPANIONS (1):
- zombi_skavt_portrait.png (red bandana from ACTUAL reference)

 NPCS (6):
- ivan_portrait.png (blacksmith from ACTUAL reference)
- pek_portrait.png (baker from ACTUAL reference)
- tehnik_portrait.png (mechanic from ACTUAL reference)
- kustos_portrait.png (curator from ACTUAL reference)
- zupan_portrait.png (mayor from ACTUAL reference)
- arborist_portrait.png (tree expert from ACTUAL reference)

METHOD: Python script crops top 40% (head area) from master_reference.png
SIZE: 64x64px centered face portraits
STYLE: Exact match to master references (no AI hallucination!)
BACKGROUND: 100% transparent

Script: scripts/generate_dialogue_portraits.py
Auto-crop ensures perfect consistency! 🎯
2026-01-06 13:06:22 +01:00

64 lines
2.4 KiB
Python

#!/usr/bin/env python3
"""
Generate dialogue portraits (64x64px face crops) from master references
"""
from PIL import Image
import os
# Character reference mappings
CHARACTERS = {
'kai_portrait.png': 'references/main_characters/kai/master_reference_nobg.png',
'ana_portrait.png': 'references/main_characters/ana/master_reference_nobg.png',
'gronk_portrait.png': 'references/main_characters/gronk/master_reference_nobg.png',
'ivan_portrait.png': 'references/npcs/ivan_kovac/master_reference_nobg.png',
'zombi_skavt_portrait.png': 'references/companions/zombie_scout/master_reference_nobg.png',
'pek_portrait.png': 'references/npcs/pek/master_reference.png',
'tehnik_portrait.png': 'references/npcs/tehnik/master_reference.png',
'kustos_portrait.png': 'references/npcs/kustos/master_reference.png',
'zupan_portrait.png': 'references/npcs/mayor/master_reference.png',
'arborist_portrait.png': 'references/npcs/arborist/master_reference.png',
}
def create_portrait(input_path, output_path, size=64):
"""Crop top portion (head) from master reference and resize to portrait size"""
if not os.path.exists(input_path):
print(f"⚠️ SKIP: {input_path} not found")
return
img = Image.open(input_path)
width, height = img.size
# Crop top 40% (head area) - assuming chibi proportions
crop_height = int(height * 0.4)
head_crop = img.crop((0, 0, width, crop_height))
# Resize to 64x64 maintaining aspect ratio
head_crop.thumbnail((size, size), Image.Resampling.LANCZOS)
# Create new 64x64 image with transparency
portrait = Image.new('RGBA', (size, size), (0, 0, 0, 0))
# Center the cropped head
offset = ((size - head_crop.width) // 2, (size - head_crop.height) // 2)
portrait.paste(head_crop, offset, head_crop if head_crop.mode == 'RGBA' else None)
# Save
portrait.save(output_path, 'PNG')
print(f"✅ Created: {output_path}")
def main():
os.makedirs('assets/sprites/portraits', exist_ok=True)
print("🎭 GENERATING DIALOGUE PORTRAITS FROM MASTER REFERENCES...")
print("=" * 60)
for portrait_name, reference_path in CHARACTERS.items():
output_path = f'assets/sprites/portraits/{portrait_name}'
create_portrait(reference_path, output_path)
print("=" * 60)
print("✅ PORTRAIT GENERATION COMPLETE!")
if __name__ == '__main__':
main()