Skip to content

Commit dcf3d0b

Browse files
committed
Added support for uncompressed LA images
1 parent 582b631 commit dcf3d0b

File tree

4 files changed

+33
-36
lines changed

4 files changed

+33
-36
lines changed
File renamed without changes.
File renamed without changes.

Tests/test_file_dds.py

Lines changed: 16 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
TEST_FILE_DX10_R8G8B8A8 = "Tests/images/argb-32bpp_MipMaps-1.dds"
2424
TEST_FILE_DX10_R8G8B8A8_UNORM_SRGB = "Tests/images/DXGI_FORMAT_R8G8B8A8_UNORM_SRGB.dds"
2525
TEST_FILE_UNCOMPRESSED_L = "Tests/images/uncompressed_l.dds"
26+
TEST_FILE_UNCOMPRESSED_L_WITH_ALPHA = "Tests/images/uncompressed_la.dds"
2627
TEST_FILE_UNCOMPRESSED_RGB = "Tests/images/hopper.dds"
2728
TEST_FILE_UNCOMPRESSED_RGB_WITH_ALPHA = "Tests/images/uncompressed_rgb.dds"
2829

@@ -195,32 +196,24 @@ def test_unimplemented_dxgi_format():
195196
pass
196197

197198

198-
def test_uncompressed():
199+
@pytest.mark.parametrize(
200+
("mode", "size", "test_file"),
201+
[
202+
("L", (128, 128), TEST_FILE_UNCOMPRESSED_L),
203+
("LA", (128, 128), TEST_FILE_UNCOMPRESSED_L_WITH_ALPHA),
204+
("RGB", (128, 128), TEST_FILE_UNCOMPRESSED_RGB),
205+
("RGBA", (800, 600), TEST_FILE_UNCOMPRESSED_RGB_WITH_ALPHA),
206+
],
207+
)
208+
def test_uncompressed(mode, size, test_file):
199209
"""Check uncompressed images can be opened"""
200-
with Image.open(TEST_FILE_UNCOMPRESSED_L) as im:
201-
assert im.format == "DDS"
202-
assert im.mode == "L"
203-
assert im.size == (128, 128)
204-
205-
assert_image_equal_tofile(im, "Tests/images/uncompressed_l.png")
206-
207-
# convert -format dds -define dds:compression=none hopper.jpg hopper.dds
208-
with Image.open(TEST_FILE_UNCOMPRESSED_RGB) as im:
209-
assert im.format == "DDS"
210-
assert im.mode == "RGB"
211-
assert im.size == (128, 128)
212210

213-
assert_image_equal_tofile(im, "Tests/images/hopper.png")
214-
215-
# Test image with alpha
216-
with Image.open(TEST_FILE_UNCOMPRESSED_RGB_WITH_ALPHA) as im:
211+
with Image.open(test_file) as im:
217212
assert im.format == "DDS"
218-
assert im.mode == "RGBA"
219-
assert im.size == (800, 600)
213+
assert im.mode == mode
214+
assert im.size == size
220215

221-
assert_image_equal_tofile(
222-
im, TEST_FILE_UNCOMPRESSED_RGB_WITH_ALPHA.replace(".dds", ".png")
223-
)
216+
assert_image_equal_tofile(im, test_file.replace(".dds", ".png"))
224217

225218

226219
def test__accept_true():
@@ -313,6 +306,7 @@ def test_save_unsupported_mode(tmp_path):
313306
("mode", "test_file"),
314307
[
315308
("L", "Tests/images/linear_gradient.png"),
309+
("LA", "Tests/images/uncompressed_la.png"),
316310
("RGB", "Tests/images/hopper.png"),
317311
("RGBA", "Tests/images/pil123rgba.png"),
318312
],

src/PIL/DdsImagePlugin.py

Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -136,15 +136,18 @@ def _open(self):
136136
(bitcount,) = struct.unpack("<I", header.read(4))
137137
masks = struct.unpack("<4I", header.read(16))
138138
if pfflags & DDPF_LUMINANCE:
139-
# Texture contains uncompressed L data
140-
self.mode = "L"
139+
# Texture contains uncompressed L or LA data
140+
if pfflags & DDPF_ALPHAPIXELS:
141+
self.mode = "LA"
142+
else:
143+
self.mode = "L"
141144

142-
self.tile = [("raw", (0, 0) + self.size, 0, ("L", 0, 1))]
145+
self.tile = [("raw", (0, 0) + self.size, 0, (self.mode, 0, 1))]
143146
elif pfflags & DDPF_RGB:
144147
# Texture contains uncompressed RGB data
145148
masks = {mask: ["R", "G", "B", "A"][i] for i, mask in enumerate(masks)}
146149
rawmode = ""
147-
if bitcount == 32:
150+
if pfflags & DDPF_ALPHAPIXELS:
148151
rawmode += masks[0xFF000000]
149152
else:
150153
self.mode = "RGB"
@@ -228,19 +231,19 @@ def load_seek(self, pos):
228231

229232

230233
def _save(im, fp, filename):
231-
if im.mode not in ("RGB", "RGBA", "L"):
234+
if im.mode not in ("RGB", "RGBA", "L", "LA"):
232235
raise OSError(f"cannot write mode {im.mode} as DDS")
233236

234-
if im.mode == "L":
235-
masks = [0xFF000000]
237+
rawmode = im.mode
238+
masks = [0xFF0000, 0xFF00, 0xFF]
239+
if im.mode in ("L", "LA"):
236240
pixel_flags = DDPF_LUMINANCE
237241
else:
238-
masks = [0xFF0000, 0xFF00, 0xFF]
239-
if im.mode == "RGBA":
240-
pixel_flags = DDS_RGBA
241-
masks.append(0xFF000000)
242-
else:
243-
pixel_flags = DDPF_RGB
242+
pixel_flags = DDPF_RGB
243+
rawmode = rawmode[::-1]
244+
if im.mode in ("LA", "RGBA"):
245+
pixel_flags |= DDPF_ALPHAPIXELS
246+
masks.append(0xFF000000)
244247

245248
bitcount = len(masks) * 8
246249
while len(masks) < 4:
@@ -272,7 +275,7 @@ def _save(im, fp, filename):
272275
if im.mode == "RGBA":
273276
r, g, b, a = im.split()
274277
im = Image.merge("RGBA", (a, r, g, b))
275-
ImageFile._save(im, fp, [("raw", (0, 0) + im.size, 0, (im.mode[::-1], 0, 1))])
278+
ImageFile._save(im, fp, [("raw", (0, 0) + im.size, 0, (rawmode, 0, 1))])
276279

277280

278281
def _accept(prefix):

0 commit comments

Comments
 (0)