#!/usr/local/bin/python2.2
## ===========================================================================
##  Exiftool is freeware by Robert F. Tobler <rft@cg.tuwien.ac.at>.
##  No warrenties whatsoever on the usefulness for whatever purpose.
##  However if the tool is useful to you, you have improvements or
##  suggestions, or if you just like it, I would appreciate feedback.
## ===========================================================================
##  NAME:       exiftool
##  TYPE:       python script
##  CONTENT:    decode EXIF header in JPEGs from digital cameras
## ===========================================================================
##  AUTHORS:    rft     Robert F. Tobler <rft@cg.tuwien.ac.at>
## ===========================================================================
##  HISTORY:
##
##  10-Aug-01 11:16:19  rft     added binary option
##  31-Jul-01 11:23:48  rft     added byte-swap (DImage 7), E995 MakerNote
##  10-May-00 14:12:42  rft     created
## ===========================================================================
##  MANUAL:
##
##  NAME
##      exiftool, decode EXIF headers in JPEGs from digital cameras
##
##  SYNOPSIS
##      exiftool [options] <jpeg-1> <jpeg-2> ...
##
##  DESCRIPTION
##      Most digital cameras store additional information about each image
##      directly within each JPEG file. This inforation is located in the
##      so-called EXIF-header and contains such things as exposure time,
##      f-stop, aso. This tool decodes this information and prints the
##      informat, stores it in a HTML file, or renames the jpeg file
##      according to the date and time the image was taken.
##
##  OPTIONS
##      -d              Print debug output. This is most useful together with
##                      verbose output (-v). It reports the offset of each
##                      directory and data entry within the EXIF header.
##
##      -h              A short help page.
##
##      -i              Prints the tags of each JPEG according to a text
##                      template file that can be specified with the -t
##                      option.
##
##      -n              No action. Do not rename files or generate HTML
##                      files, just report intended actions.
##
##      -m              Print this manual.
##
##      -o <directory>  Specify the output directory where renamed files
##                      or HTML files should be placed. In this case, the
##                      rename option will actually copy the files, leaving
##                      the originals intact.
##
##      -r              Rename files according to exif date
##
##      -t <file>       Take file contents as a template for either HTML
##                      files (if the file has an extension of '.html',
##                      '.HTML', '.htm', or '.HTM') or as a template for
##                      the info text used by the -i option otherwise.
##                      Within the template, the value of a tag can be
##                      printed by using the following syntax:
##
##                              %(<tagname>)s
##
##                      e.g. %(Model)s will report the camera model which
##                      produced the JPEG file. For a list of the tagnames
##                      that can be used, you can use the -v option.
##
##      -v              Verbose output. This reports all EXIF tags that are
##                      found in each JPEG.
##
##      -w              Writes a HTML file for each JPEG according to a
##                      template file that can be specified with the -t
##                      option.
##
##      -b              Binary option: mostly for debugging the exif library.
##
##  AUTHOR
##      Robert F. Tobler <rft@cg.tuwien.ac.at>
##
## ===========================================================================

import sys
import os
import string
import struct
import time
import shutil
from stat import *

import exif

## ---------------------------------------------------------------------------
def print_manual_and_exit():
    script = open(sys.argv[0],'r')
    line = script.readline()
    while (line[0:11] != '##  MANUAL:'):
        line = script.readline()
    line = script.readline()
    while (line[0:11] != '## ========'):
        if line[0:2] == '##':
            sys.stdout.write('  ' + line[2:])
        else:
            sys.stdout.write(line)
        line = script.readline()
    script.close()
    sys.exit(0)

## ---------------------------------------------------------------------------
def write_file_format(file_name, format, map):
    file = open(file_name, "w")
    file.write(format % map)
    file.close()

## ---------------------------------------------------------------------------
def read_file(path):
    try:
	file = open(path, "rb")
	data = file.read()
	file.close()
    except IOError:
    	print "ERROR: could not read file '%s'!" % path_name
	sys.exit(-1)
    return data

## ---------------------------------------------------------------------------
##  In order to print the exif header with a % format string, even when some
##  of the tags are missing, we use a PrintMap which returns 'unknown' for
##  all missing tags.
## ---------------------------------------------------------------------------
class PrintMap:
    def __init__(self, map):
    	self.map = map
    def __getitem__(self, key):
    	val = self.map.get(key)
	if val == None:
	    val = 'unknown'
    	return val

## ---------------------------------------------------------------------------
##  This function creates a filename from the date as it is read in the
##  exif header. In Nikon and Sony jpegs the format is: yyyy:mm:dd hh:mm:ss.
## ---------------------------------------------------------------------------
def date_name(date_str):
    return  date_str[:4] +'.'+ date_str[5:7] +'.'+ date_str[8:10] +'-'+\
    	    date_str[11:13] +'.'+ date_str[14:16] +'.'+ date_str[17:19]

## ---------------------------------------------------------------------------
##  'TEXT_FORMAT'
##  	This is the default template for printing EXIF information with the
##  	-i option.
## ---------------------------------------------------------------------------
TEXT_FORMAT = """__________________________________________
        Photo Name: %(PhotoName)s
            Camera: %(Make)s %(Model)s
              Date: %(DateTime)s
     Exposure Time: %(ExposureTime)s sec
          Aperture: f/%(FNumber)s
  Exposure Program: %(ExposureProgram)s
     Exposure Bias: %(ExposureBiasValue)s
     Metering Mode: %(MeteringMode)s
             Flash: %(Flash)s
       FocalLength: %(FocalLength)s mm
"""

## ---------------------------------------------------------------------------
##  'HTML_FORMAT'
##  	This is the default template for generating HTML files containing
##  	EXIF information with the -w option.
## ---------------------------------------------------------------------------
HTML_FORMAT = """<html>
<head>
    <title>%(PhotoName)s / Info</title>
</head>
<body bgcolor="#000000" text="#DDDDDD" link="#0077FF" vlink="#00BBFF">
<h2>%(PhotoName)s</h2>
<table align=left border=1 cellspacing=1>
    <tr><td align=right>Camera</td>
	<td align=left>%(Make)s %(Model)s</td></tr>
    <tr><td align=right>Date</td>
	<td align=left>%(DateTime)s</td></tr>
    <tr><td align=right>Exposure Time</td>
	<td align=left>%(ExposureTime)s sec</td></tr>
    <tr><td align=right>Aperture</td>
	<td align=left>f/%(FNumber)s</td></tr>
    <tr><td align=right>Exposure Program</td>
	<td align=left>%(ExposureProgram)s</td></tr>
    <tr><td align=right>Exposure Bias</td>
	<td align=left>%(ExposureBiasValue)s</td></tr>
    <tr><td align=right>Metering Mode</td>
	<td align=left>%(MeteringMode)s</td></tr>
    <tr><td align=right>Flash</td>
	<td align=left>%(Flash)s</td></tr>
    <tr><td align=right>Focal Length</td>
	<td align=left>%(FocalLength)s mm</td></tr>
</table>
</body>
</html>
"""

## ---------------------------------------------------------------------------
def print_usage_and_exit():
    print "USAGE:  exiftool [opts] <jpg-1> ... <jpg-n>"
    print "OPTS:   -h           this help page"
    print "        -m           print manual page. use 'exiftool -m | less'"
    print "        -d           debug output"
    print "        -i           print info for each jpeg file"
    print "        -n           no action"
    print "        -o <dir>     specify output directory; copy not rename"
    print "        -r           rename files according to exif date"
    print "        -t <file>    text or html template file (extension!)"
    print "        -v           verbose output, prints all tags"
    print "        -w           write a html file for each jpeg file"
    print "        -b           binary option for debugging exif library"
    print "NOTE:   You have to specify at least one of: -i -r -w -v -d!"
    print "        If no JPEGs are specified, all JPEGs in the current",
    print "dir are taken."
    sys.exit(-1)

## ---------------------------------------------------------------------------
try:
    help_opt	= 0
    debug_opt	= 0
    verbose_opt = 0
    write_opt	= 0
    rename_opt	= 0
    info_opt	= 0
    noact_opt	= 0
    outdir_par	= ''
    mode_opt = 0

    file_list = []

    act = 0
    argc = len(sys.argv)
    i = 0
    while i+1 < argc:
    	i = i+1
	arg = sys.argv[i]
    	if arg == '-h':     print_usage_and_exit()
    	if arg == '-m':     print_manual_and_exit()
	if arg == '-d':     debug_opt = 1 ; 	act = 1 ;    	continue
	if arg == '-v':     verbose_opt = 1 ;	act = 1 ;    	continue
    	if arg == '-w':     write_opt = 1 ; 	act = 1 ; 	continue
    	if arg == '-r':     rename_opt = 1 ; 	act = 1 ;   	continue
    	if arg == '-i':     info_opt = 1 ; 	act = 1 ;   	continue
    	if arg == '-n':     noact_opt = 1 ; 	    	    	continue
    	if arg == '-b':     mode_opt = exif.BINARY ;	    	continue
    	if arg == '-o':
	    if i+1 < argc: i = i+1 ; outdir_par = sys.argv[i] ; continue
	    print "ERROR: no directory for option '-d'!"
	    sys.exit(-1)
	if arg == '-t':
	    if i+1 < argc:
	    	i = i+1
		t_par = sys.argv[i]
		(t_name, t_ext) = os.path.splitext(t_par)
		if  t_ext == '.html' or t_ext == '.HTML' \
		     or t_ext == '.htm' or t_ext == '.HTM':
		    HTML_FORMAT = read_file(t_par)
		else:
		    TEXT_FORMAT = read_file(t_par)
		continue
	    print "ERROR: no template file for option '-t'!"
	    sys.exit(-1)
	if arg[0] == '-':
	    print "ERROR: unknown option '%s'!" % arg
	    sys.exit(-1)
    	file_list.append(arg)

    if debug_opt: verbose_opt = 255

    if outdir_par and not os.path.isdir(outdir_par):
    	print "ERROR: '%s' is not directory!" % outdir_par
	sys.exit(-1)

    if not act: print_usage_and_exit()

    if len(file_list) == 0:
    	file_list = os.listdir('.')

    for path_name in file_list:
	(dir_name, jpeg_name) = os.path.split(path_name)
	(photo_name, ext) = os.path.splitext(jpeg_name)
	if not os.path.exists(path_name):
	    print path_name, 'UNREADABLE_FILE'
	    continue
	if ext == '.jpg' or ext == '.JPG' or ext == '.jpeg' or ext == '.JPEG':
	    if verbose_opt:
	    	repeat = 5
		if verbose_opt > 1: repeat = 6
		print "-------------" * repeat
		print "%30s: %s" % ("PhotoName", photo_name)
	    tags = exif.parse(path_name, verbose_opt, mode_opt)
	    if tags == {}:
	    	print path_name, 'NO_EXIF_HEADER'
		continue
	    tags['PhotoName'] = photo_name
	    if rename_opt:
	    	new_name = date_name(tags['DateTime'])
		print path_name,
		if new_name == '0000.00.00-00.00.00':
		    print 'NO_VALID_TIMESTAMP'
		else:
		    new_jpeg = new_name + '.jpg'
    	    	    if outdir_par:
			new_path_name = os.path.join(outdir_par, new_jpeg)
		    else:
			new_path_name = os.path.join(dir_name, new_jpeg)
		    if not noact_opt:
		    	tags['PhotoName'] = new_name
			new_path_noext = new_path_name[:-4]+'-'
			count = 1
			while new_path_name and os.path.exists(new_path_name):
			    jpeg1 = read_file(path_name)
			    jpeg2 = read_file(new_path_name)
			    if jpeg1 == jpeg2:
			    	new_path_name = ''
				print 'IDENTICAL_FILE_EXISTS',
			    else:
			    	new_path_name = new_path_noext+`count`+'.jpg'
				count = count + 1
				if debug_opt:
				    print '[file exists, incremented name]',
			if new_path_name:
			    if outdir_par:
				shutil.copyfile(path_name, new_path_name)
			    else:
				os.rename(path_name, new_path_name)
		    print new_path_name
    	    print_tags = PrintMap(tags)
	    if info_opt:
	    	print TEXT_FORMAT % print_tags
	    if write_opt:
	        html_name = photo_name + '.html'
		if outdir_par:
		    html_name = os.path.join(outdir_par, html_name)
		print path_name, html_name
		if not noact_opt:
	    	    write_file_format(html_name, HTML_FORMAT, print_tags)

except Exception, error:
    if isinstance(error, IOError) and str(error) == '[Errno 32] Broken pipe':
    	sys.exit(-1)
    if isinstance(error,KeyboardInterrupt):
	sys.exit(-1)
    raise
## ===========================================================================





