Looks at a directory hive, finds .JPGs with EXIF info, and sorts them in a new directory structure by camera model, year, month, and optionally, date. Imports EXIF.py and dirwalk.py in addition to standard Python modules.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133  | """
---------------------------------------------------------------------------------------------------
Filename:       PhotoLibrarian.py
Author:         Alex Harden
Release Date:   2007-03-26
Description:    Iterates through a directory tree, reading the EXIF data from each JPG. Parses the
                date/time from EXIF data, and copies the photo using the date/time value into a
                new camera/year/month-based tree.  Additional sort by day available.
Attributions:   Ideas and code borrowed from Chad Cooper's RenameCopyPhotos.py:
                http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/500266
                EXIF.py: http://sourceforge.net/projects/exif-py/
                Dirwalk.py borrowed from the ActiveState Python Cookbook:
                http://code.activestate.com/recipes/105873/
Changelog:      2007-03-26: Initial 1.0 release.
---------------------------------------------------------------------------------------------------
"""
import string, sys, traceback, datetime, time
import EXIF, os, shutil
import dirwalk
inputDir = 'D:/photos'          #root directory that will be parsed (includes subdirectories)
outputDir = 'D:/photolibrary'   #our output directory (should be present before script is run)
fileExt = '.JPG'                #restrict to JPGs (we need EXIF data)
dateSort = 0                    #additional directory per date? 1=yes, 0=no
pictureList = dirwalk.dirwalk(inputDir)
count = 0
def FilePic(myPicture,myOutputDir,myDateSort):
    """
    Files the specified picture in the OutputDir according to EXIF Camera Model and date:
    /myOutputDir
        /<EXIF Camera Model>
            /<year>
                /<month>
                    /<date>  (optional)
                        /<myPicture>
    """
    # Check for/make dirs for file to go into
    # If dir already exists, use it - if it doesn't exist, then create it
    try:
        f=open(myPicture, 'rb')
        tags=EXIF.process_file(f)
        myFilename=os.path.basename(myPicture)
        datestr = str(tags['EXIF DateTimeDigitized'])
        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
        h = tm.split(':')[0]  # hour
        min = tm.split(':')[1]  # minute
        s = tm.split(':')[2]  # second
        camera=str(tags['Image Model'])
        if os.path.isdir(myOutputDir + '/' + camera) != 1:
            os.mkdir(myOutputDir + '/' + camera)
        if os.path.isdir(myOutputDir + '/' + camera + '/' + y) != 1:
            os.mkdir(myOutputDir + '/' + camera + '/' + y)
        if os.path.isdir(myOutputDir + '/' + camera + '/' + y + '/' + m) != 1:
            os.mkdir(myOutputDir + '/' + camera + '/' + y + '/' + m)
        if dateSort:
            if os.path.isdir(myOutputDir + '/' + camera + '/' + y + '/' + m + '/' + d) != 1:
                os.mkdir(myOutputDir + '/' + camera + '/' + y + '/' + m + '/' + d)
        # Copy file, renaming it with new filename
        if myDateSort:
            myNewFilePath=myOutputDir + '/' + camera + '/' + y + '/' + m + '/' + d + '/' + myFilename
        else:
            myNewFilePath=myOutputDir + '/' + camera + '/' + y + '/' + m + '/' + myFilename
        print 'New File: %s' % (myNewFilePath)
        shutil.copyfile(myPicture,myNewFilePath)
            
        # Set modified time to date photo was digitized
        myCurrentTime = datetime.datetime.now()
        myCurrentTime = int(time.mktime(myCurrentTime.timetuple()))
        myDigitizedTime = datetime.datetime(int(y), int(m), int(d), int(h), int(min), int(s))
        myDigitizedTime = int(time.mktime(myDigitizedTime.timetuple()))
        myTimes=(myCurrentTime,myDigitizedTime)
        os.utime(myNewFilePath,myTimes)
    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
##### RUN #####
if __name__ == '__main__':
    start = time.clock()
    for picture in pictureList:
        if string.upper(picture[-4:]) == fileExt:
            FilePic(picture,outputDir,dateSort)                    
            count = count + 1
    finish = time.clock()
    
    print '\nProcessing done in ', Timer(start, finish)
    print 'Images processed: ', str(count)
 | 
    Tags: graphics
  
  
      
Download
Copy to clipboard