Skip to content

Instantly share code, notes, and snippets.

@Tojaj
Created February 22, 2020 18:15
Show Gist options
  • Save Tojaj/1352245c1a2293400a91d00dd2487d58 to your computer and use it in GitHub Desktop.
Save Tojaj/1352245c1a2293400a91d00dd2487d58 to your computer and use it in GitHub Desktop.
Rename jpeg files in a directory based on the date &time in EXIF metadata
#!/usr/bin/env python3
import os
import os.path
import datetime
import argparse
from PIL import Image
EXIF_TAG_DATETIME = 306 # When taken or last edited
EXIF_TAG_DATETIMEORIGINAL = 36867 # When taken
#EXIF_TAG_DATETIMEDIGITIZED = 36868 # When stored as digital data
EXIF_TAG_SUBSECTIMEORIGINAL = 37521 # Franctions of secs for DateTimeOriginal
JPEG_SUFFIX = ".jpg"
def get_exif(filename):
"""Get dict with EXIF data"""
image = Image.open(filename)
image.verify()
return image._getexif()
def get_datetime(exif):
"""Return datetime python object for date time data from EXIF"""
# EXIF data time format example: "2019:12:22 16:52:40"
if EXIF_TAG_DATETIMEORIGINAL in exif:
raw_date_time = exif[EXIF_TAG_DATETIMEORIGINAL]
elif EXIF_TAG_DATETIME in exif:
raw_date_time = exif[EXIF_TAG_DATETIME]
else:
return None
return datetime.datetime.strptime(raw_date_time, "%Y:%m:%d %H:%M:%S")
def rename(directory, test=False):
"""Rename file in the directory"""
files = sorted(os.listdir(directory))
mapping = {}
for fn in files:
if not fn.endswith((".jpg", ".JPG", ".jpeg", ".JPEG")):
print("Skipping non JPEG file: {}".format(fn))
continue
filename = os.path.join(directory, fn)
exif = get_exif(filename)
dtobj = get_datetime(exif)
# Pick new filename
fn_prefix = os.path.join(
directory,
dtobj.strftime("%Y%m%d_%H%M%S")
)
newfn = fn_prefix + JPEG_SUFFIX
if filename == newfn:
# Nothing to do
continue
# If the file already exists, increment counter
i = 1
while os.path.exists(newfn):
newfn = fn_prefix + "_" + str(i) + JPEG_SUFFIX
i += 1
mapping[filename] = newfn
if not mapping:
print("Nothing to do")
return
if test:
print("Test mode used, printing what would be done...")
else:
print("Renaming...")
for src, dest in mapping.items():
print("{} -> {}".format(src, dest))
if not test:
os.rename(src, dest)
if test:
print("Test mode used, no rename was done!")
if __name__ == "__main__":
parser = argparse.ArgumentParser(
description="Rename jpeg files to YYYYMMDD-HHMMSS[-X].jpg " \
"format based on date &time data in EXIF metadata."
)
parser.add_argument(
"directory",
metavar="DIRECTORY",
help="Directory where to rename the files."
)
parser.add_argument(
"-t", "--test",
action="store_true",
help="Just print what would be done"
)
args = parser.parse_args()
# Check args
if not os.path.isdir(args.directory):
parser.error(f"{args.directory} is not a directory!")
rename(args.directory, test=args.test)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment