""" --------------------------------------------------------------------------------------------------- Filename: RenameCopyPhotos.py Author: Chad Cooper Date: 2006-09-11 Description: Iterates through a directory, reading the EXIF data from each jpg. Parses the date/time and focal length from EXIF data, renames the photo using the date/time and focal length. Copies photo to a directory based on the date, ie 2006/09/11. Adds date-related keywords to photo, determines by-line based on camera used, adds average RGB code of image as a tuple keyword. Changelog: 2006-09-11: Script finalized and out of testing. 2007-01-10: Everything wrapped into functions. Functions for adding by-line and date info keywords added. 2007-01-18: Added error handling to all functions and added Timer() function --------------------------------------------------------------------------------------------------- """ import string, time, sys, calendar, Image, traceback from time import localtime, strftime from IPTC import IPTCInfo import EXIF, os, shutil base = '/Users/chad/Pictures/testing' # base dir rawFolder = '/Users/chad/Pictures/exifImport' # dir where raw images from camera await import fileExt = '.JPG' filelist = os.listdir(rawFolder) count = 0 def RenameFile(base, filename, rawFolder): """ Grabs EXIF tags and renames file based on DateTimeDigitized tag info -------------------------------------------------------------------------- Inputs: base: Base directory for photos --> '/Users/chad/Pictures/testing' filename: Old filename of raw file from camera --> 'DSC_0001.jpg' rawFolder: Temp directory where images are transferred to from camera -------------------------------------------------------------------------- """ print 'Original filename: ', filename try: picNumber = filename[len(filename)-8:len(filename)-4] # Open file, get EXIF tags, get date string and focal length os.chdir(rawFolder) f = open(filename, 'rb') tags = EXIF.process_file(f) datestr = str(tags['EXIF DateTimeDigitized']) focalLen = str(tags['EXIF FocalLength']) # Start parsing EXIF tags we just grabbed datestr = datestr.split(' ') dt = datestr[0] # date tm = datestr[1] # time # Date y = dt.split(':')[0] # year if len(dt.split(':')[1]) < 2: # month m = str('0') + dt.split(':')[1] else: m = dt.split(':')[1] if len(dt.split(':')[2]) < 2: # day d = str('0') + dt.split(':')[2] else: d = dt.split(':')[2] # Time if int(tm.split(':')[0]) < 13: # hour hr = tm.split(':')[0] ampm = 'AM' elif int(tm.split(':')[0]) > 12: hr = (int(tm.split(':')[0]) - 12) ampm = 'PM' min = tm.split(':')[1] # minute sec = tm.split(':')[2] # second # Establish new filename in form of: # 0000_yyyy-mm-dd_hh-mm-ss_00mm.jpg newName = picNumber + '_' + dt.replace(':', '-') + '_' + tm.replace(':', '-') + '_' + focalLen + 'mm.jpg' except: tb = sys.exc_info()[2] tbinfo = traceback.format_tb(tb)[0] pymsg = "PYTHON ERRORS:\nTraceback Info:\n" + tbinfo + "\nError Info:\n " + \ str(sys.exc_type)+ ": " + str(sys.exc_value) + "\n" FilePic(rawFolder, base, filename, newName, y, m, d) AddDateInfoKeywords(rawFolder, filename, base, newName, y, m, d, hr, ampm) WriteByLine(base, newName, y, m, d) def FilePic(rawFolder, base, filename, newName, y, m, d): """ Files the input image according to date taken --> 2006/07/09 /Users /Chad /Pictures /2006 /07 /09 image goes here -------------------------------------------------------------------------- Inputs: rawFolder: Temp directory where images are transferred to from camera base: Base directory for photos --> '/Users/chad/Pictures/testing' filename: Old filename of raw file from camera --> 'DSC_0001.jpg' newName : New filename as result of RenameFile --> 0000_yyyy-mm-dd_hh-mm-ss_00mm.jpg y: Year from DateTimeDigitized Exif tag m: Month from DateTimeDigitized Exif tag d: Day from DateTimeDigitized Exif tag -------------------------------------------------------------------------- """ # Check for/make dirs for file to go into # If dir already exists, use it - if it doesn't exist, then create it try: if os.path.isdir(base + '/' + y) != 1: os.mkdir(base + '/' + y) if os.path.isdir(base + '/' + y + '/' + m) != 1: os.mkdir(base + '/' + y + '/' + m) if os.path.isdir(base + '/' + y + '/' + m + '/' + d) != 1: os.mkdir(base + '/' + y + '/' + m + '/' + d) # Copy file, renaming it with new filename shutil.copyfile(rawFolder + '/' + filename, base + '/' + y + '/' + m + '/' + d + '/' + newName) imageName = base + '/' + y + '/' + m + '/' + d + '/' + newName except: tb = sys.exc_info()[2] tbinfo = traceback.format_tb(tb)[0] pymsg = "PYTHON ERRORS:\nTraceback Info:\n" + tbinfo + "\nError Info:\n " + \ str(sys.exc_type)+ ": " + str(sys.exc_value) + "\n" print 'New home: ', imageName, '\n' def WriteByLine(base, newName, y, m, d): """ Writes author info to the IPTC metadata of jpeg. Does test on original filename to see which camera it came from, if Nikon, I took it with my D70; if HP, Will took it with his camera -------------------------------------------------------------------------- Inputs: base: Base directory for photos --> '/Users/chad/Pictures/testing' newName : New filename as result of RenameFile --> 0000_yyyy-mm-dd_hh-mm-ss_00mm.jpg y: Year from DateTimeDigitized Exif tag m: Month from DateTimeDigitized Exif tag d: Day from DateTimeDigitized Exif tag -------------------------------------------------------------------------- """ try: info = IPTCInfo(os.path.join(base, y, m, d, newName)) # Test to see who took the pic, depending on the camera if filename[:2] == 'HP': info.data['by-line'] = 'William L.R. Booher' info.data['keywords'] = ['taken by will'] elif filename[:3] == 'DSC': info.data['by-line'] = 'Chad D. Cooper' else: info.data['by-line'] = '' info.saveAs(os.path.join(base, y, m, d, newName)) except: tb = sys.exc_info()[2] tbinfo = traceback.format_tb(tb)[0] pymsg = "PYTHON ERRORS:\nTraceback Info:\n" + tbinfo + "\nError Info:\n " + \ str(sys.exc_type)+ ": " + str(sys.exc_value) + "\n" def AddDateInfoKeywords(rawFolder, filename, base, newName, y, m, d, hr, ampm): """ Adds keywords for year, month, and date image was take to jpegs Date data acquired from EXIF via exif.py module Adds them as a list appendage, as in: info.keyword.extend(['y'+y, 'm'+m, 'd'+d, dd]) -------------------------------------------------------------------------- Inputs: base: Base directory for photos --> '/Users/chad/Pictures/testing' newName : New filename as result of RenameFile --> 0000_yyyy-mm-dd_hh-mm-ss_00mm.jpg y: Year from DateTimeDigitized Exif tag m: Month from DateTimeDigitized Exif tag d: Day from DateTimeDigitized Exif tag -------------------------------------------------------------------------- """ try: info = IPTCInfo(os.path.join(base, y, m, d, newName)) # Day of week y = int(y) m = int(m) d = int(d) dd = calendar.weekday(y, m, d) dict = {0:'Monday',1:'Tuesday',2:'Wednesday',3:'Thursday',4:'Friday', 5:'Saturday',6:'Sunday'} day = dict[dd] # Friendly time of day tod = TimeOfDay(hr, ampm) # Average RGB value of pic rgb = 'rgb' + str(GetRgb(rawFolder, filename)) # Write our keywords to image info.keywords.extend(['y' + str(y), 'm' + str(m), 'd' + str(d), day, ampm, tod, rgb]) info.saveAs(os.path.join(base, str(y), str(m), str(d), newName)) except: tb = sys.exc_info()[2] tbinfo = traceback.format_tb(tb)[0] pymsg = "PYTHON ERRORS:\nTraceback Info:\n" + tbinfo + "\nError Info:\n " + \ str(sys.exc_type)+ ": " + str(sys.exc_value) + "\n" def TimeOfDay(hour, ampm): """ From 24 hour time, take the hour and create a human-friendly tag telling us what period of the day the photo was taken. Adapted from Dunstan Orchards PHP function at: http://1976design.com/blog/archive/2004/07/23/redesign-time-presentation/ -------------------------------------------------------------------------- Inputs: hour: Hour, in 24-hour format, our pic was shot -------------------------------------------------------------------------- """ try: if ampm == 'PM': hour = int(hour) + 12 else: hour = int(hour) # Get our human-friendly time of day if hour < 4: tod = 'the wee hours' elif hour >= 4 and hour <= 6: tod = 'terribly early in the morning' elif hour >=7 and hour <= 9: tod = 'early morning' elif hour == 10: tod = 'mid-morning' elif hour == 11: tod = 'late morning' elif hour ==12: tod = 'noon hour' elif hour >= 13 and hour <= 14: tod = 'early afternoon' elif hour >= 15 and hour <= 16: tod = 'mid=afternoon' elif hour == 17: tod = 'late afternoon' elif hour >= 18 and hour <= 19: tod = 'early evening' elif hour >= 20 and hour <= 21: tod = 'evening time' elif hour == 22: tod = 'late evening' elif hour == 23: tod = 'late at night' else: tod = '' return tod except: tb = sys.exc_info()[2] tbinfo = traceback.format_tb(tb)[0] pymsg = "PYTHON ERRORS:\nTraceback Info:\n" + tbinfo + "\nError Info:\n " + \ str(sys.exc_type)+ ": " + str(sys.exc_value) + "\n" def Timer(start, end): """ Calculates the time it takes to run a process, based on start and finish times --------------------------------------------------------------------------------------------- Inputs: start: Start time of process end: End time of process --------------------------------------------------------------------------------------------- """ elapsed = end - start # Convert process time, if needed if elapsed <= 59: time = str(round(elapsed,2)) + " seconds\n" if elapsed >= 60 and elapsed <= 3590: min = elapsed / 60 time = str(round(min,2)) + " minutes\n" if elapsed >= 3600: hour = elapsed / 3600 time = str(round(hour,2)) + " hours\n" return time def GetRgb(rawFolder, filename): """ Resizes the image down to one pixel in size, then returns a tuple of the RGB values of that pixel. Gives an average RGB value for our image. Might be good for something one day. --------------------------------------------------------------------------------------------- Inputs: rawFolder: Folder where our raw imported files are filename: Image we are processing --------------------------------------------------------------------------------------------- """ try: i=Image.open(os.path.join(rawFolder, filename)) rgb = i.quantize(1).convert('RGB').getpixel((0, 0)) return rgb except: tb = sys.exc_info()[2] tbinfo = traceback.format_tb(tb)[0] pymsg = "PYTHON ERRORS:\nTraceback Info:\n" + tbinfo + "\nError Info:\n " + \ str(sys.exc_type)+ ": " + str(sys.exc_value) + "\n" ##### RUN ##### if __name__ == '__main__': start = time.clock() for file in filelist: filename = os.path.basename(file) if filename[-4:] == fileExt: RenameFile(base, filename, rawFolder) count = count + 1 finish = time.clock() print '\nProcessing done in ', Timer(start, finish) print 'Images processed: ', str(count)