diff --git a/Tests/images/bc1.dds b/Tests/images/bc1.dds new file mode 100755 index 000000000..faec63a00 Binary files /dev/null and b/Tests/images/bc1.dds differ diff --git a/Tests/images/bc1_typeless.dds b/Tests/images/bc1_typeless.dds new file mode 100755 index 000000000..47a85e2d0 Binary files /dev/null and b/Tests/images/bc1_typeless.dds differ diff --git a/Tests/images/rgb8.dds b/Tests/images/rgb8.dds new file mode 100644 index 000000000..8193e8e5a Binary files /dev/null and b/Tests/images/rgb8.dds differ diff --git a/Tests/images/unsupported_bitcount_luminance.dds b/Tests/images/unsupported_bitcount_luminance.dds new file mode 100644 index 000000000..f9bb82254 Binary files /dev/null and b/Tests/images/unsupported_bitcount_luminance.dds differ diff --git a/Tests/images/unsupported_bitcount_rgb.dds b/Tests/images/unsupported_bitcount_rgb.dds new file mode 100644 index 000000000..77d527507 Binary files /dev/null and b/Tests/images/unsupported_bitcount_rgb.dds differ diff --git a/Tests/test_file_dds.py b/Tests/test_file_dds.py index 72bb2df7b..bed143656 100644 --- a/Tests/test_file_dds.py +++ b/Tests/test_file_dds.py @@ -15,6 +15,8 @@ TEST_FILE_ATI2 = "Tests/images/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" +TEST_FILE_DX10_BC1 = "Tests/images/bc1.dds" +TEST_FILE_DX10_BC1_TYPELESS = "Tests/images/bc1_typeless.dds" TEST_FILE_BC5S = "Tests/images/bc5s.dds" TEST_FILE_BC5U = "Tests/images/bc5u.dds" TEST_FILE_BC6H = "Tests/images/bc6h.dds" @@ -29,11 +31,20 @@ TEST_FILE_UNCOMPRESSED_RGB = "Tests/images/hopper.dds" TEST_FILE_UNCOMPRESSED_RGB_WITH_ALPHA = "Tests/images/uncompressed_rgb.dds" -def test_sanity_dxt1(): +@pytest.mark.parametrize( + "image_path", + ( + TEST_FILE_DXT1, + # hexeditted to use DX10 FourCC + TEST_FILE_DX10_BC1, + TEST_FILE_DX10_BC1_TYPELESS, + ), +) +def test_sanity_bc1(image_path): """Check DXT1 images can be opened""" with Image.open(TEST_FILE_DXT1.replace(".dds", ".png")) as target: target = target.convert("RGBA") - with Image.open(TEST_FILE_DXT1) as im: + with Image.open(image_path) as im: im.load() assert im.format == "DDS" @@ -306,8 +317,19 @@ def test_palette(): @pytest.mark.parametrize( "test_file", ( - "Tests/images/unknown_fourcc.dds", - "Tests/images/unimplemented_fourcc.dds", + "Tests/images/unsupported_bitcount_rgb.dds", + "Tests/images/unsupported_bitcount_luminance.dds", + ), +) +def test_unsupported_bitcount(test_file): + with pytest.raises(OSError): + with Image.open(test_file): + pass + + +@pytest.mark.parametrize( + "test_file", + ( "Tests/images/unimplemented_dxgi_format.dds", "Tests/images/unimplemented_pfflags.dds", ), @@ -340,6 +362,12 @@ def test_open(mode, test_file): assert_image_equal_tofile(im, test_file.replace(".dds", ".png")) +def test_open_rgb8(): + with Image.open("Tests/images/rgb8.dds") as im: + assert im.mode == "L" + assert_image_equal_tofile(im, "Tests/images/mode-l.png") + + @pytest.mark.parametrize( ("mode", "test_file"), [ diff --git a/src/PIL/DdsImagePlugin.py b/src/PIL/DdsImagePlugin.py index bf3807c84..467030114 100644 --- a/src/PIL/DdsImagePlugin.py +++ b/src/PIL/DdsImagePlugin.py @@ -346,34 +346,27 @@ class DdsImageFile(ImageFile.ImageFile): # pixel format pfsize, pfflags, fourcc, bitcount = struct.unpack("<4I", header.read(16)) masks = struct.unpack("<4I", header.read(16)) - if flags & DDSD.CAPS: - header.seek(20, io.SEEK_CUR) n = 0 rawmode = None if pfflags & DDPF.RGB: # Texture contains uncompressed RGB data masks = {mask: ["R", "G", "B", "A"][i] for i, mask in enumerate(masks)} - if bitcount == 24: + if bitcount == 8: + self._mode = "L" + elif bitcount == 24: self._mode = "RGB" - rawmode = masks[0x00FF0000] + masks[0x0000FF00] + masks[0x000000FF] + rawmode = masks[0x000000FF] + masks[0x0000FF00] + masks[0x00FF0000] elif bitcount == 32 and pfflags & DDPF.ALPHAPIXELS: self._mode = "RGBA" rawmode = ( - masks[0xFF000000] - + masks[0x00FF0000] + masks[0x000000FF] + masks[0x0000FF00] - + masks[0x000000FF] + + masks[0x00FF0000] + + masks[0xFF000000] ) else: msg = f"Unsupported bitcount {bitcount} for {pfflags}" raise OSError(msg) - rawmode = rawmode[::-1] - elif pfflags & DDPF.ALPHA: - if bitcount == 8: - self._mode = "L" - else: - msg = f"Unsupported bitcount {bitcount} for {pfflags}" - raise OSError(msg) elif pfflags & DDPF.LUMINANCE: if bitcount == 8: self._mode = "L" @@ -418,7 +411,6 @@ class DdsImageFile(ImageFile.ImageFile): self.fp.read(16) if dxgi_format in ( DXGI_FORMAT.BC1_UNORM, - DXGI_FORMAT.BC1_UNORM_SRGB, DXGI_FORMAT.BC1_TYPELESS, ): self._mode = "RGBA"