From ca1180373a56f674c2608dd62a7de909f555f1d0 Mon Sep 17 00:00:00 2001 From: com55 <33087300+com55@users.noreply.github.com> Date: Thu, 22 Oct 2026 00:35:02 +0700 Subject: [PATCH 1/2] fix(Texture2DConverter): use a valid Pillow raw mode for R16 Pillow has no "R;16" raw mode for RGB images, so decoding any R16 texture raised "unknown raw mode for given image mode". Use "R;16L" (little-endian, high byte kept), consistent with R8 decoding into the red channel. --- UnityPy/export/Texture2DConverter.py | 2 +- tests/test_texture2d_r16.py | 20 ++++++++++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) create mode 100644 tests/test_texture2d_r16.py diff --git a/UnityPy/export/Texture2DConverter.py b/UnityPy/export/Texture2DConverter.py index a46eed5f..90d82c70 100644 --- a/UnityPy/export/Texture2DConverter.py +++ b/UnityPy/export/Texture2DConverter.py @@ -506,7 +506,7 @@ def rgb9e5float(image_data: bytes, width: int, height: int) -> Image.Image: TF.RGB565: (pillow, ("RGB", "raw", "BGR;16")), TF.BGR24: (pillow, ("RGB", "raw", "BGR")), TF.R8: (pillow, ("RGB", "raw", "R")), - TF.R16: (pillow, ("RGB", "raw", "R;16")), + TF.R16: (pillow, ("RGB", "raw", "R;16L")), TF.RG16: (rg, ("RGB", "raw", "RG")), TF.DXT1: (pillow, ("RGBA", "bcn", 1)), TF.DXT3: (pillow, ("RGBA", "bcn", 2)), diff --git a/tests/test_texture2d_r16.py b/tests/test_texture2d_r16.py new file mode 100644 index 00000000..bb42e4c5 --- /dev/null +++ b/tests/test_texture2d_r16.py @@ -0,0 +1,20 @@ +import struct + +from UnityPy.enums import BuildTarget +from UnityPy.enums import TextureFormat as TF +from UnityPy.export.Texture2DConverter import parse_image_data + +VERSION = (2021, 3, 56, 0) + + +def test_r16_decodes_high_byte_into_red(): + values = [0x0000, 0x1234, 0x7FFF, 0xFFFF] + data = struct.pack("<4H", *values) + + img = parse_image_data(data, 2, 2, TF.R16, VERSION, BuildTarget.StandaloneWindows, flip=False) + + assert img.mode == "RGB" + assert img.size == (2, 2) + pixels = img.tobytes() + assert list(pixels[0::3]) == [v >> 8 for v in values] + assert not any(pixels[1::3]) and not any(pixels[2::3]) From ce1ea995c7b1c0b3842bbb797cca593728fb4f7d Mon Sep 17 00:00:00 2001 From: com55 <33087300+com55@users.noreply.github.com> Date: Fri, 6 Nov 2026 18:51:24 +0700 Subject: [PATCH 2/2] fix(Texture2DConverter): use little-endian raw modes for RGB48/RGBA64 "RGBA;16" is not a valid Pillow raw mode for RGBA images, and "RGB;16" decodes as packed 5-6-5 instead of 16-bit per channel. Use "RGB;16L" and "RGBA;16L", matching the R16 fix. Drop the standalone R16 test per review. --- UnityPy/export/Texture2DConverter.py | 4 ++-- tests/test_texture2d_r16.py | 20 -------------------- 2 files changed, 2 insertions(+), 22 deletions(-) delete mode 100644 tests/test_texture2d_r16.py diff --git a/UnityPy/export/Texture2DConverter.py b/UnityPy/export/Texture2DConverter.py index 90d82c70..b028a1bd 100644 --- a/UnityPy/export/Texture2DConverter.py +++ b/UnityPy/export/Texture2DConverter.py @@ -564,8 +564,8 @@ def rgb9e5float(image_data: bytes, width: int, height: int) -> Image.Image: TF.ASTC_HDR_10x10: (astc, ((10, 10), True)), TF.ASTC_HDR_12x12: (astc, ((12, 12), True)), TF.RG32: (rg, ("RGB", "raw", "RG;16")), - TF.RGB48: (pillow, ("RGB", "raw", "RGB;16")), - TF.RGBA64: (pillow, ("RGBA", "raw", "RGBA;16")), + TF.RGB48: (pillow, ("RGB", "raw", "RGB;16L")), + TF.RGBA64: (pillow, ("RGBA", "raw", "RGBA;16L")), TF.R8_SIGNED: (pillow, ("R", "raw", "R;8s")), TF.RG16_SIGNED: (rg, ("RGB", "raw", "RG;8s")), TF.RGB24_SIGNED: (pillow, ("RGB", "raw", "RGB;8s")), diff --git a/tests/test_texture2d_r16.py b/tests/test_texture2d_r16.py deleted file mode 100644 index bb42e4c5..00000000 --- a/tests/test_texture2d_r16.py +++ /dev/null @@ -1,20 +0,0 @@ -import struct - -from UnityPy.enums import BuildTarget -from UnityPy.enums import TextureFormat as TF -from UnityPy.export.Texture2DConverter import parse_image_data - -VERSION = (2021, 3, 56, 0) - - -def test_r16_decodes_high_byte_into_red(): - values = [0x0000, 0x1234, 0x7FFF, 0xFFFF] - data = struct.pack("<4H", *values) - - img = parse_image_data(data, 2, 2, TF.R16, VERSION, BuildTarget.StandaloneWindows, flip=False) - - assert img.mode == "RGB" - assert img.size == (2, 2) - pixels = img.tobytes() - assert list(pixels[0::3]) == [v >> 8 for v in values] - assert not any(pixels[1::3]) and not any(pixels[2::3])