diff --git a/PIL/ImageFilter.py b/PIL/ImageFilter.py index c89225484..100fea8bd 100644 --- a/PIL/ImageFilter.py +++ b/PIL/ImageFilter.py @@ -160,6 +160,26 @@ class GaussianBlur(MultibandFilter): return image.gaussian_blur(self.radius) +class BoxBlur(MultibandFilter): + """Blurs the image by setting each pixel to the average value of the pixels + in a square box extending radius pixels in each direction. + Supports float radius of arbitrary size. Uses an optimized implementation + which runs in linear time relative to the size of the image + for any radius value. + + :param radius: Size of the box in one direction. Radius 0 does not blur, + returns an identical image. Radius 1 takes 1 pixel + in each direction, i.e. 9 pixels in total. + """ + name = "BoxBlur" + + def __init__(self, radius): + self.radius = radius + + def filter(self, image): + return image.box_blur(self.radius) + + class UnsharpMask(MultibandFilter): """Unsharp mask filter. diff --git a/Tests/test_box_blur.py b/Tests/test_box_blur.py index d99847740..622b842d0 100644 --- a/Tests/test_box_blur.py +++ b/Tests/test_box_blur.py @@ -13,20 +13,6 @@ sample.putdata(sum([ ], [])) -class ImageMock(object): - def __init__(self): - self.im = self - - def load(self): - pass - - def _new(self, im): - return im - - def box_blur(self, radius, n): - return radius, n - - class TestBoxBlurApi(PillowTestCase): def test_imageops_box_blur(self): diff --git a/Tests/test_image_filter.py b/Tests/test_image_filter.py index 8a38b2979..3636a73f7 100644 --- a/Tests/test_image_filter.py +++ b/Tests/test_image_filter.py @@ -1,7 +1,6 @@ from helper import unittest, PillowTestCase, hopper -from PIL import Image -from PIL import ImageFilter +from PIL import Image, ImageFilter class TestImageFilter(PillowTestCase): @@ -9,10 +8,11 @@ class TestImageFilter(PillowTestCase): def test_sanity(self): def filter(filter): - im = hopper("L") - out = im.filter(filter) - self.assertEqual(out.mode, im.mode) - self.assertEqual(out.size, im.size) + for mode in ["L", "RGB", "CMYK"]: + im = hopper(mode) + out = im.filter(filter) + self.assertEqual(out.mode, im.mode) + self.assertEqual(out.size, im.size) filter(ImageFilter.BLUR) filter(ImageFilter.CONTOUR) @@ -28,9 +28,9 @@ class TestImageFilter(PillowTestCase): filter(ImageFilter.MedianFilter) filter(ImageFilter.MinFilter) filter(ImageFilter.ModeFilter) - filter(ImageFilter.Kernel((3, 3), list(range(9)))) filter(ImageFilter.GaussianBlur) filter(ImageFilter.GaussianBlur(5)) + filter(ImageFilter.BoxBlur(5)) filter(ImageFilter.UnsharpMask) filter(ImageFilter.UnsharpMask(10)) diff --git a/docs/reference/ImageFilter.rst b/docs/reference/ImageFilter.rst index e89fafbcf..bc1868667 100644 --- a/docs/reference/ImageFilter.rst +++ b/docs/reference/ImageFilter.rst @@ -38,6 +38,7 @@ image enhancement filters: * **SHARPEN** .. autoclass:: PIL.ImageFilter.GaussianBlur +.. autoclass:: PIL.ImageFilter.BoxBlur .. autoclass:: PIL.ImageFilter.UnsharpMask .. autoclass:: PIL.ImageFilter.Kernel .. autoclass:: PIL.ImageFilter.RankFilter