__version__ = "$Rev$" __date__ = "$Date$" __author = "$Author$" import os import sys import re # PIL import Image import getopt import time import pickle #for copying import shutil head = """ Pictures

Up a directory

""" footer = """

""" if len(sys.argv) == 1: print __version__ print "Usage:", sys.argv[0], " [option] directory" print "Options:" print " -f list supported file formats" print " -a set authorative times" print " -i show associated info and tile data" print " -v verify file headers" print " -s store filename" print " -t make thumb/" print " -w where to output" print " -q quiet, don't warn for unidentified/missing/broken files" sys.exit(1) try: opt, argv = getopt.getopt(sys.argv[1:], "tafqivw:s:D") except getopt.error, v: print v sys.exit(1) thumb = do_auth = verbose = quiet = verify = 0 whereto = '' store = '' for o, a in opt: if o == "-f": Image.init() id = Image.ID[:] id.sort() print "Supported formats:" for i in id: print i, sys.exit(1) elif o == "-a": do_auth = 1 elif o == "-i": verbose = 1 elif o == "-q": quiet = 1 elif o == "-t": thumb = 1 elif o == "-s": store = a elif o == "-w": whereto = a elif o == "-v": verify = 1 elif o == "-D": Image.DEBUG = Image.DEBUG + 1 class picture(dict): "store info of Kai's pictures" def __init__(self, file): "parse interesting stuff" self.clear() try: # TODO: Fix for exception self["order"] = get_index(file) if not quiet: print self["order"], # holding directory usually describes pictures self["abstract"] = os.path.split(os.path.split(file)[0])[1] self["mtime"] = os.stat(file)[8] im = Image.open(file) # EXPERIMENTAL exif = im._getexif() if exif: try: self["exiftime"] = time.mktime(time.strptime("%s" % exif[36867], '%Y:%m:%d %H:%M:%S')) except: print exif print "EXIF PARSE ERROR" self["exiftime"] = None else: if not quiet: print file, "failed for exif-time" self["exiftime"] = None self["size"] = im.__dict__["size"] self["filename"] = im.__dict__["filename"] except AttributeError: if not quiet: print file, "has invalid index in filename" except IOError, v: if not quiet: print file, "failed:", v def __str__(self): return "\n".join(["%s=%s" % (k, get_time(v)) for k, v in self.items() if 'time' in k]) + '\n' + \ "\n".join(["%s=%s" % (k, v) for k, v in self.items() if 'time' not in k]) + '\n' def set_mtime(self): self["authtime"] = self["mtime"] if not quiet: print "Set mtime" print self def set_exiftime(self): self["authtime"] = self["exiftime"] if not quiet: print "Set exiftime" print self def interactive(self, lasttime, nexttime): print self prompt = """ 1 Set as lasttime %s 2 Set as nexttime %s 3 Set as mtime %s 4 Set as exiftime %s """ % tuple(map(get_time, (lasttime, nexttime, self["mtime"], self["exiftime"]))) print prompt print "[1,2,3,4] ", input = sys.stdin.readline() try: if input == '\n': # last time is default if user smacks enter return 1 input = int(input) if input == 1: return 1 elif input == 2: return 2 elif input == 3: return 3 elif input == 4: return 4 else: self.interactive(lasttime, nexttime) except: self.interactive(lasttime, nexttime) def get_index(filename): index = 0 try: index = int(re.search('DCP_\d+', filename).group()[4:]) except: if not quiet: print "Invalid index:", filename return index def get_time(secs): if secs: return time.ctime(secs) else: return "No time" class pictures(list): def __init__(self): self.archivelist = [] self.skipped = [] def add_dir(self, dir): filenames = os.listdir(dir) filenames.sort() subdirs = [] for filename in filenames: pathname = os.path.join(dir, filename) if self.VALID_ARCHIVE(filename): self.archivelist.append(pathname) if os.path.isfile(pathname): self.add_file(pathname) if os.path.isdir(pathname): subdirs.append(pathname) map(self.add_dir, subdirs) def process_archives(self): import tarfile # Expensive gz to end for a in self.archivelist: if 'gz' in a: self.archivelist.remove(a) self.archivelist.append(a) # Get expensive bz2 to end for a in self.archivelist: if 'bz2' in a: self.archivelist.remove(a) self.archivelist.append(a) for a in self.archivelist: if not quiet: print "Opening archive:", a openarchive = tarfile.open(a, 'r') for f in openarchive: if self.NEW_PICTURE(f.name): openarchive.extract(f,'/tmp') pathname = os.path.join('/tmp', f.name) print len(self), "Adding:", pathname, "from archive", a self.append(picture(pathname)) def add_file(self, pathname): """ Check if the file is an image and check if not already in the filelist """ if self.NEW_PICTURE(pathname): print len(self), "Adding:", pathname self.append(picture(os.path.abspath(pathname))) def NEW_PICTURE(self, name): name = os.path.split(name)[1] if re.search("^DCP_\d{4}\.JPG$", name): index = get_index(name) if index: if index not in [i["order"] for i in self]: return 1 else: if not quiet: print "Not new:", index, name else: self.skipped.append((0,os.path.abspath(name))) elif re.search("\.(png|jpg)$", name, re.I): self.skipped.append(name) else: if not quiet: print "Skipping:", name def VALID_ARCHIVE(self, name): if re.search("\.(tar|tar.gz|tar.bz2)$", name, re.I): return 1 def next_time(self, lasttime, n): """ Seeks ahead from n to find an exif time greater than last time """ for p in self[n:]: if "exiftime" in p: if p["exiftime"] > lasttime: return p["exiftime"] def authorative(self): """ Setup authorative time """ self.sort_byorder() n = 0 lasttime = 0 lastans = ['',0] for p in self: #print n+1 nexttime = self.next_time(lasttime, n) if "authtime" not in p and "exiftime" in p: if p["exiftime"] >= lasttime: p.set_exiftime() elif p["mtime"] > lasttime and p["mtime"] < nexttime: p.set_mtime() else: if p["abstract"] == lastans[0] and nexttime: ans = lastans[1] print "ASSUMING", lastans # grouped by dir aka abstract else: ans = p.interactive(lasttime, nexttime) if ans == 1: p["authtime"] = lasttime elif ans == 2: p["authtime"] = nexttime elif ans == 3: if p["mtime"] < lasttime: print "MTIME IS LESS THAN LAST TIME!" if p["mtime"] > nexttime: print "MTIME IS MORE THAN NEXT TIME!" p.set_mtime() elif ans == 4: p.set_exiftime() else: raise lastans = (p["abstract"], ans) lasttime = p["authtime"] n = n + 1 def sort_byorder(self): o = zip([i["order"] for i in self], self) o.sort() self[:] = [j for i,j in o] def pngthumbgen(self, where): """ Generate PNG thumbnail """ for p in self: if "thumb" not in p and "copyto" in p: pathtoimage = os.path.abspath(os.path.join(where, p["copyto"])) pathtothumb = os.path.join('thumb', p["copyto"]) path = os.path.split(pathtothumb)[0] try: if not os.path.exists(path): print "Creating", path os.makedirs(path) im = Image.open(pathtoimage) # Open original image im.thumbnail((128,128)) # Generate thumb im.save(pathtothumb, "PNG") im = None p["thumb"] = 1 except IOError, v: if not quiet: print pathtoimage, "failed:", v def copy_in(self, where): """ Copy files into new pictures directory structure according to authorative time """ for i in self: if "authtime" in i and "copyto" not in i: print i i["copyto"] = time.strftime("%Y/%m/%d/", time.gmtime(i["authtime"])) + os.path.split(i["filename"])[1] print "Copy:", print i["filename"], "to", print i["copyto"] filename = os.path.join(os.path.abspath(where), i["copyto"]) path = os.path.split(filename)[0] try: if not os.path.exists(path): print "Creating", path os.makedirs(path) shutil.copy2(i["filename"], filename) except IOError, e: raise e def htmlgen(self): output = '' lastdir = '' for p in self: if "thumb" in p: writedir = os.path.split(p["copyto"])[0] if writedir != lastdir: file = open('thumb/' + lastdir + '/index.shtml', 'w') file.write(head + output + footer) file.close() output = '' lastdir = writedir output += '%s\n' % (p["copyto"], p["abstract"], p["copyto"]) file = open('thumb/' + lastdir + '/index.shtml', 'w') file.write(head + output + footer) file.close() def main(): print "PROCESSING COLLECTION", store try: s = open(store) coll = pickle.load(s) s.close() except: coll = pictures() if argv: for a in argv: coll.add_dir(a) if coll.archivelist: print "Archives:", coll.archivelist coll.process_archives() coll.archivelist = [] print len(coll), "picture(s) in collection" print len(coll.skipped), "picture(s) skipped" if do_auth: coll.authorative() if whereto: copyto = os.path.abspath(whereto) coll.copy_in(copyto) if thumb: coll.pngthumbgen(copyto) coll.htmlgen() if store: s = open(store, 'w') pickle.dump(coll, s) s.flush() s.close() print "Wrote:", store, "with", len(coll), "records" if __name__ == "__main__": main()