A script that resizes, converts, watermarks, and renames an entire folder of images in one command — handling hundreds of files in seconds.
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)
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.
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, ...)
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.
Spotted a bug, broken code, or something that doesn't look right? Tell us what's off and we'll fix it.