Skip to content

Commit dbc2fda

Browse files
committed
Refactored resource related code
1 parent 091864f commit dbc2fda

14 files changed

Lines changed: 669 additions & 743 deletions

File tree

src/mgtools/resource/__init__.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,18 +7,18 @@
77
from mgtools.enumerators.game import Game
88
from mgtools.mg1.constants import RESOURCE_SECTION_COUNT as MG1_SECTION_COUNT
99
from mgtools.mg2.constants import RESOURCE_SECTION_COUNT as MG2_SECTION_COUNT
10-
from mgtools.resource_file import Resource
10+
from mgtools.resource.file import Resource
1111

1212
app = typer.Typer(
1313
help="Tools for working with resource files (English.bin, English.raw etc.)"
1414
)
1515

1616

1717
@app.command(
18-
"export",
19-
help="Export resources from specified resource file. (English.bin, English.raw etc.)",
18+
"unpack",
19+
help="Unpack resources from specified resource file. (English.bin, English.raw etc.)",
2020
)
21-
def resource_export(
21+
def resource_unpack(
2222
input_file: Annotated[
2323
Path, typer.Argument(exists=True, file_okay=True, readable=True)
2424
],
@@ -43,16 +43,16 @@ def resource_export(
4343
resource.save_metadata(output_dir)
4444

4545
for index in range(resource.section_count):
46-
resource.export(
46+
resource.unpack(
4747
output_dir,
4848
index,
4949
separate_chars=separate_chars,
5050
locale_format=locale_format,
5151
)
5252

5353

54-
@app.command("generate", help="Generate new resource file from specified folder.")
55-
def resource_generate(
54+
@app.command("pack", help="Pack new resource file from specified folder.")
55+
def resource_pack(
5656
input_dir: Annotated[Path, typer.Argument(dir_okay=True, readable=True)],
5757
output_file: Annotated[
5858
Path | None, typer.Argument(file_okay=True, writable=True)
Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,14 @@
55
from mgtools.enumerators.data_type import DataType
66

77

8-
class File(ABC):
8+
class Asset(ABC):
99
@property
1010
def data_type(self) -> DataType:
1111
return self.__data_type
1212

1313
@property
1414
@abstractmethod
15-
def raw_data(self) -> bytes:
16-
raise NotImplementedError()
15+
def raw_data(self) -> bytes: ...
1716

1817
def __init__(self, data_type: DataType) -> None:
1918
self.__data_type: DataType = data_type
@@ -23,21 +22,17 @@ def __init__(self, data_type: DataType) -> None:
2322
def from_stream(
2423
reader: BufferedReader | BytesIO,
2524
data_type: DataType | None = None,
26-
) -> "File":
27-
raise NotImplementedError()
25+
) -> "Asset": ...
2826

2927
@staticmethod
3028
@abstractmethod
3129
def from_file(
3230
file_path: Path,
3331
data_type: DataType | None = None,
34-
) -> "File":
35-
raise NotImplementedError()
32+
) -> "Asset": ...
3633

3734
@abstractmethod
38-
def add_data(self, **kwargs) -> None:
39-
raise NotImplementedError()
35+
def add_data(self, **kwargs) -> None: ...
4036

4137
@abstractmethod
42-
def export(self, output_path: Path, **kwargs) -> None:
43-
raise NotImplementedError()
38+
def export(self, output_path: Path, **kwargs) -> None: ...
Lines changed: 34 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
from mgtools.constants import EXPORT_FONT_ATLAS_EXTENSION, EXPORT_FONT_METADATA_FILENAME
1010
from mgtools.dataclasses.glyph import Glyph
1111
from mgtools.enumerators.data_type import DataType
12-
from mgtools.file import File
1312
from mgtools.mg1.constants import (
1413
FONT_EXPORT_ATLAS_HEIGHT,
1514
FONT_EXPORT_ATLAS_WIDTH,
@@ -18,10 +17,11 @@
1817
FONT_MINIMUM_PAGE_SIZE,
1918
FONT_START_CHAR,
2019
)
21-
from mgtools.mgscii import get_mgscii_char
20+
from mgtools.resource.asset import Asset
21+
from mgtools.utilities.mgscii import get_mgscii_char
2222

2323

24-
class Font(File):
24+
class Font(Asset):
2525
@property
2626
def raw_data(self) -> bytes:
2727
page_bytes = b""
@@ -50,7 +50,7 @@ def raw_data(self) -> bytes:
5050
)
5151

5252
return (
53-
self.data_type.value.to_bytes(2)
53+
self.data_type.to_bytes(2)
5454
+ b"\0\0" # Identifier placeholder
5555
+ page_bytes
5656
)
@@ -63,7 +63,7 @@ def __init__(self, data_type: DataType) -> None:
6363
def from_stream(
6464
reader: BufferedReader | BytesIO,
6565
data_type: DataType | None = None,
66-
) -> "Font":
66+
) -> Asset:
6767
if data_type is None:
6868
data_type = DataType(int.from_bytes(reader.read(2)))
6969

@@ -82,7 +82,23 @@ def from_stream(
8282
return f
8383

8484
@staticmethod
85-
def from_file(file_path: Path, data_type: DataType | None = None) -> File:
85+
def __encode_glyph(
86+
width: int,
87+
bitmap_bytes: bytes,
88+
glyphs_data: bytearray,
89+
bitmap_data: bytearray,
90+
) -> None:
91+
"""Append one glyph's header + bitmap to the accumulators."""
92+
glyphs_data.extend(len(bitmap_data).to_bytes(2, "little"))
93+
glyphs_data.extend(
94+
(0).to_bytes(2) if width == 1 else ((width - 1) << 4).to_bytes(2, "little")
95+
)
96+
97+
if width != 1 and width != 4096:
98+
bitmap_data.extend(bitmap_bytes)
99+
100+
@staticmethod
101+
def from_file(file_path: Path, data_type: DataType | None = None) -> Asset:
86102
xmlroot = ET.parse(file_path / EXPORT_FONT_METADATA_FILENAME).getroot()
87103
page_elements = xmlroot.findall("Page")
88104
page_bytes = b""
@@ -107,29 +123,19 @@ def from_file(file_path: Path, data_type: DataType | None = None) -> File:
107123
glyph_bitmap_data = b""
108124
else:
109125
glyph_image = Image.open(glyph_image_path).convert("L")
110-
pixel_data = glyph_image.tobytes()
111-
112-
glyph_bitmap_data = Font.__pack_bitmap_data(pixel_data)
113-
126+
glyph_bitmap_data = Font.__pack_bitmap_data(
127+
glyph_image.tobytes()
128+
)
114129
width = glyph_image.width
115130

116-
glyphs_data.extend(len(bitmap_data).to_bytes(2, "little"))
117-
118-
if width == 1:
119-
glyphs_data.extend((0).to_bytes(2))
120-
else:
121-
glyphs_data.extend(((width - 1) << 4).to_bytes(2, "little"))
122-
123-
if width != 1 and width != 4096:
124-
bitmap_data.extend(glyph_bitmap_data)
131+
Font.__encode_glyph(
132+
width, glyph_bitmap_data, glyphs_data, bitmap_data
133+
)
125134
else:
126-
atlas_image = Image.open(
127-
file_path / f"{page_idx}.{EXPORT_FONT_ATLAS_EXTENSION}"
128-
).convert("L")
135+
atlas_image = Image.open(atlas_path).convert("L")
129136

130137
for glyph_element in page.findall("Glyph"):
131138
width = int(glyph_element.get("width", "0"))
132-
133139
x_offset = int(glyph_element.get("x_offset", "0"))
134140
y_offset = int(glyph_element.get("y_offset", "0"))
135141

@@ -142,25 +148,18 @@ def from_file(file_path: Path, data_type: DataType | None = None) -> File:
142148
)
143149
)
144150

145-
pixel_data = glyph_image.tobytes()
146-
glyph_bitmap_data = Font.__pack_bitmap_data(pixel_data)
151+
glyph_bitmap_data = Font.__pack_bitmap_data(glyph_image.tobytes())
147152

148-
glyphs_data.extend(len(bitmap_data).to_bytes(2, "little"))
149-
150-
if width == 1:
151-
glyphs_data.extend((0).to_bytes(2))
152-
else:
153-
glyphs_data.extend(((width - 1) << 4).to_bytes(2, "little"))
154-
155-
if width != 1 and width != 4096:
156-
bitmap_data.extend(glyph_bitmap_data)
153+
Font.__encode_glyph(
154+
width, glyph_bitmap_data, glyphs_data, bitmap_data
155+
)
157156

158157
page_bytes += (
159158
len(glyphs_data + bitmap_data).to_bytes(4) + glyphs_data + bitmap_data
160159
)
161160

162161
return Font.from_stream(
163-
BytesIO(DataType.MG1_FONT.value.to_bytes(2) + b"\0\0" + page_bytes)
162+
BytesIO(DataType.MG1_FONT.to_bytes(2) + b"\0\0" + page_bytes)
164163
)
165164

166165
def add_data(self, **kwargs) -> None:

0 commit comments

Comments
 (0)