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:
parent
9004fef5d7
commit
c3b01d03f9
@ -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
|
||||||
|
@ -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)
|
||||||
|
@ -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()
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user