Freedom Sale
Independence Day Special — Unlock the AI Path 70% off our most popular AI course · Limited time offer
--Days
--Hrs
--Min
--Sec
Claim Your Discount
✦ Beginner ⏱ 25 min

🖼️ Build a Batch Image Resizer with Python

🎯 What You'll Build

A script that resizes, converts, watermarks, and renames an entire folder of images in one command — handling hundreds of files in seconds.

📋 What You'll Need

1

Resize a single image

Open an image with Pillow and resize it while preserving the aspect ratio.

from PIL import Image
from pathlib import Path

def resize_image(input_path, output_path, max_width=800, max_height=800):
    with Image.open(input_path) as img:
        # Convert RGBA to RGB if saving as JPEG
        if img.mode in ('RGBA', 'P'):
            img = img.convert('RGB')

        # thumbnail() preserves aspect ratio and never upscales
        img.thumbnail((max_width, max_height), Image.LANCZOS)
        img.save(output_path, quality=85, optimize=True)
        print(f"Saved: {output_path}  ({img.size[0]}x{img.size[1]})")

resize_image('photo.jpg', 'photo_small.jpg', 800, 600)
2

Batch process an entire folder

Loop through every image in a folder and process all of them.

import os

SUPPORTED = {'.jpg', '.jpeg', '.png', '.bmp', '.gif', '.webp', '.tiff'}

def batch_resize(input_folder, output_folder, max_size=(800, 800), fmt='JPEG'):
    input_path  = Path(input_folder)
    output_path = Path(output_folder)
    output_path.mkdir(exist_ok=True)

    images = [f for f in input_path.iterdir() if f.suffix.lower() in SUPPORTED]
    print(f"Found {len(images)} images in {input_folder}\n")

    for i, img_path in enumerate(images, 1):
        ext = '.jpg' if fmt == 'JPEG' else '.webp' if fmt == 'WEBP' else img_path.suffix
        out = output_path / (img_path.stem + ext)

        with Image.open(img_path) as img:
            if img.mode in ('RGBA', 'P') and fmt == 'JPEG':
                img = img.convert('RGB')
            img.thumbnail(max_size, Image.LANCZOS)
            img.save(out, format=fmt, quality=85)

        print(f"[{i}/{len(images)}] {img_path.name} → {out.name}")

    print(f"\nDone! {len(images)} images processed.")

batch_resize('original_photos', 'resized_photos', max_size=(1200, 1200), fmt='WEBP')
Found 48 images in original_photos

[1/48] IMG_001.jpg → IMG_001.webp
[2/48] IMG_002.png → IMG_002.webp
...
[48/48] DSC_048.jpg → DSC_048.webp

Done! 48 images processed.
3

Add a text watermark

Stamp a copyright watermark on every image.

from PIL import ImageDraw, ImageFont

def add_watermark(img, text='© IT Expert Training'):
    draw = ImageDraw.Draw(img)
    # Use default font if custom font not available
    try:
        font = ImageFont.truetype('arial.ttf', size=max(16, img.width // 30))
    except:
        font = ImageFont.load_default()

    bbox  = draw.textbbox((0, 0), text, font=font)
    tw, th = bbox[2] - bbox[0], bbox[3] - bbox[1]

    # Bottom-right with padding
    x = img.width  - tw - 20
    y = img.height - th - 20

    # Shadow for readability
    draw.text((x+2, y+2), text, fill=(0, 0, 0, 128), font=font)
    draw.text((x,   y),   text, fill=(255, 255, 255, 200), font=font)
    return img

# Use in the batch loop:
# img = add_watermark(img, '© YourName 2026')
# img.save(out, ...)
💡 Tip: WebP format (fmt="WEBP") produces files 25-35% smaller than JPEG at the same quality — highly recommended for web images. All modern browsers support WebP.

🎉 You Did It!

Your batch processor handles hundreds of images in seconds. Combine resize + watermark + WebP conversion to prepare an entire photo library for the web in a single command.

Found something wrong?

Spotted a bug, broken code, or something that doesn't look right? Tell us what's off and we'll fix it.