#!/usr/bin/python
# vim:set ai et sts=2 sw=2:
# vim600: set fdm=marker cms=#%s :
#
# This program creates with the same directories, a html gallery.
#  Thumbmails can be any size, aspect ratio is keep
#  Within each directory, we found several directories
#  one foreach resolution thumbail (800x600, ...)
#  html page is build under this name 
#
#  Created: Luc Saillard <luc@sailard.org>  Wed, 13 Feb 2002 20:51:12 +0100
#  Last modified: Luc Saillard <luc.saillard@alcove.fr> Tue, 26 Mar 2002 22:51:40 +0100
#  Changelog:
#    v0.1: first release in Python.
#    v0.3: Working release with exif support, multiple pages, ...
#
#
#  Copyright (C) 2002 Luc Saillard <luc@saillard.org>
#
#   This program is free software; you can redistribute it and/or modify
#   it under the terms of the GNU General Public License as published by
#   the Free Software Foundation; either version 2 of the License, or
#   (at your option) any later version.
#
#   This program is distributed in the hope that it will be useful,
#   but WITHOUT ANY WARRANTY; without even the implied warranty of
#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#   GNU General Public License for more details.
#
#   You should have received a copy of the GNU General Public License
#   along with this program; if not, write to the Free Software
#   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
#
# Includes modules                                                         {{{
import getopt, os, sys, string, shutil, urllib, re
from PIL import Image, ImageFile
from stat import *
from array import array
import EXIF
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -}}}
""" Global options """#{{{
global options
options = {}
options['verbose_level'] = 0
options['output_directory'] = './photos'
options['comment_filename'] = '.comments'
options['thumbsize'] = (160,120)
options['sizelist'] = [(0,0) , (1024,768), (800,600), (640,480)]
options['forcecreate_html'] = 0
options['display_columns'] = 3
options['display_lines'] = 5
options['generate_root_index_html'] = 1
#options['img_bgcolor'] = "#eee5de"
#options['img_bgcolor'] = "#fff5ee"
options['img_bgcolor'] = "#fffaf5"
options['body_bgcolor'] = "#ccccff"
options['exif'] = 1
options['exif_bordercolor'] = "#008000"
options['exif_bgcolor'] = "#f0fff0"
options['exif_fgcolor'] = "black"

photon_version = '0.2.1'

# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -}}}
#
# Some main functions
#
def main():#{{{
  """ main procedure """
  global options

  short_opts="ho:vEd:Vl:s:t:Ifc:"
  long_opts=["help", "version", "output-directory=", "verbose", "no-exif",
             "display-columns=", "display-lines=","sizelist=","thumbsize",
             "no-index" , "body-bgcolor=", "img-bgcolor=", "exif-bordercolor=",
             "exif-bgcolor=", "exif-fgcolor=", "force", "comment="
             ]
  try:
    opts, args = getopt.getopt(sys.argv[1:], short_opts, long_opts)
  except getopt.GetoptError, msg:
    # print help information and exit:
    if msg:
      print msg
    usage()
    sys.exit(2)
  for o, a in opts:
    if o in ("-h", "--help"):
      usage()
      sys.exit()
    elif o in ("-V", "--version"):
      print "Photon",photon_version
      sys.exit()
    elif o in ("-o", "--output-directory"):
      options['output_directory'] = a
    elif o in ("-v", "--verbose"):
      options['verbose_level'] += 1
    elif o in ("-e", "--no-exif"):
      options['exif'] = 0
    elif o in ("-d", "--display-columns"):
      if a.isdigit():
        options['display_columns'] = a
      else:
        print "Bad argument:",a,"must be a number"
    elif o in ("-l", "--display-lines"):
      if a.isdigit():
        options['display_lines'] = a
      else:
        print "Bad argument:",a,"must be a number"
    elif o in ("-s", "--sizelist"):
      l=[]
      for s in a.split(','):
        if s=='0':
          l.append((0,0))
        else:
          m=re.search("^(\d+)x(\d+)$",s)
          if m:
            l.append((int(m.group(1)),int(m.group(2))))
          else:
            print "Bad size:",s,"must in the form 320x240"
      # End: for s in a.split(','):
      options['sizelist']=l
    elif o in ("-t", "--thumbsize"):
      m=re.search("^(\d+)x(\d+)$",s)
      if m:
        options['thumbsize']=((int(m.group(1)),int(m.group(2))))
      else:
        print "Bad size:",s,"must in the form 320x240"
    elif o in ("-I", "--no-index"):
      options['generate_root_index_html'] = 0
    elif o == "body-bgcolor":
      if match_color_type(a):
        options['body_bgcolor']=a
      else:
        print "Bad color:",a,"must in the form #0055ff or white"
    elif o == "img-bgcolor":
      if match_color_type(a):
        options['img_bgcolor']=a
      else:
        print "Bad color:",a,"must in the form #0055ff or white"
    elif o == "exif-bordercolor":
      if match_color_type(a):
        options['exif_bordercolor']=a
      else:
        print "Bad color:",a,"must in the form #0055ff or white"
    elif o == "exif-bgcolor":
      if match_color_type(a):
        options['exif_bgcolor']=a
      else:
        print "Bad color:",a,"must in the form #0055ff or white"
    elif o == "exif-fgcolor":
      if match_color_type(a):
        options['exif_fgcolor']=a
      else:
        print "Bad color:",a,"must in the form #0055ff or white"
    elif o in ("-f", "--force"):
      options['forcecreate_html']=1
    elif o in ("-c", "--comment"):
      options['comment_filename']=a


  print_options()

  """ Compute some values before processing directory """
  options['sizelist'].append(options['thumbsize'])
  # Fix a bug when decompressing -> compressing a jpeg file
  ImageFile.MAXBLOCK = 1000000 # default is 64k

  for path in args:
    process_directory(path,"")
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -}}}
def usage(): # {{{
  """ Print information to use this program """
  print """
  Usage: photon.py [OPTIONS] path...
    where OPTIONS are
    -h   --help                 Print this help
    -V   --version              Print Photon version
    -E   --no-exif              Don't include EXIF information in HTML file
    -d N --display-columns N    Set number of columns in index (default 3)
    -l N --display-lines N      Set number of lines in index (default 5)
    -s S --sizelist S           Image sizes (default 0,1024x768,800x600,640x480)
    -t S --sizelist S           Size of thumbnails (default 160x120).
    -I   --no-index             Do not generate the high level index.html (default no).
    -f   --force                Overwrite image files (default no).
    -c   --comment              Name of the comment file (default .comments)
         --body-bgcolor C       Background color (default #ccccff)
         --img-bgcolor C        Background color for image (default 'white')
         --exif-bordercolor C   Border color for the exif window (default #008000)
         --exif-bgcolor C       Background color for the exif window (default #f0fff0)
         --exif-fgcolor C       Text Color for the exif window (default 'black')
""" 
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -}}}
def print_options():#{{{
  """ Print Options array that contains all configurable options """
  global options

  if options['verbose_level'] >= 1:
    print "Program options:"
    for key in options.keys():
      print " ",key,options[key]
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -}}}
#
# Functions that work on an directory or on a file
#
def process_directory(realpath,relativepath): # {{{
  """ Generate thumbmails, html pages for this directory """
  global options

  directories_list = []
  images_list = []

  destdir = os.path.join(options['output_directory'],relativepath)
  safe_mkdir(destdir)

  sourcedir = os.path.join(realpath,relativepath)

  # For each images build alls sub-image,
  # for each directory, recurse into them
  for entry in os.listdir(sourcedir):
    if entry[0] == '.': # Don't accept directory or file beginning this a dot
      continue
    pathname = os.path.join(sourcedir,entry)
    mode = os.stat(pathname)[ST_MODE]
    if S_ISDIR(mode):
      process_directory(realpath,os.path.join(relativepath,entry))
      directories_list.append(entry)
    elif S_ISREG(mode):
      picinfo = process_file(realpath,relativepath,entry)
      if picinfo:
        images_list.append(picinfo)
    else:
      print 'Skipping %s' % pathname

  process_comment_file(realpath,relativepath,images_list)

  # Now, we have the complete list of directory, and files ... sort them
  images_list.sort(lambda x,y: cmp(x['filename'],y['filename']))
  directories_list.sort()
  # ... then generate html pages
  make_directory_html(relativepath,directories_list,images_list)
  if len(images_list)>0:
    make_image_html(relativepath,directories_list,images_list)

# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -}}}
def process_file(sourcedir,relativepath,filename): # {{{
  """ Create for this file all thumbmails and return the size of the image """
  global options

  srcfile = os.path.join(sourcedir,relativepath,filename)

  # Keep only Jpeg file (python cores dump with some PCD (kodak) file
  if ((string.rfind(string.lower(filename),".jpg")==-1) and
     (string.rfind(string.lower(filename),".jpeg")==-1)) :
    return None

  pic = {}
  try:
    im = Image.open(srcfile)
    print 'Processing image',srcfile, im.format, "%dx%d" % im.size, im.mode
  except IOError, err:
    print "cannot create thumbnail for",srcfile,"(",err.strerror,")"
  else:
    # Foreach size of the image, resize them only when it's different from Original
    pic['filename']=filename
    pic['original_size']=im.size
    if options['exif']:
      file = open(srcfile, 'rb')
      pic['exif'] = EXIF.process_file(file)
    if im.size[1] > im.size[0]: # Keep aspect ration
      pic['ratio']=34
    else:
      pic['ratio']=43
    for (w,h) in options['sizelist']:
      if w == 0 and h == 0: # Special case when it is a original file
        subdir='original'
        destdir = os.path.join(options['output_directory'],relativepath,subdir)
        destfile = os.path.join(destdir,filename)
	if not compare_lastmodifiedtime(srcfile,destfile):
          safe_mkdir(destdir)
          shutil.copyfile(srcfile,destfile)
      else:
	if pic['ratio']==34:
          newsize=(h,w)
	else:
          newsize=(w,h)
        subdir='%dx%d' % (w,h)
        destdir = os.path.join(options['output_directory'],relativepath,subdir)
        destfile = os.path.join(destdir,filename)
	if not compare_lastmodifiedtime(srcfile,destfile):
          if w > im.size[0]: # Don't generate thumbmail when original file is smaller
            print "Skipping",srcfile,"for resolution %dx%d" % newsize
            continue
          safe_mkdir(destdir)
	  try:
            im.resize(newsize,Image.BICUBIC).save(destfile,'JPEG',optimize=1,progressive=1)
          except IOError, err:
            print "Error while writting Jpeg Optimize file, try to do without optimization, perhaps who can try to increase ImageFile.MAXBLOCK in the source file"
            try: # Try to save the Jpeg file without progessive option
              im.resize(newsize,Image.BICUBIC).save(destfile,'JPEG')
            except IOError, err:
              print "cannot create ",destfile,"(",err,")"
    return pic
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -}}}
def process_comment_file(realpath,relativepath,images_list): # {{{
  """ Process the .comments in this directory that contains a comment for an image """
  global options

  try:
    f=open(os.path.join(realpath,relativepath,options['comment_filename']),'r')
  except IOError:
    return 

  r = re.compile('^"([^"]+)"\s+"([^"]+)"')
  s = f.readline()
  while s:
    m = r.search(s)
    if m:
      # Ok we found a filename, and a comment in this line
      # TODO: use map function ?
      for i in images_list:
        if i['filename'] == m.group(1):
          i['comments'] = m.group(2)
          break
    # silently discard bad line ?
    s = f.readline()
  f.close()

# }}}
def make_directory_html(relativepath, directories_list,images_list): # {{{
  """ Make all html page for index this directory """
  global options

  if relativepath == "" and not options['generate_root_index_html']:
    return

  images_processed=0 # Number of the images currently processed in the list
  page_index=0       # Number of index.html page currently processed
  total_images = len(images_list) + len(directories_list)
  items_per_page = options['display_columns'] * options['display_lines'];
  output_directory = os.path.join(options['output_directory'],relativepath)

  while images_processed < total_images:

    if images_processed == 0:
      index_html_filename = 'index.html'
    else:
      index_html_filename = 'index%d.html' % (images_processed / items_per_page)

    f=open(os.path.join(output_directory,index_html_filename),'w')
    output_index_html_header(f,relativepath)
    if images_processed == 0:
      output_index_html_directories(f,directories_list)
      total_images-=len(directories_list) # Small hack, because i want to do a do {} while(x)
    output_index_html_images(f,images_list[images_processed:images_processed+items_per_page])
    output_index_html_footer(f,page_index,images_processed,total_images)

    f.close()

    images_processed+=items_per_page
    page_index+=1

# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - }}}
def make_image_html(relativepath, directories_list,images_list): # {{{
  """ Make all html page for all images """
  global options

  make_blank_gif(os.path.join(options['output_directory'],relativepath,'blank.gif'))
  if options['exif']:
    make_exif_js(os.path.join(options['output_directory'],relativepath,'exif.js'))

  output_directory = os.path.join(options['output_directory'],relativepath)

  total_images = len(images_list)
  k=0

  while k < total_images:

    image = images_list[k]

    for resolution in options['sizelist']:

      image_html_filename=image_filename_to_image_htmlfilename(image['filename'],resolution)

      # Make the html page for this image and this resolution
      f=open(os.path.join(output_directory,urllib.unquote(image_html_filename)),'w')
      output_image_html_header(f,relativepath,image['filename'])
      output_image_html_body(f,relativepath,images_list,k,resolution)
      if options['exif']:
        output_image_html_exif_window(f,image)
      output_image_html_footer(f)
      f.close()
    # End: for resolution in options['sizelist']:

    k+=1

  # End: for image in images_list

# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - }}}
#
# Functions that output HTML Code
#
def output_index_html_header(f,relativepath): # - - - - - - - - - - - - - - {{{
  """ Write in the file, header of an index.html page (body included) """
  global options

  if relativepath == "":
    html_title = "Albums";
  else:
    html_title = string.split(relativepath,os.sep)[-1];

  navbar = navbar_for_index_html(relativepath)

  f.write("""
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
 <title>Photon: %s</title>
 <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> 
</head>
<body bgcolor="%s">
<div align=center>
<table bgcolor="black">
<tr>
 <td>
  <table width="100%%" cellpadding=4>
  <tr bgcolor="%s">
   <td colspan=%s>%s</td>
  </tr>
""" % (html_title,options['body_bgcolor'],options['img_bgcolor'],
      options['display_columns'],navbar)) 
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - }}}
def output_index_html_directories(f,directories_list): # - - - - - - - - - -{{{
  """ Output a HTML table that contains the directories list """
  global options

  column=0

  f.write('  <tr bgcolor="%s">\n' % options['img_bgcolor'])

  # Create a case for each directory
  for d in directories_list:
    if column >= options['display_columns']:
      f.write("  </tr>\n  <tr bgcolor=\"%s\">\n" % options['img_bgcolor']);
      column=0
    f.write('   <td align=center><a href="' + urllib.quote(d) + '/index.html"><b>' + d +
    '</b></a><br><img width=%d height=1 src="blank.gif" alt=""></td>' % options['thumbsize'][0])
    column+=1
  
  # Fill the empty case ...
  if column>0:
    while column < options['display_columns']:
      f.write('   <td><img width=%d height=1 src="blank.gif" alt=""></td>' % options['thumbsize'][0])
      column+=1
    # Close the row
    f.write('  </tr>\n')
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - }}}
def output_index_html_images(f,images_list):  # - - - - - - - - - - - - - - {{{
  """ Output a HTML table that contains the images list """
  global options
  
  column=0

  f.write('  <tr bgcolor="%s">\n' % options['img_bgcolor'])

  # Create a case for each image
  for pic in images_list:
    if column >= options['display_columns']:
      f.write("  </tr>\n  <tr bgcolor=\"%s\">\n" % options['img_bgcolor']);
      column=0

    if pic['ratio']==34:
      thumbsize_width  = options['thumbsize'][1]
      thumbsize_height = options['thumbsize'][0]
    else:
      (thumbsize_width,thumbsize_height)=options['thumbsize']
 
    imgurl=urllib.quote(os.path.join("%dx%d" % options['thumbsize'],pic['filename']))
    imghtmlurl = image_filename_to_image_htmlfilename(pic['filename'],options['sizelist'][0])

    f.write('   <td valign=bottom align=center>'
           + '<table border=0><tr><td bgcolor=black>'
           + '<a href="%s">' % imghtmlurl
           + '<img hspace=3 vspace=3 border=0 src="%s" alt="%s" width=%d height=%d>' 
             % (imgurl,pic['filename'],thumbsize_width,thumbsize_height)
           + '</a>'
           + '</td></tr></table>'
	   + '<br><a href="%s"> %s </a></td>\n' % (imghtmlurl,pic['filename']))
    column+=1

  # Fill the empty case ...
  if column>0:
    while column < options['display_columns']:
      f.write('   <td><img width=%d height=1 src="blank.gif" alt=""></td>' % options['thumbsize'][0])
      column+=1
    # Close the row
    f.write('  </tr>\n')
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - }}}
def output_index_html_footer(f,page_index,images_processed,total_images): # {{{
  """ Output the footer for a index.html page """
  global options

  items_per_page = options['display_columns'] * options['display_lines'];
  f.write('  <tr bgcolor="%s">\n' % options['img_bgcolor'] +
          '   <td colspan=%s>\n' % options['display_columns'] +
          '    <table border=0 width="100%">\n    <tr>\n     <td>')
  # Output the Start and the Prev link
  if page_index==0:
    f.write('Start | Prev %s | ' % items_per_page)
  elif page_index==1:
    f.write('<a href="index.html">Start</a> | <a href="index.html">Prev %s</a> | ' % items_per_page)
  else:
    f.write('<a href="index.html">Start</a> | <a href="index%d.html">Prev %s</a> | ' % (page_index-1,items_per_page))

  # Output the Next link
  max_pages = total_images / items_per_page
  if (total_images % items_per_page) == 0:
    max_pages-=1
  if page_index<max_pages:
    f.write('<a href="index%d.html">Next %s</a> | ' % (page_index+1,items_per_page))
  else:
    f.write('Next %s | ' % items_per_page)

  # Output the End link
  if page_index<max_pages:
    f.write('<a href="index%d.html">End</a></td>' % max_pages)
  else:
    f.write('End</td>')

  # Output the Number of Images
  if total_images==0:
    f.write('<td align=right>&nbsp;</td>')
  else:
    max_images_displayed = images_processed+items_per_page
    if max_images_displayed > total_images:
      max_images_displayed = total_images
    f.write('<td align=right>Images %d to %d of %d</td>' 
       % (images_processed+1,max_images_displayed,total_images))

  f.write("""</td>
    </tr>
    </table>
   </td>
  </tr>
  </table>
 </td>
</tr>
</table>
<font size=-1>Generated by photon %s</font>
</div>
</body>
</html>
""" % photon_version)
          
   
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - }}}

def output_image_html_header(f,relativepath,imagefilename): # - - - - - - - - {{{
  """ Write in the file, header of an image.html page (body included) """
  global options

  html_title = imagefilename;
  if options['exif']:
    script_exif='<script language="JavaScript1.2" src="exif.js"></script>'
    onload_exif='onload="exif_init()"'
  else:
    script_exif=''
    onload_exif=''

  f.write("""<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
 <title>Photon: %s</title>
 <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> 
 <style type="text/css">
   #exifwindow {position:absolute; height:1; width:1; top:0; left:0;}
 </style>
 %s
</head>
<body bgcolor="%s" %s>
""" % (html_title,script_exif,options['body_bgcolor'],onload_exif))

# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - }}}
def output_image_html_body(f,relativepath,images_list,index,resolution): # - -{{{
  """ Output in the file f, the content of the body for this image """
  global photon_version,options

  imageinfo = images_list[index]
  if index==0:
    previous_image = None
  else:
    previous_image = images_list[index-1]

  if index+1>=len(images_list):
    next_image = None
  else:
    next_image = images_list[index+1]

  resolution_string = "%dx%d" % resolution

  if resolution_string == "0x0":
    resolution_string = "original"
  image_urlname=urllib.quote(os.path.join(resolution_string,imageinfo['filename']));

  body = """<div align=center>
<table bgcolor="black">
<tr>
 <td>
  <table width="100%" cellpadding=4>
  <tr bgcolor="BODY_FGCOLOR">
   <td colspan=DISPLAY_COLUMNS>NAVBAR</td>
  </tr>
  <tr bgcolor="BODY_FGCOLOR">
   <td colspan=DISPLAY_COLUMNS><center><table border=0><tr><td bgcolor=black><img hspace=3 vspace=3 border=0 src="IMGSRC" alt="IMGALT"></td></tr></table></center></td>
  </tr>
  <tr bgcolor="BODY_FGCOLOR">
   <td colspan=DISPLAY_COLUMNS><center>COMMENTS</center></td>
  </tr>
  <tr bgcolor="BODY_FGCOLOR">
   <td colspan=DISPLAY_COLUMNS>XXX</td>
  </tr>
  </table>
 </td>
</tr>
</table>
<font size=-1>Generated by Photon PHOTON_VERSION</font>
</div>
"""

  body=body.replace("BODY_FGCOLOR",options['img_bgcolor'])
  body=body.replace("DISPLAY_COLUMNS","%d" % options['display_columns'])
  body=body.replace("IMGSRC",image_urlname)
  body=body.replace("IMGALT",imageinfo['filename'])
  body=body.replace("NAVBAR",navbar_for_image_html(relativepath,images_list,index))
  body=body.replace("PHOTON_VERSION",photon_version)
  if imageinfo.has_key('comments'):
    body=body.replace("COMMENTS",imageinfo['comments'])
  else:
    body=body.replace("COMMENTS","")
  body=body.replace("XXX",image_html_body_sub(imageinfo,resolution,previous_image,next_image))

  f.write(body)

# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - }}}
def image_html_body_sub(imageinfo,resolution,previous_image,next_image): # -{{{
  """ Return the HTML code to display 2 thumbmails to include in the image page """
  global options

  content ="""
    <table border=0 width="100%">
    <tr>
     <td valign=top>LEFT_IMG</td>
     <td valign=top align=center>SIZE_LIST</td>
     <td valign=top align=right>RIGHT_IMG</td>
    </tr>
    </table>
   """
  if previous_image:
    thumblink = image_filename_to_image_htmlfilename(previous_image['filename'],resolution)
    thumbimg = os.path.join("%dx%d" % options['thumbsize'],urllib.quote(previous_image['filename']))
    left_img="<a href=\"%s\">&lt;-Prev</a><br><table border=0><tr><td bgcolor=black><a href=\"%s\"><img align=middle hspace=2 vspace=2 border=0 src=\"%s\" alt=\"%s\"></a></td></tr></table>" % (thumblink,thumblink,thumbimg,previous_image['filename'])
  else:
    left_img="<img width=%d height=1 src=\"blank.gif\" alt=\"\">" % options['thumbsize'][0]

  if next_image:
    thumblink = image_filename_to_image_htmlfilename(next_image['filename'],resolution)
    thumbimg = os.path.join("%dx%d" % options['thumbsize'],urllib.quote(next_image['filename']))
    right_img="<a href=\"%s\">Next -&gt;</a><br><table border=0><tr><td bgcolor=black><a href=\"%s\"><img align=middle hspace=2 vspace=2 border=0 src=\"%s\" alt=\"%s\"></a></td></tr></table>" % (thumblink,thumblink,thumbimg,next_image['filename'])
  else:
    right_img="<img width=%d height=1 src=\"blank.gif\" alt=\"\">" % options['thumbsize'][0]

  if options['exif']:
    sizelist="<form action=\"\"><input type=\"button\" onclick=\"exif_hide_show()\" value=\"Image Information\"></form><br>"
  else:
    sizelist=''
  if len(options['sizelist']):
    sizelist+= "Other sizes:<br>"
    for r in options['sizelist']:
      if r != resolution:
        if r[0] > imageinfo['original_size'][0]: # Don't add this resolution when original file is smaller
          continue
        if r == (0,0):
          r_str = "Original"
        else:
	  if imageinfo['ratio']==34:
            r_str = "%dx%d" % (r[1], r[0])
          else:
            r_str = "%dx%d" % r
        sizelist+="<a href=\"%s\">%s</a><br>" % (image_filename_to_image_htmlfilename(imageinfo['filename'],r), r_str)
      # End: if r != resolution:
    # End: for r in options['sizelist']:
  # End: if len(options['sizelist']):

  content=content.replace("LEFT_IMG",left_img);
  content=content.replace("RIGHT_IMG",right_img);
  content=content.replace("SIZE_LIST",sizelist);

  return content

# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - }}}
def output_image_html_exif_window(f,imageinfo): # {{{
  """ Output the HTML code for the exif window page """
  global options

  exif_info=""

  if imageinfo.has_key('exif') and imageinfo['exif'].has_key('Image Make'):
    exif_info+="Taken with a %s%s<br>" % (imageinfo['exif']['Image Make'].printable,imageinfo['exif']['Image Model'].printable)

  for prop in imageinfo['exif'].keys():
    if prop in ('EXIF ExifImageLength','EXIF ExifImageWidth','EXIF DateTimeDigitized','EXIF ExposureTime'):
      exif_info+='<b>%s</b>: %s<br>' % (prop,imageinfo['exif'][prop].printable)

  
  f.write("""
<div id="exifwindow" style="visibility:hidden">
  <table width="1%%" height="1%%" bgcolor="%s"><tr><td><table width="300" height="250" bgcolor="%s">
   <tr><td align="left" valign="middle">%s</td></tr>
   <tr><td align="right" valign="bottom"><a href="" onclick="exif_hide(); return false;">Close this box</a></td></tr>
  </table></td></tr></table>
</div>
""" % (options['exif_bordercolor'],options['exif_bgcolor'],exif_info))
    
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - }}}
def output_image_html_footer(f): # {{{
  """ Output the footer for a image.html page """
  f.write("</body>\n</html>\n")
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - }}}


#
# Some useful misc function
#
def safe_mkdir(pathname): # - - - - - - - - - - - - - - - - - - - - - - - - {{{
  """ Create a directory only when it doesn't exist """
  try :
    mode = os.stat(pathname)[ST_MODE]
    if not S_ISDIR(mode):
      os.mkdir(pathname);
  except OSError:
    os.mkdir(pathname);
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - }}}
def navbar_for_index_html(relativepath): # - - -{{{
  """ Transform the directory location in a navigation bar printable in HTML """

  if relativepath == "":
    return "<b>Home</b>"

  ndirs = 1 + string.count(relativepath,os.sep)
  site_home = "../" * ndirs
  url = '<a href="'+site_home+'index.html">Albums</a>'

  for d in string.split(relativepath,os.sep):
    if d == "":
      continue
    ndirs-=1
    if ndirs:
      url += ' -&gt; <a href="'+ "../" * ndirs +'index.html">'+ d +'</a>'
    else:
      url += ' -&gt; <b>'+ d +'</b>'
  return url
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - }}}
def navbar_for_image_html(relativepath,images_list,index): # - - -{{{
  """ Print the navigation bar for an image.html
  relativepath: Path where to found the image
  images_list: list of the images for this directory
  index: index to the current image in the images_list
  """
  global options

  # Calculate the page number where this page is located
  items_per_page = options['display_columns'] * options['display_lines'];
  current_page = index / items_per_page

  if relativepath == "":
    if current_page:
      return '<a href="index%d.html">Albums</a>' % current_page
    else:
      return '<a href="index.html">Albums</a>'

  ndirs = 1 + string.count(relativepath,os.sep)
  site_home = "../" * ndirs
  url = '<a href="'+site_home+'index.html">Albums</a>'

  for d in string.split(relativepath,os.sep):
    if d == "":
      continue
    ndirs-=1
    if ndirs:
      url += ' -&gt; <a href="'+ "../" * ndirs +'index.html">'+ d +'</a>'
    else:
      if current_page:
        url += ' -&gt; <a href="index%d.html">%s</a>' % (current_page,d)
        url += ' -&gt; <b>'+ images_list[index]['filename'] +'</b>'
      else:
        url += ' -&gt; <a href="index.html">'+ d +'</a> -&gt; <b>'+ images_list[index]['filename'] +'</b>'
  return url
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - }}}
def image_filename_to_image_htmlfilename(imagename,resolution): # - - -{{{
  """ Return the name of the HTML page for an image and a resolution """
  # Strip .jpg from filename
  i = string.find(imagename,".")
  image_filename_without_ext = imagename[0:i]

  # if this image is the original size, do not append the resoltuion to the filename
  resolution_string = "%dx%d" % resolution
  if resolution_string == "0x0":
    image_html_filename="%s.html" % image_filename_without_ext;
  else:
    image_html_filename="%s_%s.html" % (image_filename_without_ext,resolution_string);
  return urllib.quote(image_html_filename)
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - }}}
def compare_lastmodifiedtime(pathname1,pathname2): # {{{
  """ Compare the last modified time from 2 files (or directory) """
  global options
  if options['forcecreate_html']:
    return None
  try :
    mode1 = os.stat(pathname1)[ST_MTIME]
    mode2 = os.stat(pathname2)[ST_MTIME]
    return (mode1 < mode2)
  except OSError:
    return None
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -}}}
def make_blank_gif(pathname): # - - - - - - - - - - - - - - - - - - - - - - {{{
  """ Make a small gif 1x1 with a transparent color """
  blank_gif="\107\111\106\070\071\141\001\000\001\000\200\000\000\000\000\000"\
            "\377\377\377\041\371\004\001\000\000\000\000\054\000\000\000\000"\
            "\001\000\001\000\100\002\001\104\000\073"

  try :
    f=open(pathname,'wb')
  except OSError:
    return 0
  else:
    f.write(blank_gif)
    f.close()
    
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - }}}
def make_exif_js(pathname): # - - - - - - - - - - - - - - - - - - - - - - {{{
  """ Make a separate javascript file that contains dynamic html functions """

  try :
    f=open(pathname,'w')
  except OSError:
    return 0
  else:
    f.write("""
var ns=(document.layers);
var ie=(document.all);
var w3=(document.getElementById && !ie);
var exif_layer;
var exif_isshow;

function exif_init()
{
   if(!ns && !ie && !w3) 
     return;
   if (ie)
     exif_layer=eval('document.all.exifwindow.style');
   else if (ns)
     exif_layer=eval('document.layers["exifwindow"]');
   else if (w3)
     exif_layer=eval('document.getElementById("exifwindow").style');
   
   exif_hide();
}

function exif_show()
{
  if (ie)
   {
     documentWidth  =document.body.offsetWidth/2+document.body.scrollLeft-20;
     documentHeight =document.body.offsetHeight/2+document.body.scrollTop-20;
     exif_layer.visibility="visible";
   }    
  else if (ns)
   {
     documentWidth=window.innerWidth/2+window.pageXOffset-20;
     documentHeight=window.innerHeight/2+window.pageYOffset-20;
     exif_layer.visibility ="show";
   }
  else if (w3)
   {
     documentWidth=self.innerWidth/2+window.pageXOffset-20;
     documentHeight=self.innerHeight/2+window.pageYOffset-20;
     exif_layer.visibility="visible";
   }
  exif_layer.left=documentWidth-150;
  exif_layer.top =documentHeight-125;
  exif_isshow=1;
  setTimeout("exif_hide()",10000);
}

function exif_hide()
{
  if (ie||w3)
    exif_layer.visibility="hidden";
  else
    exif_layer.visibility="hide";
  exif_isshow=0;
}

function exif_hide_show()
{
  if (exif_isshow)
    exif_hide()
  else
    exif_show()
}
""")
    f.close()
    
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - }}}

def match_color_type(color): # {{{
  """ Return the string when the string match a color in HTML format """
  if color[0] == "#":
    if re.match("^#[0-9a-f]{6}$",color):
      return color
  elif re.match("^[a-z]+$",a):
    return color
  return None
# }}}
#

if __name__ == "__main__":
    main()



