1
0
mirror of https://github.com/mon/ifstools.git synced 2024-12-02 20:47:16 +01:00

GenericFile.load now uses kwargs, add --uv arg

This commit is contained in:
Will Toohey 2018-05-21 22:07:45 +10:00
parent 9004fef5d7
commit c3b01d03f9
5 changed files with 41 additions and 21 deletions

View File

@ -21,7 +21,7 @@ Then run `ifstools` from anywhere in a command prompt.
## Usage ## Usage
``` ```
usage: ifstools [-h] [-e] [-y] [-o OUT_DIR] [--tex-only] [-c] usage: ifstools [-h] [-e] [-y] [-o OUT_DIR] [--tex-only] [-c]
[--bounds] [--no-cache] [-m] [-s] [-r] [--bounds] [--uv] [--no-cache] [-m] [-s] [-r]
file_to_unpack.ifs|folder_to_repack_ifs file_to_unpack.ifs|folder_to_repack_ifs
[file_to_unpack.ifs|folder_to_repack_ifs ...] [file_to_unpack.ifs|folder_to_repack_ifs ...]
@ -43,6 +43,8 @@ optional arguments:
-c, --canvas dump the image canvas as defined by the -c, --canvas dump the image canvas as defined by the
texturelist.xml in _canvas.png texturelist.xml in _canvas.png
--bounds draw image bounds on the exported canvas in red --bounds draw image bounds on the exported canvas in red
--uv crop images to uvrect (usually 1px smaller than
imgrect). Forces --tex-only
--no-cache ignore texture cache, recompress all --no-cache ignore texture cache, recompress all
-m, --extract-manifest -m, --extract-manifest
extract the IFS manifest for inspection extract the IFS manifest for inspection

View File

@ -16,24 +16,24 @@ class GenericFile(Node):
self.start = self.size = None self.start = self.size = None
def extract(self, base, **kwargs): def extract(self, base, **kwargs):
data = self.load() data = self.load(**kwargs)
path = os.path.join(base, self.full_path) path = os.path.join(base, self.full_path)
utils.save_with_timestamp(path, data, self.time) utils.save_with_timestamp(path, data, self.time)
def load(self, convert_kbin = True): def load(self, **kwargs):
if self.from_ifs: if self.from_ifs:
return self._load_from_ifs(convert_kbin) return self._load_from_ifs(**kwargs)
else: else:
return self._load_from_filesystem() return self._load_from_filesystem(**kwargs)
def _load_from_ifs(self, convert_kbin = True): def _load_from_ifs(self, convert_kbin = True, **kwargs):
data = self.ifs_data.get(self.start, self.size) data = self.ifs_data.get(self.start, self.size)
if convert_kbin and self.name.endswith('.xml') and KBinXML.is_binary_xml(data): if convert_kbin and self.name.endswith('.xml') and KBinXML.is_binary_xml(data):
data = KBinXML(data).to_text().encode('utf8') data = KBinXML(data).to_text().encode('utf8')
return data return data
def _load_from_filesystem(self): def _load_from_filesystem(self, **kwargs):
with open(self.disk_path, 'rb') as f: with open(self.disk_path, 'rb') as f:
ret = f.read() ret = f.read()
self.size = len(ret) self.size = len(ret)

View File

@ -25,21 +25,26 @@ class ImageFile(GenericFile):
self.format = fmt self.format = fmt
self.compress = compress self.compress = compress
self.uvrect = self._split_ints(image_elem.find('uvrect').text) # all values are multiplied by 2, odd values have never been seen
self.imgrect = self._split_ints(image_elem.find('imgrect').text) self.uvrect = [x//2 for x in self._split_ints(image_elem.find('uvrect').text)]
self.imgrect = [x//2 for x in self._split_ints(image_elem.find('imgrect').text)]
self.img_size = ( self.img_size = (
(self.imgrect[1]-self.imgrect[0])//2, self.imgrect[1]-self.imgrect[0],
(self.imgrect[3]-self.imgrect[2])//2 self.imgrect[3]-self.imgrect[2]
)
self.uv_size = (
self.uvrect[1]-self.uvrect[0],
self.uvrect[3]-self.uvrect[2]
) )
def extract(self, base, use_cache = True, **kwargs): def extract(self, base, use_cache = True, **kwargs):
GenericFile.extract(self, base, **kwargs) GenericFile.extract(self, base, **kwargs)
if use_cache and self.compress and self.from_ifs and self.format in cachable_formats: if use_cache and self.compress and self.from_ifs and self.format in cachable_formats:
self.write_cache(GenericFile._load_from_ifs(self), base) self.write_cache(GenericFile._load_from_ifs(self, **kwargs), base)
def _load_from_ifs(self, convert_kbin = False): def _load_from_ifs(self, crop_to_uvrect = False, **kwargs):
data = GenericFile._load_from_ifs(self, False) data = GenericFile._load_from_ifs(self, **kwargs)
if self.compress == 'avslz': if self.compress == 'avslz':
uncompressed_size = unpack('>I', data[:4])[0] uncompressed_size = unpack('>I', data[:4])[0]
@ -60,6 +65,17 @@ class ImageFile(GenericFile):
else: else:
raise NotImplementedError('Unknown format {}'.format(self.format)) raise NotImplementedError('Unknown format {}'.format(self.format))
if crop_to_uvrect:
start_x = self.uvrect[0] - self.imgrect[0]
start_y = self.uvrect[2] - self.imgrect[2]
dims = (
start_x,
start_y,
start_x + self.uv_size[0],
start_y + self.uv_size[1],
)
im = im.crop(dims)
b = BytesIO() b = BytesIO()
im.save(b, format = 'PNG') im.save(b, format = 'PNG')
return b.getvalue() return b.getvalue()

View File

@ -27,29 +27,27 @@ class ImageCanvas(GenericFile):
self.images = images self.images = images
self.img_size = size self.img_size = size
self.bbox = False
def extract(self, base, dump_canvas = False, draw_bbox = False, **kwargs): def extract(self, base, dump_canvas = False, **kwargs):
self.bbox = draw_bbox
if dump_canvas: if dump_canvas:
GenericFile.extract(self, base, **kwargs) GenericFile.extract(self, base, **kwargs)
def load(self, convert_kbin = False): def load(self, draw_bbox = False, **kwargs):
''' Makes the canvas. ''' Makes the canvas.
This could be far speedier if it copied raw pixels, but that would This could be far speedier if it copied raw pixels, but that would
take far too much time to write vs using Image inbuilts ''' take far too much time to write vs using Image inbuilts '''
im = Image.new('RGBA', self.img_size) im = Image.new('RGBA', self.img_size)
draw = None draw = None
if self.bbox: if draw_bbox:
draw = ImageDraw.Draw(im) draw = ImageDraw.Draw(im)
for sprite in self.images: for sprite in self.images:
data = sprite.load() data = sprite.load()
sprite_im = Image.open(BytesIO(data)) sprite_im = Image.open(BytesIO(data))
size = [x//2 for x in sprite.imgrect] size = sprite.imgrect
im.paste(sprite_im, (size[0], size[2])) im.paste(sprite_im, (size[0], size[2]))
if self.bbox: if draw_bbox:
draw.rectangle((size[0], size[2], size[1], size[3]), outline='red') draw.rectangle((size[0], size[2], size[1], size[3]), outline='red')
del draw del draw

View File

@ -43,6 +43,7 @@ def main():
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('-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('-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('--bounds', action='store_true', help='draw image bounds on the exported canvas in red', dest='draw_bbox')
parser.add_argument('--uv', action='store_true', help='crop images to uvrect (usually 1px smaller than imgrect). Forces --tex-only', dest='crop_to_uvrect')
parser.add_argument('--no-cache', action='store_false', help='ignore texture cache, recompress all', dest='use_cache') 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',
@ -52,6 +53,9 @@ def main():
args = parser.parse_args() args = parser.parse_args()
if args.crop_to_uvrect:
args.tex_only = True
if args.extract_folders: if args.extract_folders:
dirs = [f for f in args.files if os.path.isdir(f)] dirs = [f for f in args.files if os.path.isdir(f)]
# prune # prune