From 091dff94cdb7c6fd365db2d699ef18e8569c832e Mon Sep 17 00:00:00 2001 From: Fahad Date: Mon, 21 Sep 2026 09:48:12 +0000 Subject: [PATCH] Keep contain() dimensions at a minimum of one pixel ImageOps.contain() derives the second dimension with round(), which can come out as zero for a very narrow image, and resize() then fails with "height and width must be > 0". ImageOps.pad() raised the same error, since it calls contain(). --- Tests/test_imageops.py | 21 +++++++++++++++++++++ src/PIL/ImageOps.py | 4 ++-- 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/Tests/test_imageops.py b/Tests/test_imageops.py index 4a4826d22e3..d9619adf343 100644 --- a/Tests/test_imageops.py +++ b/Tests/test_imageops.py @@ -142,6 +142,27 @@ def test_contain_round() -> None: assert new_im.height == 5 +@pytest.mark.parametrize( + "size, expected_size", + ( + ((100, 1), (10, 1)), + ((1, 100), (1, 10)), + ((20, 1), (10, 1)), + ((1, 20), (1, 10)), + ), +) +def test_contain_round_to_zero( + size: tuple[int, int], expected_size: tuple[int, int] +) -> None: + im = Image.new("1", size, 1) + + new_im = ImageOps.contain(im, (10, 10)) + assert new_im.size == expected_size + + new_im = ImageOps.pad(im, (10, 10)) + assert new_im.size == (10, 10) + + @pytest.mark.parametrize( "image_name, expected_size", ( diff --git a/src/PIL/ImageOps.py b/src/PIL/ImageOps.py index 593f801b031..f52b150188f 100644 --- a/src/PIL/ImageOps.py +++ b/src/PIL/ImageOps.py @@ -300,11 +300,11 @@ def contain( if im_ratio != dest_ratio: if im_ratio > dest_ratio: - new_height = round(image.height / image.width * size[0]) + new_height = max(round(image.height / image.width * size[0]), 1) if new_height != size[1]: size = (size[0], new_height) else: - new_width = round(image.width / image.height * size[1]) + new_width = max(round(image.width / image.height * size[1]), 1) if new_width != size[0]: size = (new_width, size[1]) return image.resize(size, resample=method)