Search code examples
pythonimagemagickpython-imaging-library

Trim whitespace using PIL


Is there a simple solution to trim whitespace on the image in PIL?

ImageMagick has easy support for it in the following way:

convert test.jpeg -fuzz 7% -trim test_trimmed.jpeg

I found a solution for PIL:

from PIL import Image, ImageChops

def trim(im, border):
    bg = Image.new(im.mode, im.size, border)
    diff = ImageChops.difference(im, bg)
    bbox = diff.getbbox()
    if bbox:
        return im.crop(bbox)

But this solution has disadvantages:

  1. I need to define border color, it is not a big deal for me, my images has a white background
  2. And the most disadvantage, This PIL solution doesn't support ImageMagick's -fuzz key. To add some fuzzy cropping. as I can have some jpeg compression artifacts and unneeded huge shadows.

Maybe PIL has some built-in functions for it? Or there is some fast solution?


Solution

  • I don't think there is anything built in to PIL that can do this. But I've modified your code so it will do it.

    • It gets the border colour from the top left pixel, using getpixel, so you don't need to pass the colour.
    • Subtracts a scalar from the differenced image, this is a quick way of saturating all values under 100, 100, 100 (in my example) to zero. So is a neat way to remove any 'wobble' resulting from compression.

    Code:

    from PIL import Image, ImageChops
    
    def trim(im):
        bg = Image.new(im.mode, im.size, im.getpixel((0,0)))
        diff = ImageChops.difference(im, bg)
        diff = ImageChops.add(diff, diff, 2.0, -100)
        bbox = diff.getbbox()
        if bbox:
            return im.crop(bbox)
    
    im = Image.open("bord3.jpg")
    im = trim(im)
    im.show()
    

    Heavily compressed jpeg:

    enter image description here Cropped: enter image description here

    Noisy jpeg:

    enter image description here Cropped: enter image description here