264 lines
8.4 KiB
Python
264 lines
8.4 KiB
Python
#!/usr/bin/env python2.7
|
|
|
|
"""
|
|
This script updates only market/item icons.
|
|
"""
|
|
|
|
|
|
import argparse
|
|
import json
|
|
import os
|
|
import sqlite3
|
|
from shutil import copyfile
|
|
|
|
from PIL import Image
|
|
|
|
|
|
def get_full_alias(short_alias):
|
|
full_aliases = {
|
|
'tq': 'tranquility',
|
|
'sisi': 'singularity'}
|
|
return full_aliases.get(short_alias, short_alias)
|
|
|
|
|
|
parser = argparse.ArgumentParser(description='This script updates module icons for pyfa')
|
|
parser.add_argument('-e', '--eve', required=True, type=str, help='path to eve\'s shared cache folder')
|
|
parser.add_argument('-s', '--server', required=False, default='tq', type=str, help='which server to use (defaults to tq)')
|
|
parser.add_argument('-i', '--icons', required=True, type=str, help='Path to iconids.json extracted by phobos')
|
|
args = parser.parse_args()
|
|
|
|
|
|
script_dir = os.path.dirname(os.path.abspath(__file__))
|
|
db_path = os.path.abspath(os.path.join(script_dir, '..', 'eve.db'))
|
|
icons_dir = os.path.abspath(os.path.join(script_dir, '..', 'imgs', 'icons'))
|
|
render_dir = os.path.abspath(os.path.join(script_dir, '..', 'imgs', 'renders'))
|
|
|
|
db = sqlite3.connect(db_path)
|
|
cursor = db.cursor()
|
|
|
|
ICON_SIZE = (16, 16)
|
|
RENDER_SIZE = (32, 32)
|
|
|
|
with open(args.icons, 'r') as f:
|
|
icon_json = json.load(f)
|
|
|
|
eve_path = os.path.join(args.eve, 'index_{}.txt'.format(get_full_alias(args.server)))
|
|
with open(eve_path, 'r') as f:
|
|
lines = f.readlines()
|
|
file_index = {x.split(',')[0]: x.split(',') for x in lines}
|
|
|
|
resfileindex = file_index['app:/resfileindex.txt']
|
|
|
|
res_cache = os.path.join(args.eve, 'ResFiles')
|
|
|
|
with open(os.path.join(res_cache, resfileindex[1]), 'r') as f:
|
|
lines = f.readlines()
|
|
res_index = {x.split(',')[0].lower(): x.split(',') for x in lines}
|
|
|
|
# Need to copy the file to our cuirrent directory
|
|
graphics_loader_file = os.path.join(res_cache, file_index['app:/bin64/graphicIDsLoader.pyd'][1])
|
|
to_path = os.path.dirname(os.path.abspath(__file__))
|
|
copyfile(graphics_loader_file, os.path.join(os.path.dirname(os.path.abspath(__file__)), 'graphicIDsLoader.pyd'))
|
|
|
|
# The loader expect it to be the correct filename, so copy trhe file as well
|
|
graphics_file = os.path.join(res_cache, res_index['res:/staticdata/graphicIDs.fsdbinary'.lower()][1])
|
|
to_path = os.path.dirname(os.path.abspath(__file__))
|
|
copyfile(graphics_file, os.path.join(os.path.dirname(os.path.abspath(__file__)), 'graphicIDs.fsdbinary'))
|
|
|
|
import graphicIDsLoader
|
|
|
|
graphics = graphicIDsLoader.load(os.path.join(to_path, 'graphicIDs.fsdbinary'))
|
|
|
|
graphics_py_ob = {}
|
|
for x, v in graphics.items():
|
|
if hasattr(v, 'iconInfo') and hasattr(v.iconInfo, 'folder'):
|
|
graphics_py_ob[x] = v.iconInfo.folder
|
|
|
|
# Add children to market group list
|
|
# {parent: {children}}
|
|
mkt_tree = {}
|
|
for row in cursor.execute('select marketGroupID, parentGroupID from invmarketgroups'):
|
|
parent = row[1]
|
|
# We have all the root groups in the set we need anyway
|
|
if not parent:
|
|
continue
|
|
child = row[0]
|
|
children = mkt_tree.setdefault(parent, set())
|
|
children.add(child)
|
|
|
|
# Traverse the tree we just composed to add all children for all needed roots
|
|
def get_children(parent):
|
|
children = set()
|
|
for child in mkt_tree.get(parent, ()):
|
|
children.add(child)
|
|
children.update(get_children(child))
|
|
return children
|
|
|
|
|
|
query_items = 'select distinct it.iconID from invtypes as it inner join invgroups as ig on it.groupID = ig.groupID where ig.categoryID != 2118'
|
|
query_groups = 'select distinct iconID from invgroups'
|
|
query_cats = 'select distinct iconID from invcategories'
|
|
query_market = 'select distinct iconID from invmarketgroups'
|
|
query_attrib = 'select distinct iconID from dgmattribs'
|
|
query_ships = 'select it.graphicID from invtypes as it inner join invgroups as ig on it.groupID = ig.groupID where ig.categoryID in (6, 65)'
|
|
|
|
needed = set()
|
|
existing = set()
|
|
export = {}
|
|
|
|
|
|
# Get a list of needed icons based on the items / attributes / etc from the database
|
|
for query in (query_items, query_groups, query_cats, query_market, query_attrib):
|
|
for row in cursor.execute(query):
|
|
fname = row[0]
|
|
if fname is None:
|
|
continue
|
|
needed.add(fname)
|
|
|
|
# Get a list of all the icons we currently have
|
|
for fname in os.listdir(icons_dir):
|
|
if not os.path.isfile(os.path.join(icons_dir, fname)):
|
|
continue
|
|
fname = os.path.splitext(fname)[0]
|
|
# Get rid of "icon" prefix as well
|
|
#fname = re.sub('^icon', '', fname)
|
|
existing.add(fname)
|
|
|
|
def crop_image(img):
|
|
w, h = img.size
|
|
if h == w:
|
|
return img
|
|
normal = min(h, w)
|
|
diff_w = w - normal
|
|
diff_h = h - normal
|
|
crop_top = diff_h // 2
|
|
crop_bot = diff_h // 2 + diff_h % 2
|
|
crop_left = diff_w // 2
|
|
crop_right = diff_w // 2 + diff_w % 2
|
|
box = (crop_left, crop_top, w - crop_right, h - crop_bot)
|
|
return img.crop(box)
|
|
|
|
|
|
def get_icon_file(res_path, size):
|
|
"""
|
|
Get the iconFile field value and find proper
|
|
icon for it. Return as PIL image object down-
|
|
scaled for use in pyfa.
|
|
"""
|
|
res_path = res_path.lower()
|
|
res_path = res_path.replace('\\', '/')
|
|
res_path = res_path.replace('//', '/') #1703
|
|
if res_path not in res_index:
|
|
return None
|
|
res_icon = res_index[res_path]
|
|
icon_path = res_icon[1]
|
|
|
|
fullpath = os.path.join(res_cache, icon_path)
|
|
|
|
if not os.path.isfile(fullpath):
|
|
return None
|
|
img = Image.open(fullpath)
|
|
|
|
if size > img.size:
|
|
# if we are requesting a size that is bigger than the source, return None. See #1769
|
|
return None
|
|
|
|
img = crop_image(img)
|
|
img.thumbnail(size, Image.ANTIALIAS)
|
|
|
|
# Strip all additional image info (mostly for ICC color
|
|
# profiles, see issue #337)
|
|
img.info.clear()
|
|
return img
|
|
|
|
|
|
toremove = existing.difference(needed)
|
|
toupdate = existing.intersection(needed)
|
|
toadd = needed.difference(existing)
|
|
|
|
|
|
if toremove:
|
|
print('Some icons are not used and will be removed:')
|
|
for fname in sorted(toremove):
|
|
fullname = '{}.png'.format(fname)
|
|
fullpath = os.path.join(icons_dir, fullname)
|
|
os.remove(fullpath)
|
|
|
|
if toupdate:
|
|
print(('Updating {} icons...'.format(len(toupdate))))
|
|
missing = set()
|
|
for fname in sorted(toupdate):
|
|
icon = get_icon_file(fname)
|
|
if icon is None:
|
|
missing.add(fname)
|
|
continue
|
|
fullname = '{}.png'.format(fname)
|
|
fullpath = os.path.join(icons_dir, fullname)
|
|
icon.save(fullpath, 'png')
|
|
if missing:
|
|
print((' {} icons are missing in export:'.format(len(missing))))
|
|
for fname in sorted(missing):
|
|
print((' {}'.format(fname)))
|
|
|
|
if toadd:
|
|
print(('Adding {} icons...'.format(len(toadd))))
|
|
missing = set()
|
|
for fname in sorted(toadd):
|
|
icon = icon_json.get(str(fname), None)
|
|
if icon is None:
|
|
print("Can't find iconID {}".format(fname))
|
|
continue
|
|
key = icon['iconFile'].lower()
|
|
|
|
for i in range(2):
|
|
scale = i+1
|
|
icon = get_icon_file(key, tuple([x*scale for x in ICON_SIZE]))
|
|
if icon is None:
|
|
missing.add(fname)
|
|
continue
|
|
fullname = '{}@{}x.png'.format(fname, scale)
|
|
fullpath = os.path.join(icons_dir, fullname)
|
|
icon.save(fullpath, 'png')
|
|
if missing:
|
|
print((' {} icons are missing in export:'.format(len(missing))))
|
|
for fname in sorted(missing):
|
|
print((' {}'.format(fname)))
|
|
|
|
print("Doing renders")
|
|
|
|
needed.clear()
|
|
existing.clear()
|
|
toremove.clear()
|
|
|
|
for row in cursor.execute(query_ships):
|
|
needed.add(row[0])
|
|
|
|
toremove = existing.difference(needed)
|
|
toupdate = existing.intersection(needed)
|
|
toadd = needed.difference(existing)
|
|
|
|
if toadd:
|
|
print(('Adding {} renders...'.format(len(toadd))))
|
|
missing = set()
|
|
for fname in sorted(toadd):
|
|
try:
|
|
key = graphics_py_ob[int(fname)]
|
|
except KeyError:
|
|
print("Can't find graphicID {}".format(fname))
|
|
|
|
key = "{}/{}_64.png".format(key, fname)
|
|
|
|
for i in range(2):
|
|
scale = i+1
|
|
icon = get_icon_file(key, tuple([x*scale for x in RENDER_SIZE]))
|
|
if icon is None:
|
|
missing.add(fname)
|
|
continue
|
|
fullname = '{}@{}x.png'.format(fname, scale)
|
|
fullpath = os.path.join(render_dir, fullname)
|
|
icon.save(fullpath, 'png')
|
|
if missing:
|
|
print((' {} renders are missing in export:'.format(len(missing))))
|
|
for fname in sorted(missing):
|
|
print((' {}'.format(fname)))
|