Generating previews, normalising dataset images and cutting regions are the most common Pillow jobs.
im.resize((width, height), resample=...) returns an image of exactly that size, distorting it if the aspect ratio differs. Resampling filters live in Image.Resampling:
LANCZOS: highest quality for downscaling photos (the oldANTIALIASname was removed in Pillow 10)BICUBIC(default for most modes),BILINEAR: good general choicesNEAREST: no blending; use it for pixel art, masks and label images
im.thumbnail((max_w, max_h)) shrinks the image in place to fit inside the box while keeping its aspect ratio, and never enlarges. It returns None, so don't assign its result. For a copy, call it on im.copy().
ImageOps.contain(im, size) (fit inside), ImageOps.cover (fill the box, may overflow) and ImageOps.fit(im, size) (fill exactly by cropping the centre) cover the other common cases, returning new images.
im.crop((left, upper, right, lower)) takes a box of pixel coordinates; right and lower are exclusive, so the result is right - left wide. Coordinates outside the image are allowed and filled with zeros (black or transparent).
im.reduce(factor) shrinks by an integer factor quickly by averaging blocks, which is handy before a final resize on very large images.
Example
from PIL import Image, ImageOps
im = Image.new("RGB", (1200, 800), "orange")
small = im.resize((300, 200), Image.Resampling.LANCZOS)
print(small.size) # (300, 200)
thumb = im.copy()
result = thumb.thumbnail((256, 256)) # in place, keeps aspect ratio
print(result, thumb.size) # None (256, 171)
square = ImageOps.fit(im, (200, 200)) # centre-crop to fill
print(square.size) # (200, 200)
print(ImageOps.contain(im, (200, 200)).size) # (200, 133)
box = (100, 50, 400, 250) # left, upper, right, lower
crop = im.crop(box)
print(crop.size) # (300, 200)
print(im.crop((1100, 0, 1300, 10)).getpixel((150, 5))) # (0, 0, 0) outsideRemember
resizegives an exact size; pickImage.Resampling.LANCZOSfor quality downscalingthumbnailshrinks in place, keeps aspect ratio and returns NoneImageOps.fit/contain/coverhandle common fitting rulescrop((left, upper, right, lower))uses exclusive right/lower
Watch out for
- Writing
thumb = im.thumbnail(size)and getting None.