If you have more than a few images to process, or you want resizing built into an app, Python’s Pillow library is a good starting point. It’s small, well documented and handles most formats.
Install Pillow
pip install PillowResize to exact dimensions
from PIL import Image
img = Image.open("photo.jpg")
resized = img.resize((800, 600), Image.Resampling.LANCZOS)
resized.save("photo-800x600.jpg", quality=85)resize() forces the exact size you give it. If the new proportions don’t match the original, the image will be stretched. Use it when you’ve already decided the shape. On older Pillow versions, the resampling constant may be written as Image.LANCZOS.
Keep the aspect ratio with thumbnail()
from PIL import Image
img = Image.open("photo.jpg")
img.thumbnail((1200, 1200))
img.save("photo-small.jpg", quality=80, optimize=True)thumbnail() shrinks the image so it fits inside the box you give, keeping proportions. It changes the image in place, and it never enlarges, which is usually what you want. The ratio logic is explained in what is aspect ratio.
Fix phone photos that come out sideways
Photos from phones often rely on an EXIF orientation tag. If you resize and save without handling it, the image may appear rotated. Pillow has a helper for this:
from PIL import Image, ImageOps
img = Image.open("phone-photo.jpg")
img = ImageOps.exif_transpose(img)
img.thumbnail((1600, 1600))
img.save("phone-photo-small.jpg", quality=82)More on that tag in what is EXIF data.
Convert PNG with transparency to JPG
JPG can’t store transparency, so convert the image mode first, or Pillow will raise an error:
img = Image.open("logo.png").convert("RGB")
img.save("logo.jpg", quality=85)Transparent areas will turn black. To get a white background, paste the image onto a white canvas first. See converting PNG to JPG for why this happens.
Batch resize a folder
from pathlib import Path
from PIL import Image, ImageOps
src = Path("originals")
dst = Path("resized")
dst.mkdir(exist_ok=True)
for path in src.glob("*.jpg"):
img = ImageOps.exif_transpose(Image.open(path))
img.thumbnail((1600, 1600))
img.save(dst / path.name, quality=80, optimize=True)Saving into a separate folder means your originals stay untouched, which is the safest habit. See common resizing mistakes.
Save as WebP
img.save("photo.webp", quality=80)WebP support depends on how Pillow was built, but standard installs usually include it. Why it’s worth it is covered in converting images to WebP.
Choosing a resampling filter
Lanczos gives sharp results for shrinking photos. Bicubic is a good all-rounder. Nearest is for pixel art. Details are in resampling methods.
When code isn’t worth it
Prefer the terminal? See resizing images with ImageMagick.
For a one-off job, writing a script takes longer than using a tool. Try our free online image resizer and keep Python for the repetitive work.
