I had some free time the other day and decided I wanted to try to start learning Python. I had a need for it too: My usual protocol for sorting new photos for archiving was becoming a bit tiresome. So I read a few tutorials and started writing a script to read the EXIF data and put the photos in folders by year > month > camera model.
One byproduct of this little venture was that I saw some of my old photos and started getting excited about them. I knew there was a reason I’d saved all that crap! (Currently, there are 70,965 photos in the archive.) Here is a month’s worth, spiced up a bit in the contrast and cropping departments via Photoshop.
By the way, here’s the code:
# import logging module
import logging
# configure logging
logging.basicConfig(filename='AndrePhotoSort--LOG.log', format='%(asctime)s %(levelname)s %(message)s', datefmt='%m/%d/%Y %I:%M:%S %p', filemode='w', level=logging.INFO)
# start message
logging.info('Started sorting photos\n')
# get operating system functions like listing files in directory and making directories
import os
# get the current directory (__file__ is this module)
current_directory = os.path.dirname(os.path.abspath(__file__))
# get a list of files in the current directory
file_list = os.listdir(current_directory)
# initialize a list for jpg files only
photos = []
# put jpg files only in the directory
for file in file_list:
# check file extension to see if file is a jpg (the lower() method converts the filename to lowercase for files with .JPG extensions)
if file.lower().endswith('.jpg'):
# if file is a jpg, add it do the photos list
photos.append(file)
# count photo files
photo_count = str(len(photos))
# count files and send message to log
logging.info('Number of photos to be sorted: ' + photo_count + '\n')
# import modules
import PIL.Image # for working with images
import PIL.ExifTags # for reading exif data in images
import string # for replacing problematic characters in exif strings
from datetime import datetime # for getting data from camera datetime strings
from shutil import copyfile # for making a copy of the photo and putting it in a new directory
# loop through each of the entries in the list of photos
for idx, photo_file in enumerate(photos):
# output for console
print("Moving file " + str(idx + 1) + " of " + str(len(photos)) + ": " + str(photo_file))
# open the photo
img = PIL.Image.open(photo_file)
# exif dictionary indexed by exif string names
exif = {
PIL.ExifTags.TAGS[k]: v
for k, v in img._getexif().items()
if k in PIL.ExifTags.TAGS
}
if exif.has_key('Make') and exif.has_key('Model') and exif.has_key('DateTimeOriginal'):
# get the camera model exif data, cast it as a string, get rid of problematic characters, and strip trailing null bytes
camera_make = str(exif['Make'])
camera_make = string.replace(camera_make, '/', ' ')
camera_make = string.replace(camera_make, '.', ' ')
camera_make = string.replace(camera_make, ' ', ' ')
camera_make = camera_make.rstrip('\0')
# get the camera model exif data, cast it as a string, get rid of problematic characters, and strip trailing null bytes
camera_model = str(exif['Model'])
camera_model = string.replace(camera_model, '/', ' ')
camera_model = string.replace(camera_model, '.', ' ')
camera_model = string.replace(camera_model, ' ', ' ')
camera_model = camera_model.rstrip('\0')
# convert the exif DateTimeOriginal string (AKA, Date Taken) and convert it into a datetime object
date_taken = datetime.strptime(exif['DateTimeOriginal'], '%Y:%m:%d %H:%M:%S')
# get the year the photo was taken
photo_year = str(date_taken.year)
# get the month the photo was taken
photo_month = str(date_taken.month).zfill(2)
# build path string for destination directory
destination_directory = os.path.join(current_directory, photo_year, photo_month, (camera_make + ' - ' + camera_model))
# check to see if destination directory exists
if not (os.path.isdir(destination_directory)):
# if it doesn't, make it
os.makedirs(destination_directory)
# copy the file to the new directory
copyfile(os.path.join(current_directory, photo_file), os.path.join(destination_directory, photo_file))
# send message to log
logging.info('Moved ' + photo_file + ' to ' + destination_directory)
else:
# build path string for destination directory
destination_directory = current_directory + '\\NO EXIF DATA\\'
# check to see if destination directory exists
if not (os.path.isdir(destination_directory)):
# if it doesn't, make it
os.makedirs(destination_directory)
copyfile(current_directory + '\\' + photo_file, destination_directory + '\\' + photo_file)
logging.info('Moved ' + photo_file + ' to .\\NO EXIF DATA\\')
if (int(photo_count) == (idx + 1)):
logging.info('All ' + photo_count + ' photos were copied to a new directory\n')
else:
logging.warning('ONE OR MORE OF THE FILES WAS NOT COPIED TO A NEW DIRECTORY!\n')
logging.info('Finished sorting photos')