Python script to rename files based on EXIF 'Created on'
This script will rename files in a specified directory based on the EXIF “Created on” date.
How to use
# To just print what would be done, without actually renaming the files:
python exifrename.py <directory> --dry-run
# To rename the files:
python exifrename.py <directory>
Example:
Renaming: IMG_5198.JPG -> campchyoca/14/2021-07-03_07-47-04-IMG_5198.JPG
Full source code
#!/usr/bin/env python3
import os
import argparse
from pathlib import Path
from PIL import Image, ExifTags
from datetime import datetime
def get_exif_creation_date(file_path):
"""Retrieve the EXIF creation date from an image file."""
try:
with Image.open(file_path) as img:
exif = img._getexif()
if exif is not None:
for tag, value in exif.items():
decoded_tag = ExifTags.TAGS.get(tag, tag)
if decoded_tag == "DateTimeOriginal":
return value
except Exception as e:
print(f"Error reading EXIF data from {file_path}: {e}")
return None
def format_filename(date_string, original_name):
"""Format the filename with the date and original name."""
try:
date_object = datetime.strptime(date_string, "%Y:%m:%d %H:%M:%S")
formatted_date = date_object.strftime("%Y-%m-%d_%H-%M-%S")
return f"{formatted_date}-{original_name}"
except ValueError:
print(f"Invalid date format for {original_name}: {date_string}")
return None
def ensure_unique_filename(directory, filename):
"""Ensure the filename is unique within the directory by appending a counter if necessary."""
base, ext = os.path.splitext(filename)
counter = 1
while (directory / filename).exists():
filename = f"{base}.{counter}{ext}"
counter += 1
return filename
def exif_rename_files(directory, dry_run, recursive=False):
"""Rename files in the specified directory based on their EXIF creation date."""
# Process files in current directory
for file in directory.iterdir():
if file.is_file():
exif_date = get_exif_creation_date(file)
if exif_date:
new_name = format_filename(exif_date, file.name)
if new_name:
# Check if the formatted date is already in the filename
date_object = datetime.strptime(exif_date, "%Y:%m:%d %H:%M:%S")
formatted_date = date_object.strftime("%Y-%m-%d_%H-%M-%S")
if formatted_date in file.name:
print(f"Skipping: {file} (already contains EXIF date)")
continue
unique_name = ensure_unique_filename(directory, new_name)
new_path = directory / unique_name
if dry_run:
print(f"Would rename: {file} -> {new_path}")
else:
print(f"Renaming: {file} -> {new_path}")
file.rename(new_path)
# Process subdirectories if recursive option is enabled
if recursive:
for subdir in directory.iterdir():
if subdir.is_dir():
print(f"Processing subdirectory: {subdir}")
exif_rename_files(subdir, dry_run, recursive)
def main():
parser = argparse.ArgumentParser(description="Rename files based on EXIF creation date.")
parser.add_argument("directory", type=Path, help="Directory containing files to rename.")
parser.add_argument("--dry-run", action="store_true", help="Show what would be done without making changes.")
parser.add_argument("-r", "--recursive", action="store_true", help="Process subdirectories recursively.")
args = parser.parse_args()
if not args.directory.is_dir():
print(f"Error: {args.directory} is not a valid directory.")
return
exif_rename_files(args.directory, args.dry_run, args.recursive)
if __name__ == "__main__":
main()
If this post helped you, please consider buying me a coffee or donating via PayPal to support research & publishing of new posts on TechOverflow