From a5dde8b1c4abdf134e5e909370caa53bed8de50c Mon Sep 17 00:00:00 2001 From: REDxEYE Date: Thu, 12 Oct 2023 19:09:28 +0300 Subject: [PATCH] Apply suggestion for PR --- Tests/images/{ati1.dds => mode-ati1.dds} | Bin Tests/images/{ati1.png => mode-ati1.png} | Bin Tests/images/{ati2.dds => mode-ati2.dds} | Bin Tests/images/{l.dds => mode-l.dds} | Bin Tests/images/{l.png => mode-l.png} | Bin Tests/images/{la.dds => mode-la.dds} | Bin Tests/images/{la.png => mode-la.png} | Bin Tests/images/{rgb.dds => mode-rgb.dds} | Bin Tests/images/{rgb.png => mode-rgb.png} | Bin Tests/images/{rgba.dds => mode-rgba.dds} | Bin Tests/images/{rgba.png => mode-rgba.png} | Bin Tests/test_file_dds.py | 14 +-- src/PIL/DdsImagePlugin.py | 122 +++++++++++++++++++---- src/PIL/Image.py | 20 ++-- src/PIL/ImageFile.py | 4 +- 15 files changed, 123 insertions(+), 37 deletions(-) rename Tests/images/{ati1.dds => mode-ati1.dds} (100%) rename Tests/images/{ati1.png => mode-ati1.png} (100%) rename Tests/images/{ati2.dds => mode-ati2.dds} (100%) rename Tests/images/{l.dds => mode-l.dds} (100%) rename Tests/images/{l.png => mode-l.png} (100%) rename Tests/images/{la.dds => mode-la.dds} (100%) rename Tests/images/{la.png => mode-la.png} (100%) rename Tests/images/{rgb.dds => mode-rgb.dds} (100%) rename Tests/images/{rgb.png => mode-rgb.png} (100%) rename Tests/images/{rgba.dds => mode-rgba.dds} (100%) rename Tests/images/{rgba.png => mode-rgba.png} (100%) diff --git a/Tests/images/ati1.dds b/Tests/images/mode-ati1.dds similarity index 100% rename from Tests/images/ati1.dds rename to Tests/images/mode-ati1.dds diff --git a/Tests/images/ati1.png b/Tests/images/mode-ati1.png similarity index 100% rename from Tests/images/ati1.png rename to Tests/images/mode-ati1.png diff --git a/Tests/images/ati2.dds b/Tests/images/mode-ati2.dds similarity index 100% rename from Tests/images/ati2.dds rename to Tests/images/mode-ati2.dds diff --git a/Tests/images/l.dds b/Tests/images/mode-l.dds similarity index 100% rename from Tests/images/l.dds rename to Tests/images/mode-l.dds diff --git a/Tests/images/l.png b/Tests/images/mode-l.png similarity index 100% rename from Tests/images/l.png rename to Tests/images/mode-l.png diff --git a/Tests/images/la.dds b/Tests/images/mode-la.dds similarity index 100% rename from Tests/images/la.dds rename to Tests/images/mode-la.dds diff --git a/Tests/images/la.png b/Tests/images/mode-la.png similarity index 100% rename from Tests/images/la.png rename to Tests/images/mode-la.png diff --git a/Tests/images/rgb.dds b/Tests/images/mode-rgb.dds similarity index 100% rename from Tests/images/rgb.dds rename to Tests/images/mode-rgb.dds diff --git a/Tests/images/rgb.png b/Tests/images/mode-rgb.png similarity index 100% rename from Tests/images/rgb.png rename to Tests/images/mode-rgb.png diff --git a/Tests/images/rgba.dds b/Tests/images/mode-rgba.dds similarity index 100% rename from Tests/images/rgba.dds rename to Tests/images/mode-rgba.dds diff --git a/Tests/images/rgba.png b/Tests/images/mode-rgba.png similarity index 100% rename from Tests/images/rgba.png rename to Tests/images/mode-rgba.png diff --git a/Tests/test_file_dds.py b/Tests/test_file_dds.py index 004a2d156..52777bd30 100644 --- a/Tests/test_file_dds.py +++ b/Tests/test_file_dds.py @@ -10,8 +10,8 @@ from .helper import assert_image_equal, assert_image_equal_tofile, hopper TEST_FILE_DXT1 = "Tests/images/dxt1-rgb-4bbp-noalpha_MipMaps-1.dds" TEST_FILE_DXT3 = "Tests/images/dxt3-argb-8bbp-explicitalpha_MipMaps-1.dds" TEST_FILE_DXT5 = "Tests/images/dxt5-argb-8bbp-interpolatedalpha_MipMaps-1.dds" -TEST_FILE_ATI1 = "Tests/images/ati1.dds" -TEST_FILE_ATI2 = "Tests/images/ati2.dds" +TEST_FILE_ATI1 = "Tests/images/mode-ati1.dds" +TEST_FILE_ATI2 = "Tests/images/mode-ati2.dds" TEST_FILE_DX10_BC5_TYPELESS = "Tests/images/bc5_typeless.dds" TEST_FILE_DX10_BC5_UNORM = "Tests/images/bc5_unorm.dds" TEST_FILE_DX10_BC5_SNORM = "Tests/images/bc5_snorm.dds" @@ -314,10 +314,10 @@ def test_save_unsupported_mode(tmp_path): @pytest.mark.parametrize( ("mode", "test_file"), ( - ("L", "Tests/images/l.dds"), - ("LA", "Tests/images/la.dds"), - ("RGB", "Tests/images/rgb.dds"), - ("RGBA", "Tests/images/rgba.dds"), + ("L", "Tests/images/mode-l.dds"), + ("LA", "Tests/images/mode-la.dds"), + ("RGB", "Tests/images/mode-rgb.dds"), + ("RGBA", "Tests/images/mode-rgba.dds"), ), ) def test_open(mode, test_file): @@ -333,7 +333,7 @@ def test_open(mode, test_file): ("LA", "Tests/images/uncompressed_la.png"), ("RGB", "Tests/images/hopper.png"), ("RGBA", "Tests/images/pil123rgba.png"), - ("L", "Tests/images/ati1.dds"), + ("L", "Tests/images/mode-ati1.dds"), ], ) def test_save(mode, test_file, tmp_path): diff --git a/src/PIL/DdsImagePlugin.py b/src/PIL/DdsImagePlugin.py index 8c8662499..3fa656f0d 100644 --- a/src/PIL/DdsImagePlugin.py +++ b/src/PIL/DdsImagePlugin.py @@ -253,6 +253,8 @@ class D3DFMT(IntEnum): DXT4 = i32(b"DXT4") DXT5 = i32(b"DXT5") DX10 = i32(b"DX10") + BC4S = i32(b"BC4S") + BC4U = i32(b"BC4U") BC5S = i32(b"BC5S") BC5U = i32(b"BC5U") ATI1 = i32(b"ATI1") @@ -260,6 +262,81 @@ class D3DFMT(IntEnum): MULTI2_ARGB8 = i32(b"MET1") +# Backward compat layer +DDSD_CAPS = DDSD.CAPS +DDSD_HEIGHT = DDSD.HEIGHT +DDSD_WIDTH = DDSD.WIDTH +DDSD_PITCH = DDSD.PITCH +DDSD_PIXELFORMAT = DDSD.PIXELFORMAT +DDSD_MIPMAPCOUNT = DDSD.MIPMAPCOUNT +DDSD_LINEARSIZE = DDSD.LINEARSIZE +DDSD_DEPTH = DDSD.DEPTH + +DDSCAPS_COMPLEX = DDSCAPS.COMPLEX +DDSCAPS_TEXTURE = DDSCAPS.TEXTURE +DDSCAPS_MIPMAP = DDSCAPS.MIPMAP + +DDSCAPS2_CUBEMAP = DDSCAPS2.CUBEMAP +DDSCAPS2_CUBEMAP_POSITIVEX = DDSCAPS2.CUBEMAP_POSITIVEX +DDSCAPS2_CUBEMAP_NEGATIVEX = DDSCAPS2.CUBEMAP_NEGATIVEX +DDSCAPS2_CUBEMAP_POSITIVEY = DDSCAPS2.CUBEMAP_POSITIVEY +DDSCAPS2_CUBEMAP_NEGATIVEY = DDSCAPS2.CUBEMAP_NEGATIVEY +DDSCAPS2_CUBEMAP_POSITIVEZ = DDSCAPS2.CUBEMAP_POSITIVEZ +DDSCAPS2_CUBEMAP_NEGATIVEZ = DDSCAPS2.CUBEMAP_NEGATIVEZ +DDSCAPS2_VOLUME = DDSCAPS2.VOLUME + +DDPF_ALPHAPIXELS = DDPF.ALPHAPIXELS +DDPF_ALPHA = DDPF.ALPHA +DDPF_FOURCC = DDPF.FOURCC +DDPF_PALETTEINDEXED8 = DDPF.PALETTEINDEXED8 +DDPF_RGB = DDPF.RGB +DDPF_LUMINANCE = DDPF.LUMINANCE + +DDS_FOURCC = DDPF_FOURCC +DDS_RGB = DDPF_RGB +DDS_RGBA = DDPF_RGB | DDPF_ALPHAPIXELS +DDS_LUMINANCE = DDPF_LUMINANCE +DDS_LUMINANCEA = DDPF_LUMINANCE | DDPF_ALPHAPIXELS +DDS_ALPHA = DDPF_ALPHA +DDS_PAL8 = DDPF_PALETTEINDEXED8 + +DDS_HEADER_FLAGS_TEXTURE = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT +DDS_HEADER_FLAGS_MIPMAP = DDSD_MIPMAPCOUNT +DDS_HEADER_FLAGS_VOLUME = DDSD_DEPTH +DDS_HEADER_FLAGS_PITCH = DDSD_PITCH +DDS_HEADER_FLAGS_LINEARSIZE = DDSD_LINEARSIZE + +DDS_HEIGHT = DDSD_HEIGHT +DDS_WIDTH = DDSD_WIDTH + +DDS_SURFACE_FLAGS_TEXTURE = DDSCAPS_TEXTURE +DDS_SURFACE_FLAGS_MIPMAP = DDSCAPS_COMPLEX | DDSCAPS_MIPMAP +DDS_SURFACE_FLAGS_CUBEMAP = DDSCAPS_COMPLEX + +DDS_CUBEMAP_POSITIVEX = DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_POSITIVEX +DDS_CUBEMAP_NEGATIVEX = DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_NEGATIVEX +DDS_CUBEMAP_POSITIVEY = DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_POSITIVEY +DDS_CUBEMAP_NEGATIVEY = DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_NEGATIVEY +DDS_CUBEMAP_POSITIVEZ = DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_POSITIVEZ +DDS_CUBEMAP_NEGATIVEZ = DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_NEGATIVEZ + +DXT1_FOURCC = D3DFMT.DXT1 +DXT3_FOURCC = D3DFMT.DXT3 +DXT5_FOURCC = D3DFMT.DXT5 + +DXGI_FORMAT_R8G8B8A8_TYPELESS = DXGI_FORMAT.R8G8B8A8_TYPELESS +DXGI_FORMAT_R8G8B8A8_UNORM = DXGI_FORMAT.R8G8B8A8_UNORM +DXGI_FORMAT_R8G8B8A8_UNORM_SRGB = DXGI_FORMAT.R8G8B8A8_UNORM_SRGB +DXGI_FORMAT_BC5_TYPELESS = DXGI_FORMAT.BC5_TYPELESS +DXGI_FORMAT_BC5_UNORM = DXGI_FORMAT.BC5_UNORM +DXGI_FORMAT_BC5_SNORM = DXGI_FORMAT.BC5_SNORM +DXGI_FORMAT_BC6H_UF16 = DXGI_FORMAT.BC6H_UF16 +DXGI_FORMAT_BC6H_SF16 = DXGI_FORMAT.BC6H_SF16 +DXGI_FORMAT_BC7_TYPELESS = DXGI_FORMAT.BC7_TYPELESS +DXGI_FORMAT_BC7_UNORM = DXGI_FORMAT.BC7_UNORM +DXGI_FORMAT_BC7_UNORM_SRGB = DXGI_FORMAT.BC7_UNORM_SRGB + + class DdsImageFile(ImageFile.ImageFile): format = "DDS" format_description = "DirectDraw Surface" @@ -311,6 +388,13 @@ class DdsImageFile(ImageFile.ImageFile): else: msg = f"Unsupported bitcount {bitcount} for {pfflags_}" raise OSError(msg) + elif pfflags & DDPF.ALPHA: + if bitcount == 8: + self.mode = "L" + self.tile = [("raw", extents, 0, ("L", 0, 1))] + else: + msg = f"Unsupported bitcount {bitcount} for {pfflags_}" + raise OSError(msg) elif pfflags & DDPF.LUMINANCE: if bitcount == 8: self.mode = "L" @@ -331,68 +415,72 @@ class DdsImageFile(ImageFile.ImageFile): if fourcc == D3DFMT.DXT1: self.mode = "RGBA" self.pixel_format = "DXT1" - tile = Image.Tile("bcn", extents, data_offs, (1, self.pixel_format)) + tile = Image._Tile("bcn", extents, data_offs, (1, self.pixel_format)) elif fourcc == D3DFMT.DXT3: self.mode = "RGBA" self.pixel_format = "DXT3" - tile = Image.Tile("bcn", extents, data_offs, (2, self.pixel_format)) + tile = Image._Tile("bcn", extents, data_offs, (2, self.pixel_format)) elif fourcc == D3DFMT.DXT5: self.mode = "RGBA" self.pixel_format = "DXT5" - tile = Image.Tile("bcn", extents, data_offs, (3, self.pixel_format)) - elif fourcc == D3DFMT.ATI1: + tile = Image._Tile("bcn", extents, data_offs, (3, self.pixel_format)) + elif fourcc == D3DFMT.ATI1 or fourcc == D3DFMT.BC4U: self.mode = "L" self.pixel_format = "BC4" - tile = Image.Tile("bcn", extents, data_offs, (4, self.pixel_format)) + tile = Image._Tile("bcn", extents, data_offs, (4, self.pixel_format)) elif fourcc == D3DFMT.BC5S: self.mode = "RGB" self.pixel_format = "BC5S" - tile = Image.Tile("bcn", extents, data_offs, (5, self.pixel_format)) + tile = Image._Tile("bcn", extents, data_offs, (5, self.pixel_format)) elif fourcc == D3DFMT.BC5U: self.mode = "RGB" self.pixel_format = "BC5U" - tile = Image.Tile("bcn", extents, data_offs, (5, self.pixel_format)) + tile = Image._Tile("bcn", extents, data_offs, (5, self.pixel_format)) elif fourcc == D3DFMT.ATI2: self.mode = "RGB" self.pixel_format = "BC5" - tile = Image.Tile("bcn", extents, data_offs, (5, self.pixel_format)) + tile = Image._Tile("bcn", extents, data_offs, (5, self.pixel_format)) elif fourcc == D3DFMT.DX10: data_offs += 20 # ignoring flags which pertain to volume textures and cubemaps (dxgi_format,) = struct.unpack(" 0: fp.seek(offset)