Images are often the largest component of web page weight. In 2026, using WebP format isn't optional—it's essential for building fast, modern websites. This guide shows you how to automate image optimization with Python scripts that convert PNG and JPG files to WebP, reducing file sizes by 25-35% on average while maintaining visual quality.
Why WebP Matters in 2026
WebP provides superior compression compared to traditional formats:
- 25-35% smaller than JPEG at the same quality
- 26% smaller than PNG for lossless compression
- Universal browser support (all modern browsers)
- Faster page loads = better SEO and user experience
Python Script for WebP Conversion
Here's a complete Python script that converts PNG and JPG images to WebP format automatically:
#!/usr/bin/env python3
"""
Convert PNG and JPG images to WebP format
Optimizes images for web performance in 2026
"""
import os
from pathlib import Path
from PIL import Image
import sys
def convert_to_webp(input_path, output_path=None, quality=85, lossless=False):
"""
Convert an image to WebP format.
Args:
input_path: Path to input image (PNG, JPG, etc.)
output_path: Path for output WebP file (optional)
quality: Quality for lossy compression (1-100)
lossless: Use lossless compression (for PNG with transparency)
Returns:
Tuple of (success: bool, original_size: int, new_size: int, savings: float)
"""
try:
# Open image
img = Image.open(input_path)
# Determine output path
if output_path is None:
output_path = str(Path(input_path).with_suffix('.webp'))
# Check if image has transparency (alpha channel)
has_transparency = img.mode in ('RGBA', 'LA') or 'transparency' in img.info
# Use lossless for images with transparency, lossy otherwise
save_kwargs = {
'format': 'WEBP',
'method': 6 # Best compression method
}
if has_transparency or lossless:
save_kwargs['lossless'] = True
else:
save_kwargs['quality'] = quality
# Save as WebP
img.save(output_path, **save_kwargs)
# Calculate file sizes
original_size = os.path.getsize(input_path)
new_size = os.path.getsize(output_path)
savings = ((original_size - new_size) / original_size) * 100
return True, original_size, new_size, savings
except Exception as e:
print(f"Error converting {input_path}: {e}", file=sys.stderr)
return False, 0, 0, 0
def optimize_directory(directory, quality=85, remove_originals=False):
"""
Convert all PNG and JPG images in a directory to WebP.
Args:
directory: Directory containing images
quality: Quality for lossy compression
remove_originals: Whether to delete original files after conversion
"""
directory = Path(directory)
image_extensions = {'.png', '.jpg', '.jpeg', '.PNG', '.JPG', '.JPEG'}
# Find all image files
image_files = [
f for f in directory.iterdir()
if f.is_file() and f.suffix in image_extensions
]
if not image_files:
print(f"No images found in {directory}")
return
print(f"Found {len(image_files)} images to convert...")
print()
converted = 0
skipped = 0
errors = 0
total_original_size = 0
total_new_size = 0
for img_file in image_files:
webp_path = img_file.with_suffix('.webp')
# Skip if WebP already exists and is newer
if webp_path.exists():
if webp_path.stat().st_mtime > img_file.stat().st_mtime:
skipped += 1
print(f"[SKIP] {img_file.name} - WebP already exists")
continue
# Convert to WebP
success, orig_size, new_size, savings = convert_to_webp(
str(img_file),
str(webp_path),
quality=quality
)
if success:
converted += 1
total_original_size += orig_size
total_new_size += new_size
print(f"[{converted}/{len(image_files)}] ✓ {img_file.name}")
print(f" {orig_size:,} bytes → {new_size:,} bytes ({savings:.1f}% smaller)")
# Remove original if requested
if remove_originals:
img_file.unlink()
print(f" Removed original: {img_file.name}")
else:
errors += 1
print(f"[ERROR] Failed to convert {img_file.name}")
print()
# Summary
print("=" * 60)
print("Conversion Summary:")
print(f" Converted: {converted}")
print(f" Skipped: {skipped}")
print(f" Errors: {errors}")
if converted > 0:
total_savings = ((total_original_size - total_new_size) / total_original_size) * 100
print(f" Total size reduction: {total_savings:.1f}%")
print(f" Space saved: {(total_original_size - total_new_size) / 1024 / 1024:.2f} MB")
if __name__ == '__main__':
import argparse
parser = argparse.ArgumentParser(
description='Convert PNG and JPG images to WebP format'
)
parser.add_argument(
'directory',
nargs='?',
default='images',
help='Directory containing images (default: images)'
)
parser.add_argument(
'-q', '--quality',
type=int,
default=85,
help='Quality for lossy compression (1-100, default: 85)'
)
parser.add_argument(
'-r', '--remove-originals',
action='store_true',
help='Remove original files after conversion'
)
args = parser.parse_args()
# Ensure directory exists
if not os.path.isdir(args.directory):
print(f"Error: Directory '{args.directory}' does not exist")
sys.exit(1)
optimize_directory(
args.directory,
quality=args.quality,
remove_originals=args.remove_originals
)
How to Use the Script
First, install the required Python library:
pip install Pillow
Then run the script:
# Convert all images in the 'images' directory
python convert_to_webp.py images
# Use custom quality (higher = better quality, larger file)
python convert_to_webp.py images --quality 90
# Remove original files after conversion (be careful!)
python convert_to_webp.py images --remove-originals
Updating HTML to Use WebP
After converting images, update your HTML to use WebP with fallbacks for older browsers:
<picture>
<source srcset="image.webp" type="image/webp">
<img src="image.jpg" alt="Description">
</picture>
Advanced: Batch HTML Update Script
Here's a Python script to automatically update all HTML files to reference WebP images:
#!/usr/bin/env python3
"""
Update HTML files to use WebP images with fallbacks
"""
import re
from pathlib import Path
def update_html_to_webp(html_file):
"""Update image references in HTML to use WebP with fallbacks."""
with open(html_file, 'r', encoding='utf-8') as f:
content = f.read()
# Pattern to match img tags
img_pattern = r'<img\s+([^>]*src=["\']([^"\']+)\.(jpg|jpeg|png)(["\'])([^>]*)>'
def replace_img(match):
attrs = match.group(1) + match.group(5)
src = match.group(2)
ext = match.group(3)
quote = match.group(4)
# Skip if already has picture tag or is already WebP
if 'picture' in attrs.lower() or '.webp' in src:
return match.group(0)
# Build picture tag with WebP source and fallback
webp_src = f"{src}.webp"
original_src = f"{src}.{ext}"
return f'''<picture>
<source srcset="{webp_src}" type="image/webp">
<img {attrs}src="{original_src}"{quote}>
</picture>'''
updated_content = re.sub(img_pattern, replace_img, content, flags=re.IGNORECASE)
if updated_content != content:
with open(html_file, 'w', encoding='utf-8') as f:
f.write(updated_content)
return True
return False
# Update all HTML files in current directory
html_files = list(Path('.').glob('*.html'))
updated = 0
for html_file in html_files:
if update_html_to_webp(html_file):
print(f"Updated: {html_file}")
updated += 1
print(f"\nUpdated {updated} HTML file(s)")
Best Practices for 2026
- Use quality 85-90 for most images (good balance of size and quality)
- Use lossless for images with transparency or when quality is critical
- Always provide fallbacks for older browsers using <picture> tags
- Optimize during build - automate conversion in your deployment pipeline
- Monitor file sizes - track your image optimization savings
Real-World Results
In my experience optimizing websites, WebP conversion typically results in:
- 30-40% reduction in total page weight
- 1-2 second improvement in page load times
- Better Core Web Vitals scores (LCP, FID, CLS)
- Improved SEO rankings due to faster page speeds
Conclusion
WebP optimization is no longer optional in 2026. With these Python scripts, you can automate the entire process of converting images and updating your HTML. The result? Faster websites, better user experience, and improved SEO performance.
Start optimizing your images today—your users (and Google) will thank you.
Related Articles:
← Modern Web Development: Best Practices for 2024