ReverseBox 0.18.2__tar.gz → 0.18.4__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (100) hide show
  1. {ReverseBox-0.18.2 → ReverseBox-0.18.4}/PKG-INFO +1 -1
  2. {ReverseBox-0.18.2 → ReverseBox-0.18.4}/ReverseBox.egg-info/PKG-INFO +1 -1
  3. {ReverseBox-0.18.2 → ReverseBox-0.18.4}/ReverseBox.egg-info/SOURCES.txt +4 -0
  4. ReverseBox-0.18.4/reversebox/compression/compression_refpack.py +68 -0
  5. ReverseBox-0.18.4/reversebox/image/decoders/bumpmap_decoder.py +58 -0
  6. ReverseBox-0.18.4/reversebox/image/decoders/n64_decoder.py +100 -0
  7. ReverseBox-0.18.4/reversebox/image/decoders/yuv_decoder.py +519 -0
  8. {ReverseBox-0.18.2 → ReverseBox-0.18.4}/reversebox/image/swizzling/swizzle_ps2.py +4 -4
  9. ReverseBox-0.18.4/reversebox/libs/__init__.py +0 -0
  10. ReverseBox-0.18.4/reversebox/libs/refpack.dll +0 -0
  11. {ReverseBox-0.18.2 → ReverseBox-0.18.4}/setup.py +1 -1
  12. ReverseBox-0.18.2/reversebox/compression/compression_refpack.py +0 -55
  13. ReverseBox-0.18.2/reversebox/libs/refpack.dll +0 -0
  14. {ReverseBox-0.18.2 → ReverseBox-0.18.4}/LICENSE +0 -0
  15. {ReverseBox-0.18.2 → ReverseBox-0.18.4}/README.md +0 -0
  16. {ReverseBox-0.18.2 → ReverseBox-0.18.4}/ReverseBox.egg-info/dependency_links.txt +0 -0
  17. {ReverseBox-0.18.2 → ReverseBox-0.18.4}/ReverseBox.egg-info/requires.txt +0 -0
  18. {ReverseBox-0.18.2 → ReverseBox-0.18.4}/ReverseBox.egg-info/top_level.txt +0 -0
  19. {ReverseBox-0.18.2 → ReverseBox-0.18.4}/reversebox/__init__.py +0 -0
  20. {ReverseBox-0.18.2 → ReverseBox-0.18.4}/reversebox/checksum/__init__.py +0 -0
  21. {ReverseBox-0.18.2 → ReverseBox-0.18.4}/reversebox/checksum/checksum_adler32.py +0 -0
  22. {ReverseBox-0.18.2 → ReverseBox-0.18.4}/reversebox/checksum/checksum_fletcher16.py +0 -0
  23. {ReverseBox-0.18.2 → ReverseBox-0.18.4}/reversebox/checksum/checksum_fletcher32.py +0 -0
  24. {ReverseBox-0.18.2 → ReverseBox-0.18.4}/reversebox/checksum/checksum_internet_ipv4_header.py +0 -0
  25. {ReverseBox-0.18.2 → ReverseBox-0.18.4}/reversebox/checksum/checksum_sum8.py +0 -0
  26. {ReverseBox-0.18.2 → ReverseBox-0.18.4}/reversebox/checksum/checksum_sum8_2s_complement.py +0 -0
  27. {ReverseBox-0.18.2 → ReverseBox-0.18.4}/reversebox/checksum/checksum_unix_sum_bsd16.py +0 -0
  28. {ReverseBox-0.18.2 → ReverseBox-0.18.4}/reversebox/checksum/checksum_unix_sum_sysv.py +0 -0
  29. {ReverseBox-0.18.2 → ReverseBox-0.18.4}/reversebox/checksum/checksum_xor8.py +0 -0
  30. {ReverseBox-0.18.2 → ReverseBox-0.18.4}/reversebox/common/__init__.py +0 -0
  31. {ReverseBox-0.18.2 → ReverseBox-0.18.4}/reversebox/common/common.py +0 -0
  32. {ReverseBox-0.18.2 → ReverseBox-0.18.4}/reversebox/common/logger.py +0 -0
  33. {ReverseBox-0.18.2 → ReverseBox-0.18.4}/reversebox/compression/__init__.py +0 -0
  34. {ReverseBox-0.18.2 → ReverseBox-0.18.4}/reversebox/compression/compression_jcalg1.py +0 -0
  35. {ReverseBox-0.18.2 → ReverseBox-0.18.4}/reversebox/compression/compression_lzo.py +0 -0
  36. {ReverseBox-0.18.2 → ReverseBox-0.18.4}/reversebox/compression/compression_mio0.py +0 -0
  37. {ReverseBox-0.18.2 → ReverseBox-0.18.4}/reversebox/compression/compression_zlib.py +0 -0
  38. {ReverseBox-0.18.2 → ReverseBox-0.18.4}/reversebox/crc/__init__.py +0 -0
  39. {ReverseBox-0.18.2 → ReverseBox-0.18.4}/reversebox/crc/crc16_arc.py +0 -0
  40. {ReverseBox-0.18.2 → ReverseBox-0.18.4}/reversebox/crc/crc16_ccitt.py +0 -0
  41. {ReverseBox-0.18.2 → ReverseBox-0.18.4}/reversebox/crc/crc16_dnp.py +0 -0
  42. {ReverseBox-0.18.2 → ReverseBox-0.18.4}/reversebox/crc/crc16_ea_crcf.py +0 -0
  43. {ReverseBox-0.18.2 → ReverseBox-0.18.4}/reversebox/crc/crc16_kermit.py +0 -0
  44. {ReverseBox-0.18.2 → ReverseBox-0.18.4}/reversebox/crc/crc16_modbus.py +0 -0
  45. {ReverseBox-0.18.2 → ReverseBox-0.18.4}/reversebox/crc/crc16_sick.py +0 -0
  46. {ReverseBox-0.18.2 → ReverseBox-0.18.4}/reversebox/crc/crc32_asobo.py +0 -0
  47. {ReverseBox-0.18.2 → ReverseBox-0.18.4}/reversebox/crc/crc32_iso_hdlc.py +0 -0
  48. {ReverseBox-0.18.2 → ReverseBox-0.18.4}/reversebox/crc/crc64_asobo.py +0 -0
  49. {ReverseBox-0.18.2 → ReverseBox-0.18.4}/reversebox/crc/crc64_go_iso.py +0 -0
  50. {ReverseBox-0.18.2 → ReverseBox-0.18.4}/reversebox/crc/crc8.py +0 -0
  51. {ReverseBox-0.18.2 → ReverseBox-0.18.4}/reversebox/crc/crc_unix_cksum.py +0 -0
  52. {ReverseBox-0.18.2 → ReverseBox-0.18.4}/reversebox/encryption/__init__.py +0 -0
  53. {ReverseBox-0.18.2 → ReverseBox-0.18.4}/reversebox/encryption/encryption_rot13.py +0 -0
  54. {ReverseBox-0.18.2 → ReverseBox-0.18.4}/reversebox/encryption/encryption_xor_basic.py +0 -0
  55. {ReverseBox-0.18.2 → ReverseBox-0.18.4}/reversebox/encryption/encryption_xor_basic_key_guesser.py +0 -0
  56. {ReverseBox-0.18.2 → ReverseBox-0.18.4}/reversebox/encryption/encryption_xor_gianas_return_zda.py +0 -0
  57. {ReverseBox-0.18.2 → ReverseBox-0.18.4}/reversebox/encryption/encryption_xor_retro64_eco.py +0 -0
  58. {ReverseBox-0.18.2 → ReverseBox-0.18.4}/reversebox/hash/__init__.py +0 -0
  59. {ReverseBox-0.18.2 → ReverseBox-0.18.4}/reversebox/hash/hash_ap.py +0 -0
  60. {ReverseBox-0.18.2 → ReverseBox-0.18.4}/reversebox/hash/hash_djb2.py +0 -0
  61. {ReverseBox-0.18.2 → ReverseBox-0.18.4}/reversebox/hash/hash_fnv.py +0 -0
  62. {ReverseBox-0.18.2 → ReverseBox-0.18.4}/reversebox/hash/hash_md2.py +0 -0
  63. {ReverseBox-0.18.2 → ReverseBox-0.18.4}/reversebox/hash/hash_md5.py +0 -0
  64. {ReverseBox-0.18.2 → ReverseBox-0.18.4}/reversebox/hash/hash_sdbm.py +0 -0
  65. {ReverseBox-0.18.2 → ReverseBox-0.18.4}/reversebox/hash/hash_sha1.py +0 -0
  66. {ReverseBox-0.18.2 → ReverseBox-0.18.4}/reversebox/hash/hash_sha2.py +0 -0
  67. {ReverseBox-0.18.2 → ReverseBox-0.18.4}/reversebox/image/__init__.py +0 -0
  68. {ReverseBox-0.18.2 → ReverseBox-0.18.4}/reversebox/image/common.py +0 -0
  69. {ReverseBox-0.18.2 → ReverseBox-0.18.4}/reversebox/image/compression/__init__.py +0 -0
  70. {ReverseBox-0.18.2 → ReverseBox-0.18.4}/reversebox/image/compression/compression_gst.py +0 -0
  71. {ReverseBox-0.18.2/reversebox/image/file_formats → ReverseBox-0.18.4/reversebox/image/decoders}/__init__.py +0 -0
  72. {ReverseBox-0.18.2/reversebox/image/palettes → ReverseBox-0.18.4/reversebox/image/file_formats}/__init__.py +0 -0
  73. {ReverseBox-0.18.2 → ReverseBox-0.18.4}/reversebox/image/file_formats/image_dds.py +0 -0
  74. {ReverseBox-0.18.2 → ReverseBox-0.18.4}/reversebox/image/image_decoder.py +0 -0
  75. {ReverseBox-0.18.2 → ReverseBox-0.18.4}/reversebox/image/image_encoder.py +0 -0
  76. {ReverseBox-0.18.2 → ReverseBox-0.18.4}/reversebox/image/image_formats.py +0 -0
  77. {ReverseBox-0.18.2/reversebox/image/swizzling → ReverseBox-0.18.4/reversebox/image/palettes}/__init__.py +0 -0
  78. {ReverseBox-0.18.2 → ReverseBox-0.18.4}/reversebox/image/palettes/palette_random.py +0 -0
  79. {ReverseBox-0.18.2 → ReverseBox-0.18.4}/reversebox/image/pillow_wrapper.py +0 -0
  80. {ReverseBox-0.18.2/reversebox/io_files → ReverseBox-0.18.4/reversebox/image/swizzling}/__init__.py +0 -0
  81. {ReverseBox-0.18.2 → ReverseBox-0.18.4}/reversebox/image/swizzling/swizzle_3ds.py +0 -0
  82. {ReverseBox-0.18.2 → ReverseBox-0.18.4}/reversebox/image/swizzling/swizzle_bc.py +0 -0
  83. {ReverseBox-0.18.2 → ReverseBox-0.18.4}/reversebox/image/swizzling/swizzle_cmpr.py +0 -0
  84. {ReverseBox-0.18.2 → ReverseBox-0.18.4}/reversebox/image/swizzling/swizzle_gamecube.py +0 -0
  85. {ReverseBox-0.18.2 → ReverseBox-0.18.4}/reversebox/image/swizzling/swizzle_gst.py +0 -0
  86. {ReverseBox-0.18.2 → ReverseBox-0.18.4}/reversebox/image/swizzling/swizzle_morton.py +0 -0
  87. {ReverseBox-0.18.2 → ReverseBox-0.18.4}/reversebox/image/swizzling/swizzle_morton_dreamcast.py +0 -0
  88. {ReverseBox-0.18.2 → ReverseBox-0.18.4}/reversebox/image/swizzling/swizzle_morton_ps4.py +0 -0
  89. {ReverseBox-0.18.2 → ReverseBox-0.18.4}/reversebox/image/swizzling/swizzle_psp.py +0 -0
  90. {ReverseBox-0.18.2 → ReverseBox-0.18.4}/reversebox/image/swizzling/swizzle_psvita.py +0 -0
  91. {ReverseBox-0.18.2 → ReverseBox-0.18.4}/reversebox/image/swizzling/swizzle_switch.py +0 -0
  92. {ReverseBox-0.18.2/reversebox/libs → ReverseBox-0.18.4/reversebox/io_files}/__init__.py +0 -0
  93. {ReverseBox-0.18.2 → ReverseBox-0.18.4}/reversebox/io_files/bytes_handler.py +0 -0
  94. {ReverseBox-0.18.2 → ReverseBox-0.18.4}/reversebox/io_files/bytes_helper_functions.py +0 -0
  95. {ReverseBox-0.18.2 → ReverseBox-0.18.4}/reversebox/io_files/check_file.py +0 -0
  96. {ReverseBox-0.18.2 → ReverseBox-0.18.4}/reversebox/io_files/file_handler.py +0 -0
  97. {ReverseBox-0.18.2 → ReverseBox-0.18.4}/reversebox/io_files/mod_handler.py +0 -0
  98. {ReverseBox-0.18.2 → ReverseBox-0.18.4}/reversebox/io_files/translation_text_handler.py +0 -0
  99. {ReverseBox-0.18.2 → ReverseBox-0.18.4}/reversebox/libs/ea_swizzle.dll +0 -0
  100. {ReverseBox-0.18.2 → ReverseBox-0.18.4}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: ReverseBox
3
- Version: 0.18.2
3
+ Version: 0.18.4
4
4
  Summary: A set of functions useful in reverse engineering.
5
5
  Home-page: https://github.com/bartlomiejduda/ReverseBox
6
6
  Author: Bartlomiej Duda
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: ReverseBox
3
- Version: 0.18.2
3
+ Version: 0.18.4
4
4
  Summary: A set of functions useful in reverse engineering.
5
5
  Home-page: https://github.com/bartlomiejduda/ReverseBox
6
6
  Author: Bartlomiej Duda
@@ -63,6 +63,10 @@ reversebox/image/image_formats.py
63
63
  reversebox/image/pillow_wrapper.py
64
64
  reversebox/image/compression/__init__.py
65
65
  reversebox/image/compression/compression_gst.py
66
+ reversebox/image/decoders/__init__.py
67
+ reversebox/image/decoders/bumpmap_decoder.py
68
+ reversebox/image/decoders/n64_decoder.py
69
+ reversebox/image/decoders/yuv_decoder.py
66
70
  reversebox/image/file_formats/__init__.py
67
71
  reversebox/image/file_formats/image_dds.py
68
72
  reversebox/image/palettes/__init__.py
@@ -0,0 +1,68 @@
1
+ """
2
+ Copyright © 2024 Bartłomiej Duda
3
+ License: GPL-3.0 License
4
+ """
5
+ import ctypes
6
+ from ctypes import c_char
7
+
8
+ from reversebox.common.common import get_dll_path
9
+
10
+ # fmt: off
11
+
12
+
13
+ class RefpackHandler:
14
+ def compress_data(self, uncompressed_data: bytes) -> bytes:
15
+ if len(uncompressed_data) == 0:
16
+ raise Exception("Data is empty! Nothing to compress!")
17
+
18
+ maxback: int = 131072
19
+ quick: int = 0
20
+
21
+ c_uncompressed_data_len = ctypes.c_uint(len(uncompressed_data))
22
+ c_uncompressed_data = (ctypes.c_ubyte * len(uncompressed_data))(*uncompressed_data)
23
+ c_compressed_data_buffer = (c_char * int(len(uncompressed_data)*5))() # just in case
24
+ c_options_maxback = ctypes.c_uint(maxback)
25
+ c_options_quick = ctypes.c_uint(quick)
26
+
27
+ try:
28
+ refpack_dll_path: str = get_dll_path("refpack.dll")
29
+ refpack_dll_file = ctypes.CDLL(refpack_dll_path)
30
+ compressed_data_size = refpack_dll_file.refpack_compress(ctypes.byref(c_compressed_data_buffer), c_uncompressed_data, c_uncompressed_data_len, ctypes.byref(c_options_maxback), ctypes.byref(c_options_quick))
31
+ except Exception as error:
32
+ raise Exception(f"Error while decompressing refpack data! Error: {error}")
33
+ return bytes(bytearray(c_compressed_data_buffer)[:compressed_data_size])
34
+
35
+ def _get_output_buffer_size(self, compressed_data: bytes) -> int:
36
+ current_input_offset: int = 0
37
+ compression_type = compressed_data[current_input_offset]
38
+ current_input_offset += 1
39
+ compression_type = (compression_type << 8) + compressed_data[current_input_offset]
40
+ current_input_offset += 1
41
+
42
+ if compression_type & 0x100:
43
+ current_input_offset += 3 # skip uncompressed_size
44
+
45
+ uncompressed_size: int = compressed_data[current_input_offset]
46
+ current_input_offset += 1
47
+ uncompressed_size = (uncompressed_size << 8) + compressed_data[current_input_offset]
48
+ current_input_offset += 1
49
+ uncompressed_size = (uncompressed_size << 8) + compressed_data[current_input_offset]
50
+ current_input_offset += 1
51
+ return uncompressed_size
52
+
53
+ def decompress_data(self, compressed_data: bytes) -> bytes:
54
+ if len(compressed_data) < 5:
55
+ raise Exception("Compressed data too short!")
56
+ if compressed_data[:2] != b"\x10\xFB":
57
+ raise Exception("Wrong refpack compression header!")
58
+
59
+ uncompressed_data_buffer = (c_char * self._get_output_buffer_size(compressed_data))()
60
+ compressed_data_len = ctypes.c_uint(len(compressed_data))
61
+
62
+ try:
63
+ refpack_dll_path: str = get_dll_path("refpack.dll")
64
+ refpack_dll_file = ctypes.CDLL(refpack_dll_path)
65
+ uncompressed_data_size = refpack_dll_file.refpack_decompress(ctypes.byref(uncompressed_data_buffer), compressed_data, ctypes.byref(compressed_data_len))
66
+ except Exception as error:
67
+ raise Exception(f"Error while decompressing refpack data! Error: {error}")
68
+ return bytes(bytearray(uncompressed_data_buffer)[:uncompressed_data_size])
@@ -0,0 +1,58 @@
1
+ """
2
+ Copyright © 2024 Bartłomiej Duda
3
+ License: GPL-3.0 License
4
+ """
5
+ import math
6
+
7
+ from reversebox.common.logger import get_logger
8
+ from reversebox.image.image_formats import ImageFormats
9
+
10
+ logger = get_logger(__name__)
11
+
12
+ # fmt: off
13
+
14
+
15
+ class BumpmapDecoder:
16
+
17
+ def __init__(self):
18
+ pass
19
+
20
+ # 16-bit normal map. Each texel consist of a pair of 8-bit values (S and R)
21
+ # which represent a normal in spherical coordinates.
22
+ # S = polar angle. 0-255 maps to 0-89 degrees.
23
+ # R = azimuthal angle. 0-255 maps to 0-359 degrees.
24
+ # Used in DTEX Texconv Tool
25
+ def _decode_bumpmap_sr_image(self, image_data: bytes, img_width: int, img_height: int) -> bytes:
26
+ rgba_data = bytearray(img_width * img_height * 4)
27
+
28
+ for i in range(img_width * img_height):
29
+ S = image_data[i * 2]
30
+ R = image_data[i * 2 + 1]
31
+
32
+ polar_angle = S * 89.0 / 255.0
33
+ azimuthal_angle = R * 359.0 / 255.0
34
+
35
+ polar_radians = math.radians(polar_angle)
36
+ azimuthal_radians = math.radians(azimuthal_angle)
37
+
38
+ nx = math.sin(polar_radians) * math.cos(azimuthal_radians)
39
+ ny = math.sin(polar_radians) * math.sin(azimuthal_radians)
40
+ nz = math.cos(polar_radians)
41
+
42
+ r_value = int((nx + 1.0) * 127.5)
43
+ g_value = int((ny + 1.0) * 127.5)
44
+ b_value = int((nz + 1.0) * 127.5)
45
+
46
+ rgba_data[i * 4] = r_value
47
+ rgba_data[i * 4 + 1] = g_value
48
+ rgba_data[i * 4 + 2] = b_value
49
+ rgba_data[i * 4 + 3] = 0xFF
50
+
51
+ return rgba_data
52
+
53
+ def decode_bumpmap_image_main(self, image_data: bytes, img_width: int, img_height: int, image_format: ImageFormats) -> bytes:
54
+
55
+ if image_format == ImageFormats.BUMPMAP_SR:
56
+ return self._decode_bumpmap_sr_image(image_data, img_width, img_height)
57
+ else:
58
+ raise Exception(f"Image format not supported by BUMPMAP decoder! Image_format: {image_format}")
@@ -0,0 +1,100 @@
1
+ """
2
+ Copyright © 2024 Bartłomiej Duda
3
+ License: GPL-3.0 License
4
+ """
5
+
6
+ from reversebox.common.logger import get_logger
7
+ from reversebox.image.common import crop_image, get_storage_wh
8
+ from reversebox.image.image_formats import ImageFormats
9
+ from reversebox.io_files.bytes_handler import BytesHandler
10
+ from reversebox.io_files.bytes_helper_functions import get_uint8, get_uint16
11
+
12
+ logger = get_logger(__name__)
13
+
14
+ # fmt: off
15
+ # mypy: ignore-errors
16
+
17
+
18
+ class N64Decoder:
19
+
20
+ def __init__(self):
21
+ pass
22
+
23
+ def _decode_n64_rgba32_image(self, image_data: bytes, img_width: int, img_height: int, block_width: int, block_height: int) -> bytes:
24
+ _width, _height = get_storage_wh(img_width, img_height, block_width, block_height)
25
+ output_data = bytearray(_width * _height * 4)
26
+ offset = 0
27
+
28
+ for y in range(0, _height, block_height):
29
+ for x in range(0, _width, block_width):
30
+ for y2 in range(block_height):
31
+ for x2 in range(block_width):
32
+ idx = (((y + y2) * _width) + (x + x2)) * 4
33
+ output_data[idx + 0] = image_data[offset + 1]
34
+ output_data[idx + 1] = image_data[offset + 32]
35
+ output_data[idx + 2] = image_data[offset + 33]
36
+ output_data[idx + 3] = image_data[offset + 0]
37
+ offset += 2
38
+ offset += 32
39
+
40
+ output_data = crop_image(output_data, _width, _height, 32, img_width, img_height)
41
+ return output_data
42
+
43
+ def _decode_n64_cmpr_image(self, image_data: bytes, img_width: int, img_height: int, block_width: int, block_height: int) -> bytes:
44
+ _width, _height = get_storage_wh(img_width, img_height, block_width, block_height)
45
+ output_data = bytearray(_width * _height * 4)
46
+ image_data_handler = BytesHandler(image_data)
47
+
48
+ def _decode_rgb565_pixel(pixel_int: int) -> bytes:
49
+ p = bytearray(4)
50
+ p[0] = ((pixel_int >> 11) & 0x1F) * 0xFF // 0x1F
51
+ p[1] = ((pixel_int >> 5) & 0x3F) * 0xFF // 0x3F
52
+ p[2] = ((pixel_int >> 0) & 0x1F) * 0xFF // 0x1F
53
+ p[3] = 0xFF
54
+ return p
55
+
56
+ current_offset: int = 0
57
+ for y in range(0, _height, block_height):
58
+ for x in range(0, _width, block_width):
59
+ for y2 in range(0, block_height, 4):
60
+ for x2 in range(0, block_width, 4):
61
+
62
+ c0 = get_uint16(image_data_handler.get_bytes(current_offset, 2), ">")
63
+ current_offset += 2
64
+ c1 = get_uint16(image_data_handler.get_bytes(current_offset, 2), ">")
65
+ current_offset += 2
66
+
67
+ c = [
68
+ _decode_rgb565_pixel(c0),
69
+ _decode_rgb565_pixel(c1),
70
+ bytearray(4),
71
+ bytearray(4)
72
+ ]
73
+
74
+ if c0 > c1:
75
+ for i in range(4):
76
+ c[2][i] = int((2 * c[0][i] + c[1][i]) / 3)
77
+ c[3][i] = int((2 * c[1][i] + c[0][i]) / 3)
78
+ else:
79
+ for i in range(4):
80
+ c[2][i] = int((c[0][i] + c[1][i]) * .5)
81
+ c[3][i] = 0
82
+
83
+ for y3 in range(4):
84
+ b = get_uint8(image_data_handler.get_bytes(current_offset, 1), ">")
85
+ current_offset += 1
86
+ for x3 in range(4):
87
+ idx = (((y + y2 + y3) * _width) + (x + x2 + x3)) * 4
88
+ output_data[idx: idx + 4] = c[(b >> (6 - (x3 * 2))) & 0x3]
89
+
90
+ output_data = crop_image(output_data, _width, _height, 32, img_width, img_height)
91
+ return output_data
92
+
93
+ def decode_n64_image_main(self, image_data: bytes, img_width: int, img_height: int, image_format: ImageFormats) -> bytes:
94
+
95
+ if image_format == ImageFormats.N64_RGBA32:
96
+ return self._decode_n64_rgba32_image(image_data, img_width, img_height, 4, 4)
97
+ elif image_format == ImageFormats.N64_CMPR:
98
+ return self._decode_n64_cmpr_image(image_data, img_width, img_height, 8, 8)
99
+ else:
100
+ raise Exception(f"Image format not supported by N64 decoder! Image_format: {image_format}")
@@ -0,0 +1,519 @@
1
+ """
2
+ Copyright © 2024 Bartłomiej Duda
3
+ License: GPL-3.0 License
4
+ """
5
+
6
+
7
+ from reversebox.common.logger import get_logger
8
+ from reversebox.image.image_formats import ImageFormats
9
+
10
+ logger = get_logger(__name__)
11
+
12
+ # fmt: off
13
+
14
+
15
+ class YUVDecoder:
16
+
17
+ def __init__(self):
18
+ pass
19
+
20
+ def _check_if_yuv_image_dimensions_are_correct(self, img_width: int, img_height: int) -> bool:
21
+ MIN_IMAGE_WIDTH = 4
22
+ MIN_IMAGE_HEIGHT = 4
23
+
24
+ if img_width < MIN_IMAGE_WIDTH or img_height < MIN_IMAGE_HEIGHT:
25
+ raise Exception("YUV image to small to convert!")
26
+
27
+ return True
28
+
29
+ def _limit_rgb_value(self, f: float) -> int:
30
+ i: int = int(f + 0.5)
31
+ if i < 0:
32
+ i = 0
33
+ if i > 255:
34
+ i = 255
35
+ return i
36
+
37
+ def _yuv_to_rgb(self, Y, U, V) -> tuple:
38
+ R = Y + 1.140 * (V - 128)
39
+ G = Y - 0.395 * (U - 128) - 0.581 * (V - 128)
40
+ B = Y + 2.032 * (U - 128)
41
+
42
+ R = self._limit_rgb_value(R)
43
+ G = self._limit_rgb_value(G)
44
+ B = self._limit_rgb_value(B)
45
+
46
+ return R, G, B
47
+
48
+ def _decode_yuy2_pixel(self, Y: float, U: float, V: float) -> bytes:
49
+ p = bytearray(4)
50
+
51
+ C: float = Y - 16.0
52
+ D: float = U - 128.0
53
+ E: float = V - 128.0
54
+
55
+ R: float = 1.164383 * C + 1.596027 * E
56
+ G: float = 1.164383 * C - (0.391762 * D) - (0.812968 * E)
57
+ B: float = 1.164383 * C + 2.017232 * D
58
+
59
+ p[0] = self._limit_rgb_value(R)
60
+ p[1] = self._limit_rgb_value(G)
61
+ p[2] = self._limit_rgb_value(B)
62
+ p[3] = 0xFF
63
+ return p
64
+
65
+ def _decode_yuv422_yuy2_image(self, image_data: bytes, img_width: int, img_height: int) -> bytes:
66
+ is_width_odd: bool = True if (img_width & 1) else False
67
+ current_yuv_offset: int = 0
68
+ current_pixel_number: int = 0
69
+ output_texture_data = bytearray(img_width * img_height * 4)
70
+
71
+ for y in range(img_height):
72
+ for x in range(0, img_width, 2):
73
+
74
+ Y0: float = float(image_data[current_yuv_offset])
75
+ U: float = float(image_data[current_yuv_offset + 1])
76
+ Y1: float = float(image_data[current_yuv_offset + 2])
77
+ V: float = float(image_data[current_yuv_offset + 3])
78
+
79
+ pixel1 = self._decode_yuy2_pixel(Y0, U, V)
80
+ pixel2 = self._decode_yuy2_pixel(Y1, U, V)
81
+ output_texture_data[current_pixel_number * 4:(current_pixel_number + 1) * 4] = pixel1
82
+ output_texture_data[(current_pixel_number + 1) * 4:(current_pixel_number + 2) * 4] = pixel2
83
+
84
+ if is_width_odd and x == img_width - 1:
85
+ current_yuv_offset += 4
86
+ current_pixel_number += 1
87
+ else:
88
+ current_yuv_offset += 4
89
+ current_pixel_number += 2
90
+
91
+ return output_texture_data
92
+
93
+ def _decode_yuv420_nv12_image(self, image_data: bytes, img_width: int, img_height: int) -> bytes:
94
+ output_texture_data = bytearray(img_width * img_height * 4)
95
+
96
+ p: int = img_height
97
+ for i in range(0, img_height, 2):
98
+ for j in range(0, img_width, 2):
99
+ Y00 = float(image_data[i * img_width + j])
100
+ Y01 = float(image_data[i * img_width + j + 1])
101
+ Y10 = float(image_data[(i + 1) * img_width + j])
102
+ Y11 = float(image_data[(i + 1) * img_width + j + 1])
103
+ U = float(image_data[p * img_width + j])
104
+ V = float(image_data[p * img_width + j + 1])
105
+
106
+ R = Y00 + 1.140 * (V - 128.0)
107
+ G = Y00 - 0.395 * (U - 128.0) - 0.581 * (V - 128.0)
108
+ B = Y00 + 2.032 * (U - 128.0)
109
+ output_texture_data[i * img_width * 4 + j * 4] = self._limit_rgb_value(R)
110
+ output_texture_data[i * img_width * 4 + j * 4 + 1] = self._limit_rgb_value(G)
111
+ output_texture_data[i * img_width * 4 + j * 4 + 2] = self._limit_rgb_value(B)
112
+ output_texture_data[i * img_width * 4 + j * 4 + 3] = 0xFF
113
+
114
+ R = Y01 + 1.140 * (V - 128.0)
115
+ G = Y01 - 0.395 * (U - 128.0) - 0.581 * (V - 128.0)
116
+ B = Y01 + 2.032 * (U - 128.0)
117
+ output_texture_data[i * img_width * 4 + j * 4 + 4] = self._limit_rgb_value(R)
118
+ output_texture_data[i * img_width * 4 + j * 4 + 5] = self._limit_rgb_value(G)
119
+ output_texture_data[i * img_width * 4 + j * 4 + 6] = self._limit_rgb_value(B)
120
+ output_texture_data[i * img_width * 4 + j * 4 + 7] = 0xFF
121
+
122
+ R = Y10 + 1.140 * (V - 128.0)
123
+ G = Y10 - 0.395 * (U - 128.0) - 0.581 * (V - 128.0)
124
+ B = Y10 + 2.032 * (U - 128.0)
125
+ output_texture_data[(i + 1) * img_width * 4 + j * 4] = self._limit_rgb_value(R)
126
+ output_texture_data[(i + 1) * img_width * 4 + j * 4 + 1] = self._limit_rgb_value(G)
127
+ output_texture_data[(i + 1) * img_width * 4 + j * 4 + 2] = self._limit_rgb_value(B)
128
+ output_texture_data[(i + 1) * img_width * 4 + j * 4 + 3] = 0xFF
129
+
130
+ R = Y11 + 1.140 * (V - 128.0)
131
+ G = Y11 - 0.395 * (U - 128.0) - 0.581 * (V - 128.0)
132
+ B = Y11 + 2.032 * (U - 128.0)
133
+ output_texture_data[(i + 1) * img_width * 4 + j * 4 + 4] = self._limit_rgb_value(R)
134
+ output_texture_data[(i + 1) * img_width * 4 + j * 4 + 5] = self._limit_rgb_value(G)
135
+ output_texture_data[(i + 1) * img_width * 4 + j * 4 + 6] = self._limit_rgb_value(B)
136
+ output_texture_data[(i + 1) * img_width * 4 + j * 4 + 7] = 0xFF
137
+
138
+ p += 1
139
+
140
+ return output_texture_data
141
+
142
+ def _decode_yuv420_nv21_image(self, image_data: bytes, img_width: int, img_height: int) -> bytes:
143
+ output_texture_data = bytearray(img_width * img_height * 4)
144
+
145
+ p: int = img_height
146
+ for i in range(0, img_height, 2):
147
+ for j in range(0, img_width, 2):
148
+ Y00 = float(image_data[i * img_width + j])
149
+ Y01 = float(image_data[i * img_width + j + 1])
150
+ Y10 = float(image_data[(i + 1) * img_width + j])
151
+ Y11 = float(image_data[(i + 1) * img_width + j + 1])
152
+ U = float(image_data[p * img_width + j + 1])
153
+ V = float(image_data[p * img_width + j])
154
+
155
+ R = Y00 + 1.140 * (V - 128.0)
156
+ G = Y00 - 0.395 * (U - 128.0) - 0.581 * (V - 128.0)
157
+ B = Y00 + 2.032 * (U - 128.0)
158
+ output_texture_data[i * img_width * 4 + j * 4] = self._limit_rgb_value(R)
159
+ output_texture_data[i * img_width * 4 + j * 4 + 1] = self._limit_rgb_value(G)
160
+ output_texture_data[i * img_width * 4 + j * 4 + 2] = self._limit_rgb_value(B)
161
+ output_texture_data[i * img_width * 4 + j * 4 + 3] = 0xFF
162
+
163
+ R = Y01 + 1.140 * (V - 128.0)
164
+ G = Y01 - 0.395 * (U - 128.0) - 0.581 * (V - 128.0)
165
+ B = Y01 + 2.032 * (U - 128.0)
166
+ output_texture_data[i * img_width * 4 + j * 4 + 4] = self._limit_rgb_value(R)
167
+ output_texture_data[i * img_width * 4 + j * 4 + 5] = self._limit_rgb_value(G)
168
+ output_texture_data[i * img_width * 4 + j * 4 + 6] = self._limit_rgb_value(B)
169
+ output_texture_data[i * img_width * 4 + j * 4 + 7] = 0xFF
170
+
171
+ R = Y10 + 1.140 * (V - 128.0)
172
+ G = Y10 - 0.395 * (U - 128.0) - 0.581 * (V - 128.0)
173
+ B = Y10 + 2.032 * (U - 128.0)
174
+ output_texture_data[(i + 1) * img_width * 4 + j * 4] = self._limit_rgb_value(R)
175
+ output_texture_data[(i + 1) * img_width * 4 + j * 4 + 1] = self._limit_rgb_value(G)
176
+ output_texture_data[(i + 1) * img_width * 4 + j * 4 + 2] = self._limit_rgb_value(B)
177
+ output_texture_data[(i + 1) * img_width * 4 + j * 4 + 3] = 0xFF
178
+
179
+ R = Y11 + 1.140 * (V - 128.0)
180
+ G = Y11 - 0.395 * (U - 128.0) - 0.581 * (V - 128.0)
181
+ B = Y11 + 2.032 * (U - 128.0)
182
+ output_texture_data[(i + 1) * img_width * 4 + j * 4 + 4] = self._limit_rgb_value(R)
183
+ output_texture_data[(i + 1) * img_width * 4 + j * 4 + 5] = self._limit_rgb_value(G)
184
+ output_texture_data[(i + 1) * img_width * 4 + j * 4 + 6] = self._limit_rgb_value(B)
185
+ output_texture_data[(i + 1) * img_width * 4 + j * 4 + 7] = 0xFF
186
+
187
+ p += 1
188
+
189
+ return output_texture_data
190
+
191
+ def _decode_yuv422_uyvy_image(self, image_data: bytes, img_width: int, img_height: int) -> bytes:
192
+ output_texture_data = bytearray(img_width * img_height * 4)
193
+
194
+ j: int = 0
195
+ for i in range(0, len(image_data), 4):
196
+ U = float(image_data[i])
197
+ Y0 = float(image_data[i + 1])
198
+ V = float(image_data[i + 2])
199
+ Y1 = float(image_data[i + 3])
200
+
201
+ R0 = Y0 + 1.140 * (V - 128.0)
202
+ G0 = Y0 - 0.395 * (U - 128.0) - 0.581 * (V - 128.0)
203
+ B0 = Y0 + 2.032 * (U - 128.0)
204
+
205
+ R1 = Y1 + 1.140 * (V - 128.0)
206
+ G1 = Y1 - 0.395 * (U - 128.0) - 0.581 * (V - 128.0)
207
+ B1 = Y1 + 2.032 * (U - 128.0)
208
+
209
+ output_texture_data[j] = self._limit_rgb_value(R0)
210
+ output_texture_data[j + 1] = self._limit_rgb_value(G0)
211
+ output_texture_data[j + 2] = self._limit_rgb_value(B0)
212
+ output_texture_data[j + 3] = 0xFF
213
+
214
+ output_texture_data[j + 4] = self._limit_rgb_value(R1)
215
+ output_texture_data[j + 5] = self._limit_rgb_value(G1)
216
+ output_texture_data[j + 6] = self._limit_rgb_value(B1)
217
+ output_texture_data[j + 7] = 0xFF
218
+
219
+ j += 8
220
+
221
+ return output_texture_data
222
+
223
+ def _decode_yuv444p_image(self, image_data: bytes, img_width: int, img_height: int) -> bytes:
224
+ output_texture_data = bytearray(img_width * img_height * 4)
225
+
226
+ num_pixels: int = img_width * img_height
227
+ y_plane_start: int = 0
228
+ u_plane_start: int = num_pixels
229
+ v_plane_start: int = num_pixels * 2
230
+
231
+ for i in range(img_height):
232
+ for j in range(img_width):
233
+ y_index = y_plane_start + i * img_width + j
234
+ u_index = u_plane_start + i * img_width + j
235
+ v_index = v_plane_start + i * img_width + j
236
+
237
+ Y = image_data[y_index]
238
+ U = image_data[u_index]
239
+ V = image_data[v_index]
240
+
241
+ R = Y + 1.140 * (V - 128)
242
+ G = Y - 0.395 * (U - 128) - 0.581 * (V - 128)
243
+ B = Y + 2.032 * (U - 128)
244
+
245
+ R = self._limit_rgb_value(R)
246
+ G = self._limit_rgb_value(G)
247
+ B = self._limit_rgb_value(B)
248
+
249
+ rgba_index = (i * img_width + j) * 4
250
+ output_texture_data[rgba_index] = R
251
+ output_texture_data[rgba_index + 1] = G
252
+ output_texture_data[rgba_index + 2] = B
253
+ output_texture_data[rgba_index + 3] = 0xFF
254
+
255
+ return output_texture_data
256
+
257
+ def _decode_yuv410p_image(self, image_data: bytes, img_width: int, img_height: int) -> bytes:
258
+ output_texture_data = bytearray(img_width * img_height * 4)
259
+ num_pixels: int = img_width * img_height
260
+ uv_width: int = img_width // 4
261
+ uv_height: int = img_height // 4
262
+ uv_size: int = uv_width * uv_height
263
+
264
+ y_plane_start: int = 0
265
+ u_plane_start: int = num_pixels
266
+ v_plane_start: int = num_pixels + uv_size
267
+
268
+ for i in range(img_height):
269
+ for j in range(img_width):
270
+ y_index = y_plane_start + i * img_width + j
271
+ u_index = u_plane_start + (i // 4) * uv_width + (j // 4)
272
+ v_index = v_plane_start + (i // 4) * uv_width + (j // 4)
273
+
274
+ Y = image_data[y_index]
275
+ U = image_data[u_index]
276
+ V = image_data[v_index]
277
+
278
+ R = Y + 1.140 * (V - 128)
279
+ G = Y - 0.395 * (U - 128) - 0.581 * (V - 128)
280
+ B = Y + 2.032 * (U - 128)
281
+
282
+ R = self._limit_rgb_value(R)
283
+ G = self._limit_rgb_value(G)
284
+ B = self._limit_rgb_value(B)
285
+
286
+ rgba_index = (i * img_width + j) * 4
287
+ output_texture_data[rgba_index] = R
288
+ output_texture_data[rgba_index + 1] = G
289
+ output_texture_data[rgba_index + 2] = B
290
+ output_texture_data[rgba_index + 3] = 0xFF
291
+
292
+ return output_texture_data
293
+
294
+ def _decode_yuv420p_image(self, image_data: bytes, img_width: int, img_height: int) -> bytes:
295
+ output_texture_data = bytearray(img_width * img_height * 4)
296
+ num_pixels: int = img_width * img_height
297
+ uv_width: int = img_width // 2
298
+ uv_height: int = img_height // 2
299
+ uv_size: int = uv_width * uv_height
300
+
301
+ y_plane_start: int = 0
302
+ u_plane_start: int = num_pixels
303
+ v_plane_start: int = num_pixels + uv_size
304
+
305
+ for i in range(img_height):
306
+ for j in range(img_width):
307
+ y_index = y_plane_start + i * img_width + j
308
+ u_index = u_plane_start + (i // 2) * uv_width + (j // 2)
309
+ v_index = v_plane_start + (i // 2) * uv_width + (j // 2)
310
+
311
+ Y = image_data[y_index]
312
+ U = image_data[u_index]
313
+ V = image_data[v_index]
314
+
315
+ R = Y + 1.140 * (V - 128)
316
+ G = Y - 0.395 * (U - 128) - 0.581 * (V - 128)
317
+ B = Y + 2.032 * (U - 128)
318
+
319
+ R = self._limit_rgb_value(R)
320
+ G = self._limit_rgb_value(G)
321
+ B = self._limit_rgb_value(B)
322
+
323
+ rgba_index = (i * img_width + j) * 4
324
+ output_texture_data[rgba_index] = R
325
+ output_texture_data[rgba_index + 1] = G
326
+ output_texture_data[rgba_index + 2] = B
327
+ output_texture_data[rgba_index + 3] = 0xFF
328
+
329
+ return output_texture_data
330
+
331
+ def _decode_yuv422p_image(self, image_data: bytes, img_width: int, img_height: int) -> bytes:
332
+ output_texture_data = bytearray(img_width * img_height * 4)
333
+ num_pixels: int = img_width * img_height
334
+ uv_width: int = img_width // 2
335
+ uv_size: int = uv_width * img_height
336
+
337
+ y_plane_start: int = 0
338
+ u_plane_start: int = num_pixels
339
+ v_plane_start: int = num_pixels + uv_size
340
+
341
+ for i in range(img_height):
342
+ for j in range(img_width):
343
+ y_index = y_plane_start + i * img_width + j
344
+ u_index = u_plane_start + i * uv_width + (j // 2)
345
+ v_index = v_plane_start + i * uv_width + (j // 2)
346
+
347
+ Y = image_data[y_index]
348
+ U = image_data[u_index]
349
+ V = image_data[v_index]
350
+
351
+ R = Y + 1.140 * (V - 128)
352
+ G = Y - 0.395 * (U - 128) - 0.581 * (V - 128)
353
+ B = Y + 2.032 * (U - 128)
354
+
355
+ R = self._limit_rgb_value(R)
356
+ G = self._limit_rgb_value(G)
357
+ B = self._limit_rgb_value(B)
358
+
359
+ rgba_index = (i * img_width + j) * 4
360
+ output_texture_data[rgba_index] = R
361
+ output_texture_data[rgba_index + 1] = G
362
+ output_texture_data[rgba_index + 2] = B
363
+ output_texture_data[rgba_index + 3] = 0xFF
364
+
365
+ return output_texture_data
366
+
367
+ def _decode_yuv411p_image(self, image_data: bytes, img_width: int, img_height: int) -> bytes:
368
+ output_texture_data = bytearray(img_width * img_height * 4)
369
+ num_pixels: int = img_width * img_height
370
+ uv_width: int = img_width // 4
371
+ uv_size: int = uv_width * img_height
372
+
373
+ y_plane_start: int = 0
374
+ u_plane_start: int = num_pixels
375
+ v_plane_start: int = num_pixels + uv_size
376
+
377
+ for i in range(img_height):
378
+ for j in range(img_width):
379
+ y_index = y_plane_start + i * img_width + j
380
+ u_index = u_plane_start + i * uv_width + (j // 4)
381
+ v_index = v_plane_start + i * uv_width + (j // 4)
382
+
383
+ Y = image_data[y_index]
384
+ U = image_data[u_index]
385
+ V = image_data[v_index]
386
+
387
+ R = Y + 1.140 * (V - 128)
388
+ G = Y - 0.395 * (U - 128) - 0.581 * (V - 128)
389
+ B = Y + 2.032 * (U - 128)
390
+
391
+ R = self._limit_rgb_value(R)
392
+ G = self._limit_rgb_value(G)
393
+ B = self._limit_rgb_value(B)
394
+
395
+ rgba_index = (i * img_width + j) * 4
396
+ output_texture_data[rgba_index] = R
397
+ output_texture_data[rgba_index + 1] = G
398
+ output_texture_data[rgba_index + 2] = B
399
+ output_texture_data[rgba_index + 3] = 0xFF
400
+
401
+ return output_texture_data
402
+
403
+ def _decode_yuv411_uyyvyy411_image(self, image_data: bytes, img_width: int, img_height: int) -> bytes:
404
+ output_texture_data = bytearray(img_width * img_height * 4)
405
+
406
+ def set_pixel(out_rgba_array, row, col, R, G, B):
407
+ out_index = (row * img_width + col) * 4
408
+ out_rgba_array[out_index] = R
409
+ out_rgba_array[out_index + 1] = G
410
+ out_rgba_array[out_index + 2] = B
411
+ out_rgba_array[out_index + 3] = 0xFF
412
+
413
+ for i in range(img_height):
414
+ for j in range(0, img_width, 4):
415
+ index: int = int(i * img_width * 1.5 + j * 1.5)
416
+
417
+ U = image_data[index]
418
+ Y0 = image_data[index + 1]
419
+ Y1 = image_data[index + 2]
420
+ V = image_data[index + 3]
421
+ Y2 = image_data[index + 4]
422
+ Y3 = image_data[index + 5]
423
+
424
+ R0, G0, B0 = self._yuv_to_rgb(Y0, U, V)
425
+ R1, G1, B1 = self._yuv_to_rgb(Y1, U, V)
426
+ R2, G2, B2 = self._yuv_to_rgb(Y2, U, V)
427
+ R3, G3, B3 = self._yuv_to_rgb(Y3, U, V)
428
+
429
+ set_pixel(output_texture_data, i, j, R0, G0, B0)
430
+ set_pixel(output_texture_data, i, j + 1, R1, G1, B1)
431
+ set_pixel(output_texture_data, i, j + 2, R2, G2, B2)
432
+ set_pixel(output_texture_data, i, j + 3, R3, G3, B3)
433
+
434
+ return output_texture_data
435
+
436
+ def _decode_yuv440p_image(self, image_data: bytes, img_width: int, img_height: int) -> bytes:
437
+ output_texture_data = bytearray(img_width * img_height * 4)
438
+ y_plane_size: int = img_width * img_height
439
+ uv_plane_size: int = img_width * (img_height // 2)
440
+
441
+ def set_pixel(out_rgba_array, row, col, R, G, B):
442
+ out_index = (row * img_width + col) * 4
443
+ out_rgba_array[out_index] = R
444
+ out_rgba_array[out_index + 1] = G
445
+ out_rgba_array[out_index + 2] = B
446
+ out_rgba_array[out_index + 3] = 0xFF
447
+
448
+ y_plane = image_data[0:y_plane_size]
449
+ u_plane = image_data[y_plane_size:y_plane_size + uv_plane_size]
450
+ v_plane = image_data[y_plane_size + uv_plane_size:y_plane_size + 2 * uv_plane_size]
451
+
452
+ for i in range(img_height):
453
+ for j in range(img_width):
454
+ Y = y_plane[i * img_width + j]
455
+ U = u_plane[(i // 2) * img_width + j]
456
+ V = v_plane[(i // 2) * img_width + j]
457
+
458
+ R, G, B = self._yuv_to_rgb(Y, U, V)
459
+ set_pixel(output_texture_data, i, j, R, G, B)
460
+
461
+ return output_texture_data
462
+
463
+ def _decode_yuva420p_image(self, image_data: bytes, img_width: int, img_height: int) -> bytes:
464
+ output_texture_data = bytearray(img_width * img_height * 4)
465
+ y_plane_size: int = img_width * img_height
466
+ uv_plane_size: int = (img_width // 2) * (img_height // 2)
467
+
468
+ def set_pixel(out_rgba_array, row, col, R, G, B, A):
469
+ out_index = (row * img_width + col) * 4
470
+ out_rgba_array[out_index] = R
471
+ out_rgba_array[out_index + 1] = G
472
+ out_rgba_array[out_index + 2] = B
473
+ out_rgba_array[out_index + 3] = A
474
+
475
+ y_plane = image_data[0:y_plane_size]
476
+ u_plane = image_data[y_plane_size:y_plane_size + uv_plane_size]
477
+ v_plane = image_data[y_plane_size + uv_plane_size:y_plane_size + 2 * uv_plane_size]
478
+ a_plane = image_data[y_plane_size + 2 * uv_plane_size:]
479
+
480
+ for i in range(img_height):
481
+ for j in range(img_width):
482
+ Y = y_plane[i * img_width + j]
483
+ U = u_plane[(i // 2) * (img_width // 2) + (j // 2)]
484
+ V = v_plane[(i // 2) * (img_width // 2) + (j // 2)]
485
+ A = a_plane[i * img_width + j]
486
+ R, G, B = self._yuv_to_rgb(Y, U, V)
487
+ set_pixel(output_texture_data, i, j, R, G, B, A)
488
+
489
+ return output_texture_data
490
+
491
+ def decode_yuv_image_main(self, image_data: bytes, img_width: int, img_height: int, image_format: ImageFormats) -> bytes:
492
+ self._check_if_yuv_image_dimensions_are_correct(img_width, img_height)
493
+
494
+ if image_format == ImageFormats.YUV422_YUY2:
495
+ return self._decode_yuv422_yuy2_image(image_data, img_width, img_height)
496
+ elif image_format == ImageFormats.YUV420_NV12:
497
+ return self._decode_yuv420_nv12_image(image_data, img_width, img_height)
498
+ elif image_format == ImageFormats.YUV420_NV21:
499
+ return self._decode_yuv420_nv21_image(image_data, img_width, img_height)
500
+ elif image_format == ImageFormats.YUV422_UYVY:
501
+ return self._decode_yuv422_uyvy_image(image_data, img_width, img_height)
502
+ elif image_format == ImageFormats.YUV444P:
503
+ return self._decode_yuv444p_image(image_data, img_width, img_height)
504
+ elif image_format == ImageFormats.YUV410P:
505
+ return self._decode_yuv410p_image(image_data, img_width, img_height)
506
+ elif image_format == ImageFormats.YUV420P:
507
+ return self._decode_yuv420p_image(image_data, img_width, img_height)
508
+ elif image_format == ImageFormats.YUV422P:
509
+ return self._decode_yuv422p_image(image_data, img_width, img_height)
510
+ elif image_format == ImageFormats.YUV411P:
511
+ return self._decode_yuv411p_image(image_data, img_width, img_height)
512
+ elif image_format == ImageFormats.YUV411_UYYVYY411:
513
+ return self._decode_yuv411_uyyvyy411_image(image_data, img_width, img_height)
514
+ elif image_format == ImageFormats.YUV440P:
515
+ return self._decode_yuv440p_image(image_data, img_width, img_height)
516
+ elif image_format == ImageFormats.YUVA420P:
517
+ return self._decode_yuva420p_image(image_data, img_width, img_height)
518
+ else:
519
+ raise Exception(f"Image format not supported by yuv decoder! Image_format: {image_format}")
@@ -130,7 +130,7 @@ def _convert_ps2_16bit(image_data: bytes, width: int, height: int, swizzle_flag:
130
130
  return converted_data
131
131
 
132
132
 
133
- # special 4-bit swizzle/unswizzle function used in SSH files from EA PS2 games
133
+ # special "type 3" 4-bit swizzle/unswizzle function used in SSH files from EA PS2 games
134
134
  def _convert_ps2_ea_4bit(image_data: bytes, img_width: int, img_height: int, bpp: int, swizzle_flag: bool) -> bytes:
135
135
  if bpp != 4:
136
136
  raise Exception(f"Not supported bpp={bpp} for EA swizzle!")
@@ -140,11 +140,11 @@ def _convert_ps2_ea_4bit(image_data: bytes, img_width: int, img_height: int, bpp
140
140
 
141
141
  try:
142
142
  ea_swizzle_dll_path: str = get_dll_path("ea_swizzle.dll")
143
- refpack_dll_file = ctypes.CDLL(ea_swizzle_dll_path)
143
+ ea_swizzle_dll_file = ctypes.CDLL(ea_swizzle_dll_path)
144
144
  if not swizzle_flag:
145
- refpack_dll_file.unswizzle4(image_data, byref(converted_data_buffer), img_width, img_height)
145
+ ea_swizzle_dll_file.unswizzle4(image_data, byref(converted_data_buffer), img_width, img_height)
146
146
  else:
147
- refpack_dll_file.swizzle4(image_data, byref(converted_data_buffer), img_width, img_height)
147
+ ea_swizzle_dll_file.swizzle4(image_data, byref(converted_data_buffer), img_width, img_height)
148
148
  except Exception as error:
149
149
  raise Exception(f"Error while unswizzling data! Error: {error}")
150
150
 
File without changes
@@ -7,7 +7,7 @@ import os
7
7
 
8
8
  import setuptools
9
9
 
10
- VERSION_NUM = "0.18.2"
10
+ VERSION_NUM = "0.18.4"
11
11
 
12
12
 
13
13
  def get_long_description() -> str:
@@ -1,55 +0,0 @@
1
- """
2
- Copyright © 2024 Bartłomiej Duda
3
- License: GPL-3.0 License
4
- """
5
- import ctypes
6
- from ctypes import byref, c_char
7
-
8
- from reversebox.common.common import get_dll_path
9
-
10
-
11
- class RefpackHandler:
12
- def compress_data(self, input_data: bytes) -> bytes:
13
- return input_data # TODO - fix this
14
-
15
- def _get_output_buffer_size(self, compressed_data: bytes) -> int:
16
- current_input_offset: int = 0
17
- compression_type = compressed_data[current_input_offset]
18
- current_input_offset += 1
19
- compression_type = (compression_type << 8) + compressed_data[
20
- current_input_offset
21
- ]
22
- current_input_offset += 1
23
-
24
- if compression_type & 0x100:
25
- current_input_offset += 3 # skip uncompressed_size
26
-
27
- uncompressed_size: int = compressed_data[current_input_offset]
28
- current_input_offset += 1
29
- uncompressed_size = (uncompressed_size << 8) + compressed_data[
30
- current_input_offset
31
- ]
32
- current_input_offset += 1
33
- uncompressed_size = (uncompressed_size << 8) + compressed_data[
34
- current_input_offset
35
- ]
36
- current_input_offset += 1
37
- return uncompressed_size
38
-
39
- def decompress_data(self, compressed_data: bytes) -> bytes:
40
- if len(compressed_data) < 5:
41
- raise Exception("Compressed data too short!")
42
- if compressed_data[:2] != b"\x10\xFB":
43
- raise Exception("Wrong refpack compression header!")
44
- uncompressed_data_buffer = (
45
- c_char * self._get_output_buffer_size(compressed_data)
46
- )()
47
- try:
48
- refpack_dll_path: str = get_dll_path("refpack.dll")
49
- refpack_dll_file = ctypes.CDLL(refpack_dll_path)
50
- uncompressed_data_size = refpack_dll_file.unrefpack(
51
- compressed_data, byref(uncompressed_data_buffer), 1
52
- )
53
- except Exception as error:
54
- raise Exception(f"Error while decompressing refpack data! Error: {error}")
55
- return bytes(bytearray(uncompressed_data_buffer)[:uncompressed_data_size])
File without changes
File without changes
File without changes