From 98e2b7ea599625fbc75f28f20361b593f1013ace Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Sat, 6 Jun 2026 17:45:50 +1000 Subject: [PATCH] Validate size and rank when initializing RankFilter --- Tests/test_image_filter.py | 16 ++++++++++++++-- src/PIL/ImageFilter.py | 20 +++++++++++++------- 2 files changed, 27 insertions(+), 9 deletions(-) diff --git a/Tests/test_image_filter.py b/Tests/test_image_filter.py index e566cd0557a..5a7d3f90a0a 100644 --- a/Tests/test_image_filter.py +++ b/Tests/test_image_filter.py @@ -136,11 +136,23 @@ def test_rankfilter_error(filter: ImageFilter.RankFilter) -> None: def test_rankfilter_properties() -> None: - rankfilter = ImageFilter.RankFilter(1, 2) + rankfilter = ImageFilter.RankFilter(3, 2) - assert rankfilter.size == 1 + assert rankfilter.size == 3 assert rankfilter.rank == 2 + with pytest.raises(ValueError, match="bad filter size"): + ImageFilter.RankFilter(2, 1) + with pytest.raises(ValueError, match="bad filter size"): + ImageFilter.MaxFilter(2) + with pytest.raises(ValueError, match="bad filter size"): + ImageFilter.MedianFilter(2) + with pytest.raises(ValueError, match="bad filter size"): + ImageFilter.MinFilter(2) + + with pytest.raises(ValueError, match="bad rank value"): + ImageFilter.RankFilter(1, 1) + def test_builtinfilter_p() -> None: builtin_filter = ImageFilter.BuiltinFilter() diff --git a/src/PIL/ImageFilter.py b/src/PIL/ImageFilter.py index 9326eeeda9d..a7aeff3040c 100644 --- a/src/PIL/ImageFilter.py +++ b/src/PIL/ImageFilter.py @@ -90,7 +90,7 @@ class RankFilter(Filter): Create a rank filter. The rank filter sorts all pixels in a window of the given size, and returns the ``rank``'th value. - :param size: The kernel size, in pixels. + :param size: The kernel size, in pixels. Must be odd. :param rank: What pixel value to pick. Use 0 for a min filter, ``size * size / 2`` for a median filter, ``size * size - 1`` for a max filter, etc. @@ -99,6 +99,12 @@ class RankFilter(Filter): name = "Rank" def __init__(self, size: int, rank: int) -> None: + if size % 2 == 0: + msg = "bad filter size" + raise ValueError(msg) + if rank < 0 or rank >= size * size: + msg = "bad rank value" + raise ValueError(msg) self.size = size self.rank = rank @@ -121,8 +127,8 @@ class MedianFilter(RankFilter): name = "Median" def __init__(self, size: int = 3) -> None: - self.size = size - self.rank = size * size // 2 + rank = size * size // 2 + super().__init__(size, rank) class MinFilter(RankFilter): @@ -136,8 +142,8 @@ class MinFilter(RankFilter): name = "Min" def __init__(self, size: int = 3) -> None: - self.size = size - self.rank = 0 + rank = 0 + super().__init__(size, rank) class MaxFilter(RankFilter): @@ -151,8 +157,8 @@ class MaxFilter(RankFilter): name = "Max" def __init__(self, size: int = 3) -> None: - self.size = size - self.rank = size * size - 1 + rank = size * size - 1 + super().__init__(size, rank) class ModeFilter(Filter):