Added support for uncompressed LA images

This commit is contained in:
Andrew Murray 2022-12-23 19:07:45 +11:00
parent 582b631001
commit dcf3d0bee2
4 changed files with 34 additions and 37 deletions

View File

Before

Width:  |  Height:  |  Size: 1.0 KiB

After

Width:  |  Height:  |  Size: 1.0 KiB

View File

@ -23,6 +23,7 @@ TEST_FILE_DX10_BC7_UNORM_SRGB = "Tests/images/DXGI_FORMAT_BC7_UNORM_SRGB.dds"
TEST_FILE_DX10_R8G8B8A8 = "Tests/images/argb-32bpp_MipMaps-1.dds" TEST_FILE_DX10_R8G8B8A8 = "Tests/images/argb-32bpp_MipMaps-1.dds"
TEST_FILE_DX10_R8G8B8A8_UNORM_SRGB = "Tests/images/DXGI_FORMAT_R8G8B8A8_UNORM_SRGB.dds" TEST_FILE_DX10_R8G8B8A8_UNORM_SRGB = "Tests/images/DXGI_FORMAT_R8G8B8A8_UNORM_SRGB.dds"
TEST_FILE_UNCOMPRESSED_L = "Tests/images/uncompressed_l.dds" TEST_FILE_UNCOMPRESSED_L = "Tests/images/uncompressed_l.dds"
TEST_FILE_UNCOMPRESSED_L_WITH_ALPHA = "Tests/images/uncompressed_la.dds"
TEST_FILE_UNCOMPRESSED_RGB = "Tests/images/hopper.dds" TEST_FILE_UNCOMPRESSED_RGB = "Tests/images/hopper.dds"
TEST_FILE_UNCOMPRESSED_RGB_WITH_ALPHA = "Tests/images/uncompressed_rgb.dds" TEST_FILE_UNCOMPRESSED_RGB_WITH_ALPHA = "Tests/images/uncompressed_rgb.dds"
@ -195,32 +196,24 @@ def test_unimplemented_dxgi_format():
pass pass
def test_uncompressed(): @pytest.mark.parametrize(
("mode", "size", "test_file"),
[
("L", (128, 128), TEST_FILE_UNCOMPRESSED_L),
("LA", (128, 128), TEST_FILE_UNCOMPRESSED_L_WITH_ALPHA),
("RGB", (128, 128), TEST_FILE_UNCOMPRESSED_RGB),
("RGBA", (800, 600), TEST_FILE_UNCOMPRESSED_RGB_WITH_ALPHA),
],
)
def test_uncompressed(mode, size, test_file):
"""Check uncompressed images can be opened""" """Check uncompressed images can be opened"""
with Image.open(TEST_FILE_UNCOMPRESSED_L) as im:
with Image.open(test_file) as im:
assert im.format == "DDS" assert im.format == "DDS"
assert im.mode == "L" assert im.mode == mode
assert im.size == (128, 128) assert im.size == size
assert_image_equal_tofile(im, "Tests/images/uncompressed_l.png") assert_image_equal_tofile(im, test_file.replace(".dds", ".png"))
# convert -format dds -define dds:compression=none hopper.jpg hopper.dds
with Image.open(TEST_FILE_UNCOMPRESSED_RGB) as im:
assert im.format == "DDS"
assert im.mode == "RGB"
assert im.size == (128, 128)
assert_image_equal_tofile(im, "Tests/images/hopper.png")
# Test image with alpha
with Image.open(TEST_FILE_UNCOMPRESSED_RGB_WITH_ALPHA) as im:
assert im.format == "DDS"
assert im.mode == "RGBA"
assert im.size == (800, 600)
assert_image_equal_tofile(
im, TEST_FILE_UNCOMPRESSED_RGB_WITH_ALPHA.replace(".dds", ".png")
)
def test__accept_true(): def test__accept_true():
@ -313,6 +306,7 @@ def test_save_unsupported_mode(tmp_path):
("mode", "test_file"), ("mode", "test_file"),
[ [
("L", "Tests/images/linear_gradient.png"), ("L", "Tests/images/linear_gradient.png"),
("LA", "Tests/images/uncompressed_la.png"),
("RGB", "Tests/images/hopper.png"), ("RGB", "Tests/images/hopper.png"),
("RGBA", "Tests/images/pil123rgba.png"), ("RGBA", "Tests/images/pil123rgba.png"),
], ],

View File

@ -136,15 +136,18 @@ class DdsImageFile(ImageFile.ImageFile):
(bitcount,) = struct.unpack("<I", header.read(4)) (bitcount,) = struct.unpack("<I", header.read(4))
masks = struct.unpack("<4I", header.read(16)) masks = struct.unpack("<4I", header.read(16))
if pfflags & DDPF_LUMINANCE: if pfflags & DDPF_LUMINANCE:
# Texture contains uncompressed L data # Texture contains uncompressed L or LA data
if pfflags & DDPF_ALPHAPIXELS:
self.mode = "LA"
else:
self.mode = "L" self.mode = "L"
self.tile = [("raw", (0, 0) + self.size, 0, ("L", 0, 1))] self.tile = [("raw", (0, 0) + self.size, 0, (self.mode, 0, 1))]
elif pfflags & DDPF_RGB: elif pfflags & DDPF_RGB:
# Texture contains uncompressed RGB data # Texture contains uncompressed RGB data
masks = {mask: ["R", "G", "B", "A"][i] for i, mask in enumerate(masks)} masks = {mask: ["R", "G", "B", "A"][i] for i, mask in enumerate(masks)}
rawmode = "" rawmode = ""
if bitcount == 32: if pfflags & DDPF_ALPHAPIXELS:
rawmode += masks[0xFF000000] rawmode += masks[0xFF000000]
else: else:
self.mode = "RGB" self.mode = "RGB"
@ -228,19 +231,19 @@ class DdsImageFile(ImageFile.ImageFile):
def _save(im, fp, filename): def _save(im, fp, filename):
if im.mode not in ("RGB", "RGBA", "L"): if im.mode not in ("RGB", "RGBA", "L", "LA"):
raise OSError(f"cannot write mode {im.mode} as DDS") raise OSError(f"cannot write mode {im.mode} as DDS")
if im.mode == "L": rawmode = im.mode
masks = [0xFF000000] masks = [0xFF0000, 0xFF00, 0xFF]
if im.mode in ("L", "LA"):
pixel_flags = DDPF_LUMINANCE pixel_flags = DDPF_LUMINANCE
else:
masks = [0xFF0000, 0xFF00, 0xFF]
if im.mode == "RGBA":
pixel_flags = DDS_RGBA
masks.append(0xFF000000)
else: else:
pixel_flags = DDPF_RGB pixel_flags = DDPF_RGB
rawmode = rawmode[::-1]
if im.mode in ("LA", "RGBA"):
pixel_flags |= DDPF_ALPHAPIXELS
masks.append(0xFF000000)
bitcount = len(masks) * 8 bitcount = len(masks) * 8
while len(masks) < 4: while len(masks) < 4:
@ -272,7 +275,7 @@ def _save(im, fp, filename):
if im.mode == "RGBA": if im.mode == "RGBA":
r, g, b, a = im.split() r, g, b, a = im.split()
im = Image.merge("RGBA", (a, r, g, b)) im = Image.merge("RGBA", (a, r, g, b))
ImageFile._save(im, fp, [("raw", (0, 0) + im.size, 0, (im.mode[::-1], 0, 1))]) ImageFile._save(im, fp, [("raw", (0, 0) + im.size, 0, (rawmode, 0, 1))])
def _accept(prefix): def _accept(prefix):