1
0
mirror of https://github.com/mon/ifstools.git synced 2024-11-24 01:50:10 +01:00

Canvas dumping, rename nocache to no-cache

This commit is contained in:
Will Toohey 2018-04-22 18:09:58 +02:00
parent ee8ae3374c
commit 8c5ed5a3b9
4 changed files with 73 additions and 9 deletions

View File

@ -1,25 +1,75 @@
from io import BytesIO
from kbinxml import KBinXML from kbinxml import KBinXML
from tqdm import tqdm
from PIL import Image, ImageDraw
from . import MD5Folder, ImageFile, GenericFile from . import MD5Folder, ImageFile, GenericFile
from .ImageDecoders import cachable_formats
class TextureList(GenericFile): class TextureList(GenericFile):
def _load_from_filesystem(self): def _load_from_filesystem(self):
raw = GenericFile._load_from_filesystem(self) raw = GenericFile._load_from_filesystem(self)
k = KBinXML(raw) k = KBinXML(raw)
# force the only type we can compress # fallback to a type we can encode
for tex in k.xml_doc.iterchildren(): for tex in k.xml_doc.iterchildren():
if tex.attrib['format'] not in cachable_formats:
tex.attrib['format'] = 'argb8888rev' tex.attrib['format'] = 'argb8888rev'
return k.to_binary() return k.to_binary()
class ImageCanvas(GenericFile):
def __init__(self, name, size, images, parent):
self.name = '_canvas_{}.png'.format(name)
self._packed_name = self.name
self.time = parent.time
self.path = parent.path
self.images = images
self.img_size = size
self.bbox = False
def extract(self, base, dump_canvas = False, draw_bbox = False, **kwargs):
self.bbox = draw_bbox
if dump_canvas:
GenericFile.extract(self, base, **kwargs)
def load(self, convert_kbin = False):
''' Makes the canvas.
This could be far speedier if it copied raw pixels, but that would
take far too much time to write vs using Image inbuilts '''
im = Image.new('RGBA', self.img_size)
if self.bbox:
draw = ImageDraw.Draw(im)
for sprite in self.images:
data = sprite.load()
sprite_im = Image.open(BytesIO(data))
size = [x//2 for x in sprite.imgrect]
im.paste(sprite_im, (size[0], size[2]))
if self.bbox:
draw.rectangle((size[0], size[2], size[1], size[3]), outline='red')
del draw
b = BytesIO()
im.save(b, format = 'PNG')
return b.getvalue()
# since it's basically metadata, we ignore similarly to _cache
def repack(self, manifest, data_blob, tqdm_progress, **kwargs):
return
class TexFolder(MD5Folder): class TexFolder(MD5Folder):
def __init__(self, ifs_data, obj, parent = None, path = '', name = '', supers = None): def __init__(self, ifs_data, obj, parent = None, path = '', name = '', supers = None):
MD5Folder.__init__(self, ifs_data, obj, parent, path, name, supers, 'image', '.png') MD5Folder.__init__(self, ifs_data, obj, parent, path, name, supers, 'image', '.png')
def tree_complete(self): def tree_complete(self):
MD5Folder.tree_complete(self) MD5Folder.tree_complete(self)
if '_cache' in self.folders: if '_cache' in self.folders:
self.folders.pop('_cache') self.folders.pop('_cache')
if not self.info_kbin: if not self.info_kbin:
return return
@ -32,12 +82,17 @@ class TexFolder(MD5Folder):
for tex in self.info_kbin.xml_doc.iterchildren(): for tex in self.info_kbin.xml_doc.iterchildren():
folder = tex.attrib['name'] folder = tex.attrib['name']
fmt = tex.attrib['format'] fmt = tex.attrib['format']
canvas_contents = []
canvas_size = None
for indiv in tex.iterchildren(): for indiv in tex.iterchildren():
if indiv.tag == 'size': if indiv.tag == 'size':
continue canvas_size = self._split_ints(indiv.text)
elif indiv.tag == 'image': elif indiv.tag == 'image':
name = indiv.attrib['name'] + '.png' name = indiv.attrib['name'] + '.png'
if name in self.files: if name in self.files:
ImageFile.upgrade_generic(self.files[name], indiv, fmt, self.compress) ImageFile.upgrade_generic(self.files[name], indiv, fmt, self.compress)
canvas_contents.append(self.files[name])
else: else:
print('Unknown texturelist.xml element {}'.format(indiv.tag)) tqdm.write('Unknown texturelist.xml element {}'.format(indiv.tag))
canvas = ImageCanvas(folder, canvas_size, canvas_contents, self)
self.files[canvas.name] = canvas

View File

@ -6,4 +6,4 @@ from .ImageFile import ImageFile
from .GenericFolder import GenericFolder from .GenericFolder import GenericFolder
from .MD5Folder import MD5Folder from .MD5Folder import MD5Folder
from .AfpFolder import AfpFolder from .AfpFolder import AfpFolder
from .TexFolder import TexFolder from .TexFolder import TexFolder, ImageCanvas

View File

@ -11,7 +11,7 @@ from tqdm import tqdm
from kbinxml import KBinXML from kbinxml import KBinXML
from kbinxml.bytebuffer import ByteBuffer from kbinxml.bytebuffer import ByteBuffer
from .handlers import GenericFolder, MD5Folder, ImageFile from .handlers import GenericFolder, MD5Folder, ImageFile, ImageCanvas
from . import utils from . import utils
SIGNATURE = 0x6CAD8F89 SIGNATURE = 0x6CAD8F89
@ -143,7 +143,14 @@ class IFS:
# build the tree # build the tree
for folder in self.tree.all_folders: for folder in self.tree.all_folders:
if tex_only and folder.name != 'tex': if tex_only and folder.name == 'tex':
self.tree = folder
# make it root to discourage repacking
folder.name = ''
for f in folder.all_files:
f.path = ''
break
elif tex_only:
continue continue
f_path = join(path, folder.full_path) f_path = join(path, folder.full_path)
utils.mkdir_silent(f_path) utils.mkdir_silent(f_path)
@ -151,7 +158,7 @@ class IFS:
# extract the files # extract the files
for f in tqdm(self.tree.all_files): for f in tqdm(self.tree.all_files):
if tex_only and not isinstance(f, ImageFile): if tex_only and not isinstance(f, ImageFile) and not isinstance(f, ImageCanvas):
continue continue
f.extract(path, **kwargs) f.extract(path, **kwargs)
if progress: if progress:

View File

@ -41,7 +41,9 @@ def main():
parser.add_argument('-y', action='store_true', help='don\'t prompt for file/folder overwrite', dest='overwrite') parser.add_argument('-y', action='store_true', help='don\'t prompt for file/folder overwrite', dest='overwrite')
parser.add_argument('-o', default='.', help='output directory', dest='out_dir') parser.add_argument('-o', default='.', help='output directory', dest='out_dir')
parser.add_argument('--tex-only', action='store_true', help='only extract textures', dest='tex_only') parser.add_argument('--tex-only', action='store_true', help='only extract textures', dest='tex_only')
parser.add_argument('--nocache', action='store_false', help='ignore texture cache, recompress all', dest='use_cache') parser.add_argument('-c', '--canvas', action='store_true', help='dump the image canvas as defined by the texturelist.xml in _canvas.png', dest='dump_canvas')
parser.add_argument('--bounds', action='store_true', help='draw image bounds on the exported canvas in red', dest='draw_bbox')
parser.add_argument('--no-cache', action='store_false', help='ignore texture cache, recompress all', dest='use_cache')
parser.add_argument('-m', '--extract-manifest', action='store_true', help='extract the IFS manifest for inspection', dest='extract_manifest') parser.add_argument('-m', '--extract-manifest', action='store_true', help='extract the IFS manifest for inspection', dest='extract_manifest')
parser.add_argument('-s', '--silent', action='store_false', dest='progress', parser.add_argument('-s', '--silent', action='store_false', dest='progress',
help='don\'t display files as they are processed') help='don\'t display files as they are processed')