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 tqdm import tqdm
from PIL import Image, ImageDraw
from . import MD5Folder, ImageFile, GenericFile
from .ImageDecoders import cachable_formats
class TextureList(GenericFile):
def _load_from_filesystem(self):
raw = GenericFile._load_from_filesystem(self)
k = KBinXML(raw)
# force the only type we can compress
# fallback to a type we can encode
for tex in k.xml_doc.iterchildren():
tex.attrib['format'] = 'argb8888rev'
if tex.attrib['format'] not in cachable_formats:
tex.attrib['format'] = 'argb8888rev'
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):
def __init__(self, ifs_data, obj, parent = None, path = '', name = '', supers = None):
MD5Folder.__init__(self, ifs_data, obj, parent, path, name, supers, 'image', '.png')
def tree_complete(self):
MD5Folder.tree_complete(self)
if '_cache' in self.folders:
self.folders.pop('_cache')
if not self.info_kbin:
return
@ -32,12 +82,17 @@ class TexFolder(MD5Folder):
for tex in self.info_kbin.xml_doc.iterchildren():
folder = tex.attrib['name']
fmt = tex.attrib['format']
canvas_contents = []
canvas_size = None
for indiv in tex.iterchildren():
if indiv.tag == 'size':
continue
canvas_size = self._split_ints(indiv.text)
elif indiv.tag == 'image':
name = indiv.attrib['name'] + '.png'
if name in self.files:
ImageFile.upgrade_generic(self.files[name], indiv, fmt, self.compress)
canvas_contents.append(self.files[name])
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 .MD5Folder import MD5Folder
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.bytebuffer import ByteBuffer
from .handlers import GenericFolder, MD5Folder, ImageFile
from .handlers import GenericFolder, MD5Folder, ImageFile, ImageCanvas
from . import utils
SIGNATURE = 0x6CAD8F89
@ -143,7 +143,14 @@ class IFS:
# build the tree
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
f_path = join(path, folder.full_path)
utils.mkdir_silent(f_path)
@ -151,7 +158,7 @@ class IFS:
# extract the 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
f.extract(path, **kwargs)
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('-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('--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('-s', '--silent', action='store_false', dest='progress',
help='don\'t display files as they are processed')