69 lines
2.6 KiB
Python
69 lines
2.6 KiB
Python
#!/usr/bin/env python3
|
|
""" Extract sprites from HGSS follower spritesheets. """
|
|
import os.path
|
|
from os.path import join as joinp
|
|
import subprocess
|
|
import sys
|
|
from glob import glob
|
|
|
|
import png
|
|
from tqdm import tqdm
|
|
|
|
|
|
def stack_sprite(name, path):
|
|
frames = [joinp(path, 'down', name), joinp(path, 'down', 'frame2', name),
|
|
joinp(path, 'up', name), joinp(path, 'up', 'frame2', name),
|
|
joinp(path, 'left', name), joinp(path, 'left', 'frame2', name)]
|
|
output = joinp(path, name)
|
|
subprocess.run(['convert'] + frames + ['+append', output], check=True)
|
|
print(f'Stacked {output}')
|
|
|
|
def closest_color(c, palette):
|
|
min_d = float('inf')
|
|
best = 0
|
|
r1, g1, b1 = c
|
|
for i, (r2, g2, b2) in enumerate(palette[1:], 1):
|
|
# Color diff from https://stackoverflow.com/questions/1847092/given-an-rgb-value-what-would-be-the-best-way-to-find-the-closest-match-in-the-d
|
|
d = ((r2-r1)*0.30)**2 + ((g2-g1)*0.59)**2 + ((b2-b1)*0.11)**2
|
|
if d < min_d:
|
|
min_d = d
|
|
best = i
|
|
return best
|
|
|
|
def apply_palette(palette_file, input_file, output_file): # Apply one file's palette to another
|
|
plt = png.Reader(palette_file)
|
|
plt.read()
|
|
target_palette = tuple(c[:3] for c in plt.palette())
|
|
inp = png.Reader(input_file)
|
|
w, h, rows, info = inp.read()
|
|
src_palette = tuple(c[:3] for c in inp.palette())
|
|
new_rows = [[closest_color(src_palette[c][:3], target_palette) if c else 0 for c in row] for row in rows]
|
|
with open(output_file, 'wb') as f:
|
|
w = png.Writer(width=w, height=h, bitdepth=4, palette=target_palette)
|
|
w.write(f, new_rows)
|
|
|
|
# Sprites from https://veekun.com/dex/downloads
|
|
|
|
def apply_front_palettes(ow_dir, project_root=''):
|
|
mon_graphics = joinp(project_root, 'graphics', 'pokemon')
|
|
t = tqdm(sorted(glob(joinp(ow_dir, '*.png'))))
|
|
spaces = 0
|
|
for path in t:
|
|
name, _ = os.path.splitext(os.path.basename(path))
|
|
spaces = min(max(len(name), spaces), 10)
|
|
t.set_description(name + ' '*(spaces-len(name)))
|
|
output_path = joinp(project_root, 'graphics', 'object_events', 'pics', 'pokemon', f'{name}.png')
|
|
if 'unown' in name:
|
|
palette_path = joinp(mon_graphics, 'unown', 'a', 'anim_front.png')
|
|
elif name == 'castform':
|
|
palette_path = joinp(mon_graphics, name, 'anim_front_normal_form.png')
|
|
else:
|
|
palette_path = joinp(mon_graphics, name, 'anim_front.png')
|
|
try:
|
|
apply_palette(palette_path, path, output_path)
|
|
except Exception as e:
|
|
t.write(f'{name}: {e.__class__.__name__}: {e}', file=sys.stderr)
|
|
|
|
|
|
if __name__ == '__main__':
|
|
apply_front_palettes('overworld')
|