This Python script converts images from one format to another in bulk while preserving EXIF metadata and maintaining quality. It’s particularly useful for photographers, content creators, or anyone needing to process large batches of images efficiently.
import os
from pathlib import Path
from PIL import Image, ExifTags
from typing import List, Tuple
import argparse
def convert_images(input_dir: str, output_dir: str,
input_format: str, output_format: str,
quality: int = 95) -> Tuple[int, int]:
"""
Convert images from one format to another while preserving EXIF metadata.
Args:
input_dir: Directory containing source images
output_dir: Directory to save converted images
input_format: Source format (e.g., 'jpg', 'png')
output_format: Target format (e.g., 'webp', 'png')
quality: Output quality (1-100, for formats that support it)
Returns:
Tuple of (converted_count, error_count)
"""
input_path = Path(input_dir)
output_path = Path(output_dir)
# Create output directory if it doesn't exist
output_path.mkdir(parents=True, exist_ok=True)
# Get all images with specified input format
image_files = list(input_path.glob(f"*.{input_format.lower()}"))
image_files.extend(input_path.glob(f"*.{input_format.upper()}"))
converted = 0
errors = 0
for img_file in image_files:
try:
# Open image and preserve EXIF data
with Image.open(img_file) as img:
# Handle transparency for formats that support it
if img.mode in ("RGBA", "LA") and output_format.lower() in ["jpg", "jpeg"]:
# Convert RGBA to RGB for JPEG (which doesn't support transparency)
background = Image.new("RGB", img.size, (255, 255, 255))
background.paste(img, mask=img.split()[-1] if img.mode == "RGBA" else None)
img = background
# Prepare output filename
output_filename = img_file.stem + f".{output_format.lower()}"
output_file = output_path / output_filename
# Handle EXIF data
exif_data = img.info.get('exif')
# Save with appropriate parameters
save_kwargs = {}
if output_format.lower() in ["jpg", "jpeg", "webp"]:
save_kwargs['quality'] = quality
save_kwargs['optimize'] = True
if exif_data:
save_kwargs['exif'] = exif_data
# Save converted image
img.save(output_file, **save_kwargs)
converted += 1
print(f"Converted: {img_file.name} -> {output_filename}")
except Exception as e:
print(f"Error converting {img_file.name}: {str(e)}")
errors += 1
return converted, errors
def main():
parser = argparse.ArgumentParser(description="Bulk convert image formats while preserving metadata")
parser.add_argument("input_dir", help="Input directory containing images")
parser.add_argument("output_dir", help="Output directory for converted images")
parser.add_argument("input_format", help="Source image format (jpg, png, etc.)")
parser.add_argument("output_format", help="Target image format (webp, png, etc.)")
parser.add_argument("--quality", type=int, default=95, help="Output quality (1-100, default: 95)")
args = parser.parse_args()
if not os.path.exists(args.input_dir):
print(f"Error: Input directory '{args.input_dir}' does not exist")
return
converted, errors = convert_images(
args.input_dir,
args.output_dir,
args.input_format,
args.output_format,
args.quality
)
print(f"\nConversion complete!")
print(f"Successfully converted: {converted}")
print(f"Errors: {errors}")
if __name__ == "__main__":
# Example usage without command line arguments:
# convert_images("./photos", "./webp_photos", "jpg", "webp", 90)
main()
This script converts batches of images from one format to another while preserving important metadata like EXIF data (camera settings, GPS coordinates, timestamps). It handles common edge cases like transparency conversion when switching to formats that don’t support it (like converting PNG with transparency to JPEG).
Key features:
Modern web development and content creation often requires converting images to more efficient formats like WebP while maintaining quality and metadata. This tool is especially valuable for:
pip install Pillow
python image_converter.py ./input_folder ./output_folder jpg webp --quality 90
if __name__ == "__main__"):
convert_images("./photos", "./webp_photos", "jpg", "webp", 90)
The script will process all images in the input directory matching the source format and save converted versions in the output directory, reporting conversion statistics when complete.