Crop a PNG image to its minimum size

Here is ready-to-use solution:

import numpy as np
from PIL import Image

def bbox(im):
    a = np.array(im)[:,:,:3]  # keep RGB only
    m = np.any(a != [255, 255, 255], axis=2)
    coords = np.argwhere(m)
    y0, x0, y1, x1 = *np.min(coords, axis=0), *np.max(coords, axis=0)
    return (x0, y0, x1+1, y1+1)

im = Image.open('test.png')
print(bbox(im))  # (33, 12, 223, 80)
im2 = im.crop(bbox(im))
im2.save('test_cropped.png')

Example input (download link if you want to try):

enter image description here

Output:

enter image description here


I had the same problem today. Here is my solution to crop the transparent borders. Just throw this script in your folder with your batch .png files:

from PIL import Image
import numpy as np
from os import listdir

def crop(png_image_name):
    pil_image = Image.open(png_image_name)
    np_array = np.array(pil_image)
    blank_px = [255, 255, 255, 0]
    mask = np_array != blank_px
    coords = np.argwhere(mask)
    x0, y0, z0 = coords.min(axis=0)
    x1, y1, z1 = coords.max(axis=0) + 1
    cropped_box = np_array[x0:x1, y0:y1, z0:z1]
    pil_image = Image.fromarray(cropped_box, 'RGBA')
    print(pil_image.width, pil_image.height)
    pil_image.save(png_image_name)
    print(png_image_name)

for f in listdir('.'):
    if f.endswith('.png'):
        crop(f)

PIL's getbbox is working for me

im.getbbox() => 4-tuple or None

Calculates the bounding box of the non-zero regions in the image. The bounding box is returned as a 4-tuple defining the left, upper, right, and lower pixel coordinate. If the image is completely empty, this method returns None.

Code Sample that I tried, I have tested with bmp, but it should work for png too.

import Image
im = Image.open("test.bmp")
im.size  # (364, 471)
im.getbbox()  # (64, 89, 278, 267)
im2 = im.crop(im.getbbox())
im2.size  # (214, 178)
im2.save("test2.bmp")

Tags:

Python

Image

Png