diff --git a/Tests/test_file_dds.py b/Tests/test_file_dds.py index 5ef9fbf05..3239065d7 100644 --- a/Tests/test_file_dds.py +++ b/Tests/test_file_dds.py @@ -115,6 +115,19 @@ def test_sanity_ati1_bc4u(image_path: str) -> None: assert_image_equal_tofile(im, TEST_FILE_ATI1.replace(".dds", ".png")) +def test_dx10_bc2(tmp_path: Path) -> None: + out = str(tmp_path / "temp.dds") + with Image.open(TEST_FILE_DXT3) as im: + im.save(out, pixel_format="BC2") + + with Image.open(out) as reloaded: + assert reloaded.format == "DDS" + assert reloaded.mode == "RGBA" + assert reloaded.size == (256, 256) + + assert_image_similar(im, reloaded, 3.81) + + def test_dx10_bc3(tmp_path: Path) -> None: out = str(tmp_path / "temp.dds") with Image.open(TEST_FILE_DXT5) as im: diff --git a/src/PIL/DdsImagePlugin.py b/src/PIL/DdsImagePlugin.py index c30672c86..d65e3fc65 100644 --- a/src/PIL/DdsImagePlugin.py +++ b/src/PIL/DdsImagePlugin.py @@ -419,6 +419,10 @@ class DdsImageFile(ImageFile.ImageFile): self._mode = "RGBA" self.pixel_format = "BC1" n = 1 + elif dxgi_format in (DXGI_FORMAT.BC2_TYPELESS, DXGI_FORMAT.BC2_UNORM): + self._mode = "RGBA" + self.pixel_format = "BC2" + n = 2 elif dxgi_format in (DXGI_FORMAT.BC3_TYPELESS, DXGI_FORMAT.BC3_UNORM): self._mode = "RGBA" self.pixel_format = "BC3" @@ -526,7 +530,7 @@ def _save(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None: bitcount = len(im.getbands()) * 8 pixel_format = im.encoderinfo.get("pixel_format") args: tuple[int] | str - if pixel_format in ("DXT1", "DXT3", "BC3", "DXT5"): + if pixel_format in ("DXT1", "BC2", "DXT3", "BC3", "DXT5"): codec_name = "bcn" flags |= DDSD.LINEARSIZE pitch = (im.width + 3) * 4 @@ -538,10 +542,16 @@ def _save(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None: elif pixel_format == "DXT3": fourcc = D3DFMT.DXT3 args = (2,) - else: - fourcc = D3DFMT.DXT5 if pixel_format == "DXT5" else D3DFMT.DX10 + elif pixel_format == "DXT5": + fourcc = D3DFMT.DXT5 args = (3,) - if fourcc == D3DFMT.DX10: + else: + fourcc = D3DFMT.DX10 + if pixel_format == "BC2": + args = (2,) + dxgi_format = DXGI_FORMAT.BC2_TYPELESS + else: + args = (3,) dxgi_format = DXGI_FORMAT.BC3_TYPELESS else: codec_name = "raw"