diff --git a/bemani/format/tdxt.py b/bemani/format/tdxt.py index 59f5d7c..962e383 100644 --- a/bemani/format/tdxt.py +++ b/bemani/format/tdxt.py @@ -16,6 +16,7 @@ class TDXT: fmt: int, fmtflags: int, endian: str, + length_fixup: bool, raw: bytes, img: Optional[Image.Image], ) -> None: @@ -27,6 +28,7 @@ class TDXT: self.fmt = fmt self.fmtflags = fmtflags self.endian = endian + self.length_fixup = length_fixup self.__raw = raw self.__img = img @@ -78,7 +80,13 @@ class TDXT: f"{endian}4sIIIHHIII", raw_data[0:32], ) - if (raw_length + 64) != len(raw_data): + # Standalone TDXT files don't include the header in the length. Embedded ones + # inside a TXP2 file do. Ugh. + if raw_length == len(raw_data): + length_fixup = False + elif (raw_length + 64) == len(raw_data): + length_fixup = True + else: raise Exception("Invalid texture length!") # I have only ever observed the following values across two different games. @@ -116,6 +124,7 @@ class TDXT: fmt=fmt, fmtflags=fmtflags & 0xFFFFFF00, endian=endian, + length_fixup=length_fixup, raw=raw_data[64:], img=TDXT._rawToImg(width, height, fmt, endian, raw_data[64:]), ) @@ -322,7 +331,9 @@ class TDXT: magic, self.header_flags1, self.header_flags2, - 64 + len(self.raw), + # Some files include the header in the length, some do not. We detect this + # in the header, and round-trip it here. + len(self.raw) if self.length_fixup else (64 + len(self.raw)), self.width, self.height, fmtflags, diff --git a/bemani/utils/tdxtutils.py b/bemani/utils/tdxtutils.py index eca8415..fadc62c 100644 --- a/bemani/utils/tdxtutils.py +++ b/bemani/utils/tdxtutils.py @@ -30,7 +30,9 @@ def extract_texture( output_dir = os.path.dirname(os.path.abspath(output_fname)) os.makedirs(output_dir, exist_ok=True) - print(f"Extracting texture from {os.path.abspath(fname)} to {os.path.abspath(output_fname)}") + print( + f"Extracting texture from {os.path.abspath(fname)} to {os.path.abspath(output_fname)}" + ) with open(output_fname, "wb") as bfp: tdxt.img.save(bfp, format="PNG") @@ -52,7 +54,9 @@ def update_texture( tdxt.img = img - print(f"Updating texture in {os.path.abspath(fname)} from {os.path.abspath(input_fname)}") + print( + f"Updating texture in {os.path.abspath(fname)} from {os.path.abspath(input_fname)}" + ) with open(fname, "wb") as bfp: bfp.write(tdxt.toBytes())