Skip to content

Commit ec11f7a

Browse files
authored
Merge branch 'main' into image_grab_wayland_kde
2 parents 2f67293 + bce83ac commit ec11f7a

26 files changed

+188
-106
lines changed
984 Bytes
Loading
0 Bytes
Loading

Tests/test_file_bmp.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -224,3 +224,13 @@ def test_offset() -> None:
224224
# to exclude the palette size from the pixel data offset
225225
with Image.open("Tests/images/pal8_offset.bmp") as im:
226226
assert_image_equal_tofile(im, "Tests/images/bmp/g/pal8.bmp")
227+
228+
229+
def test_use_raw_alpha(monkeypatch: pytest.MonkeyPatch) -> None:
230+
with Image.open("Tests/images/bmp/g/rgb32.bmp") as im:
231+
assert im.info["compression"] == BmpImagePlugin.BmpImageFile.COMPRESSIONS["RAW"]
232+
assert im.mode == "RGB"
233+
234+
monkeypatch.setattr(BmpImagePlugin, "USE_RAW_ALPHA", True)
235+
with Image.open("Tests/images/bmp/g/rgb32.bmp") as im:
236+
assert im.mode == "RGBA"

Tests/test_file_libtiff.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1026,6 +1026,17 @@ def test_old_style_jpeg(self) -> None:
10261026
with Image.open("Tests/images/old-style-jpeg-compression.tif") as im:
10271027
assert_image_equal_tofile(im, "Tests/images/old-style-jpeg-compression.png")
10281028

1029+
def test_old_style_jpeg_orientation(self) -> None:
1030+
with open("Tests/images/old-style-jpeg-compression.tif", "rb") as fp:
1031+
data = fp.read()
1032+
1033+
# Set EXIF Orientation to 2
1034+
data = data[:102] + b"\x02" + data[103:]
1035+
1036+
with Image.open(io.BytesIO(data)) as im:
1037+
im = im.transpose(Image.Transpose.FLIP_LEFT_RIGHT)
1038+
assert_image_equal_tofile(im, "Tests/images/old-style-jpeg-compression.png")
1039+
10291040
def test_open_missing_samplesperpixel(self) -> None:
10301041
with Image.open(
10311042
"Tests/images/old-style-jpeg-compression-no-samplesperpixel.tif"

Tests/test_file_palm.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,11 @@ def roundtrip(tmp_path: Path, mode: str) -> None:
4343

4444
im.save(outfile)
4545
converted = open_with_magick(magick, tmp_path, outfile)
46+
if mode == "P":
47+
assert converted.mode == "P"
48+
49+
im = im.convert("RGB")
50+
converted = converted.convert("RGB")
4651
assert_image_equal(converted, im)
4752

4853

@@ -55,7 +60,6 @@ def test_monochrome(tmp_path: Path) -> None:
5560
roundtrip(tmp_path, mode)
5661

5762

58-
@pytest.mark.xfail(reason="Palm P image is wrong")
5963
def test_p_mode(tmp_path: Path) -> None:
6064
# Arrange
6165
mode = "P"

Tests/test_file_wmf.py

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
from PIL import Image, ImageFile, WmfImagePlugin
1010

11-
from .helper import assert_image_similar_tofile, hopper
11+
from .helper import assert_image_equal_tofile, assert_image_similar_tofile, hopper
1212

1313

1414
def test_load_raw() -> None:
@@ -44,6 +44,15 @@ def test_load_zero_inch() -> None:
4444
pass
4545

4646

47+
def test_render() -> None:
48+
with open("Tests/images/drawing.emf", "rb") as fp:
49+
data = fp.read()
50+
b = BytesIO(data[:808] + b"\x00" + data[809:])
51+
with Image.open(b) as im:
52+
if hasattr(Image.core, "drawwmf"):
53+
assert_image_equal_tofile(im, "Tests/images/drawing.emf")
54+
55+
4756
def test_register_handler(tmp_path: Path) -> None:
4857
class TestHandler(ImageFile.StubHandler):
4958
methodCalled = False
@@ -88,6 +97,20 @@ def test_load_set_dpi() -> None:
8897

8998
assert_image_similar_tofile(im, "Tests/images/drawing_wmf_ref_144.png", 2.1)
9099

100+
with Image.open("Tests/images/drawing.emf") as im:
101+
assert im.size == (1625, 1625)
102+
103+
if not hasattr(Image.core, "drawwmf"):
104+
return
105+
im.load(im.info["dpi"])
106+
assert im.size == (1625, 1625)
107+
108+
with Image.open("Tests/images/drawing.emf") as im:
109+
im.load((72, 144))
110+
assert im.size == (82, 164)
111+
112+
assert_image_equal_tofile(im, "Tests/images/drawing_emf_ref_72_144.png")
113+
91114

92115
@pytest.mark.parametrize("ext", (".wmf", ".emf"))
93116
def test_save(ext: str, tmp_path: Path) -> None:

Tests/test_imagedraw.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1704,7 +1704,7 @@ def test_discontiguous_corners_polygon() -> None:
17041704
BLACK,
17051705
)
17061706
expected = os.path.join(IMAGES_PATH, "discontiguous_corners_polygon.png")
1707-
assert_image_similar_tofile(img, expected, 1)
1707+
assert_image_equal_tofile(img, expected)
17081708

17091709

17101710
def test_polygon2() -> None:

Tests/test_imagefile.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,26 @@ def test_safeblock(self) -> None:
131131

132132
assert_image_equal(im1, im2)
133133

134+
def test_tile_size(self) -> None:
135+
with open("Tests/images/hopper.tif", "rb") as im_fp:
136+
data = im_fp.read()
137+
138+
reads = []
139+
140+
class FP(BytesIO):
141+
def read(self, size: int | None = None) -> bytes:
142+
reads.append(size)
143+
return super().read(size)
144+
145+
fp = FP(data)
146+
with Image.open(fp) as im:
147+
assert len(im.tile) == 7
148+
149+
im.load()
150+
151+
# Despite multiple tiles, assert only one tile caused a read of maxblock size
152+
assert reads.count(im.decodermaxblock) == 1
153+
134154
def test_raise_oserror(self) -> None:
135155
with pytest.warns(DeprecationWarning):
136156
with pytest.raises(OSError):

docs/releasenotes/11.2.0.rst

Lines changed: 12 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -4,21 +4,12 @@
44
Security
55
========
66

7-
TODO
8-
^^^^
7+
Undefined shift when loading compressed DDS images
8+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
99

10-
TODO
11-
12-
:cve:`YYYY-XXXXX`: TODO
13-
^^^^^^^^^^^^^^^^^^^^^^^
14-
15-
TODO
16-
17-
Backwards Incompatible Changes
18-
==============================
19-
20-
TODO
21-
^^^^
10+
When loading some compressed DDS formats, an integer was bitshifted by 24 places to
11+
generate the 32 bits of the lookup table. This was undefined behaviour, and has been
12+
present since Pillow 3.4.0.
2213

2314
Deprecations
2415
============
@@ -36,10 +27,14 @@ an :py:class:`PIL.ImageFile.ImageFile` instance.
3627
API Changes
3728
===========
3829

39-
TODO
40-
^^^^
30+
``append_images`` no longer requires ``save_all``
31+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
32+
33+
Previously, ``save_all`` was required to in order to use ``append_images``. Now,
34+
``save_all`` will default to ``True`` if ``append_images`` is not empty and the format
35+
supports saving multiple frames::
4136

42-
TODO
37+
im.save("out.gif", append_images=ims)
4338

4439
API Additions
4540
=============
@@ -73,11 +68,3 @@ Compressed DDS images can now be saved using a ``pixel_format`` argument. DXT1,
7368
DXT5, BC2, BC3 and BC5 are supported::
7469

7570
im.save("out.dds", pixel_format="DXT1")
76-
77-
Other Changes
78-
=============
79-
80-
TODO
81-
^^^^
82-
83-
TODO

src/PIL/BmpImagePlugin.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,8 @@
4848
32: ("RGB", "BGRX"),
4949
}
5050

51+
USE_RAW_ALPHA = False
52+
5153

5254
def _accept(prefix: bytes) -> bool:
5355
return prefix.startswith(b"BM")
@@ -242,7 +244,9 @@ def _bitmap(self, header: int = 0, offset: int = 0) -> None:
242244
msg = "Unsupported BMP bitfields layout"
243245
raise OSError(msg)
244246
elif file_info["compression"] == self.COMPRESSIONS["RAW"]:
245-
if file_info["bits"] == 32 and header == 22: # 32-bit .cur offset
247+
if file_info["bits"] == 32 and (
248+
header == 22 or USE_RAW_ALPHA # 32-bit .cur offset
249+
):
246250
raw_mode, self._mode = "BGRA", "RGBA"
247251
elif file_info["compression"] in (
248252
self.COMPRESSIONS["RLE8"],

0 commit comments

Comments
 (0)