diff --git a/bemani/format/afp/geo.py b/bemani/format/afp/geo.py index bc6ff2a..81eb940 100644 --- a/bemani/format/afp/geo.py +++ b/bemani/format/afp/geo.py @@ -15,10 +15,14 @@ class Shape: self.name = name self.data = data - # Vertex points outlining this shape. + # Vertex points outlining this shape. These are in pixels and the rectangle they outline + # should match the size of the texture in pixels. self.vertex_points: List[Point] = [] - # Texture points, as used alongside vertex chunks when the shape contains a texture. + # Texture points, as used alongside vertex chunks when the shape contains a texture. These + # are in floating points that when multiplied by the width and height of the original + # texture sheet that the texture was taken from (multiplied by two), should match the uvrect + # of the texture exactly. self.tex_points: List[Point] = [] # Colors for texture points, if they exist in the file. diff --git a/bemani/format/ifs.py b/bemani/format/ifs.py index e3c14eb..d2e86b7 100644 --- a/bemani/format/ifs.py +++ b/bemani/format/ifs.py @@ -22,7 +22,8 @@ class IFS: self.__files: Dict[str, bytes] = {} self.__formats: Dict[str, str] = {} self.__compressed: Dict[str, bool] = {} - self.__sizes: Dict[str, Tuple[int, int]] = {} + self.__imgsize: Dict[str, Tuple[int, int, int, int]] = {} + self.__uvsize: Dict[str, Tuple[int, int, int, int]] = {} self.__decode_binxml = decode_binxml self.__decode_textures = decode_textures self.__parse_file(data) @@ -141,9 +142,19 @@ class IFS: rect = subchild.child_value('imgrect') if rect is not None: - self.__sizes[newname] = ( - (rect[1] - rect[0]) // 2, - (rect[3] - rect[2]) // 2, + self.__imgsize[newname] = ( + rect[0] // 2, + rect[1] // 2, + rect[2] // 2, + rect[3] // 2, + ) + rect = subchild.child_value('uvrect') + if rect is not None: + self.__uvsize[newname] = ( + rect[0] // 2, + rect[1] // 2, + rect[2] // 2, + rect[3] // 2, ) elif abs_filename.endswith("/afplist.xml"): # This is a texture index. @@ -212,18 +223,27 @@ class IFS: if filexml is not None: filedata = str(filexml).encode('utf-8') - if self.__decode_textures and filename in self.__formats and filename in self.__sizes: + if self.__decode_textures and filename in self.__formats and filename in self.__imgsize and filename in self.__uvsize: fmt = self.__formats[filename] - wh = self.__sizes[filename] + img = self.__imgsize[filename] + crop = self.__uvsize[filename] # Decode the image data itself. if fmt == "argb8888rev": - if len(filedata) < (wh[0] * wh[1] * 4): - left = (wh[0] * wh[1] * 4) - len(filedata) + width = img[1] - img[0] + height = img[3] - img[2] + if len(filedata) < (width * height * 4): + left = (width * height * 4) - len(filedata) filedata = filedata + b'\x00' * left - img = Image.frombytes('RGBA', wh, filedata, 'raw', 'BGRA') + png = Image.frombytes('RGBA', (width, height), filedata, 'raw', 'BGRA') + png = png.crop(( + crop[0] - img[0], + crop[2] - img[2], + crop[1] - img[0], + crop[3] - img[2], + )) b = io.BytesIO() - img.save(b, format='PNG') + png.save(b, format='PNG') filedata = b.getvalue() return filedata