#!/usr/bin/python
# vim:set ai et sts=2 sw=2:
# vim600: set fdm=marker cms=#%s :
#
# Photon is a static HTML gallery generator.
#   * directory structure is kept intact
#   * scaled images are put in separate directories (800x600, ...)
#   * etc...
#
#  Created: Luc Saillard <luc(@)sailard.org>  Wed, 13 Feb 2002 20:51:12 +0100
#  Last modified: Luc Saillard <luc(@)saillard.org> Tue, 26 Apr 2004 12:01:23 +0100
#  Changelog:
#    v0.1: first release in Python.
#    v0.2.3: ???
#    v0.2.4: speed up improvement
#    v0.2.5: New <link> that indicates previous/next page
#            Key Shorcuts can now be use
#            Slideshow functions
#    v0.2.6: Javascript fix
#            Cmdline option fix
#            New exclude option
#    v0.2.7: Gimp plugin (very slow for the moment)
#            Bug fixes
#            New options: --resize-plugin
#    v0.2.8: Anchor is made for each row in the galery view
#    v0.2.9: Compat with gimp-2.0, python2.1, python2.2
#            Fix a bug when thumbsize > image
#            Fix a bug when gimp cannot recognize the image
#            
#
#
#  Copyright (C) 2002-2004 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, shutil, urllib, re, locale, codecs
from fnmatch import *
from stat import *
from tempfile import gettempdir
from array import array
from commands import getstatusoutput
import EXIF

try:
  from PIL import Image, ImageFile
except:
  print 'Could not load PIL. In order to use this script,'
  print 'you must have PIL installed.'
  print 'http://www.pythonware.com/products/pil/'
  sys.exit(3)

# ------------------------------------------------------------------------ 
""" 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'] = 4
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"
options['javascript'] = 1
options['exclude'] = ["*.mov","*.avi"]
options['resize_plugin'] = "internal"
options['resize_quality_low'] = 0.5
options['resize_quality_high'] = 0.85
options['gimp_program'] = "gimp"
options['charset'] = 'iso-8859-15'

photon_version = '0.2.10'

gimp_list = []  # This is a global list that contains jobs to be run by Gimp


# ------------------------------------------------------------------------ 
#
# Main functions
#
def main():# 
  """ main procedure """

  short_opts="c:d:EfhIl:o:s:t:Vv"
  long_opts=[ "comment=", "display-columns=", "no-exif", "force", "help",
              "no-index", "display-lines=", "output-directory=", "sizelist=",
              "thumbsize=", "version",  "verbose", "javascript",
              "exif-bordercolor=", "exif-bgcolor=", "exif-fgcolor=",
              "body-bgcolor=", "img-bgcolor=", "exclude=", "resize-plugin=",
              "resize-quality-low=", "resize-quality-high=", "gimp-program="
            ]
  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 ("-c", "--comment"):
      options['comment_filename'] = a
    elif o in ("-d", "--display-columns"):
      if a.isdigit():
        options['display_columns'] = int(a)
      else:
        print "Bad argument:",a,"must be a number"
    elif o in ("-E", "--no-exif"):
      options['exif'] = 0
    elif o in ("-f", "--force"):
      options['forcecreate_html'] = 1
    elif o in ("-h", "--help"):
      usage()
      sys.exit()
    elif o in ("-I", "--no-index"):
      options['generate_root_index_html'] = 0
    elif o in ("-J", "--no-javascript"):
      options['javascript'] = 0
    elif o in ("-l", "--display-lines"):
      if a.isdigit():
        options['display_lines'] = int(a)
      else:
        print "Bad argument:", a, "must be a number"
    elif o in ("-o", "--output-directory"):
      options['output_directory'] = a
    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 ("-V", "--version"):
      print "Photon ", photon_version
      sys.exit()
    elif o in ("-v", "--verbose"):
      options['verbose_level'] += 1
    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 == "--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 == "--exclude":
      options['exclude'].append(a)
    elif o == "--resize-plugin":
      if a in ("internal","gimp"):
        options['resize_plugin'] = a
      elif a in ("magick"):
        print "This method plugin ",a," is not available"
      else:
        print "This method plugin ",a," is unknow. Using default plugin: ",options['resize_plugin']
    elif o == "--resize-quality-low":
      if a.isdigit():
        options['resize_quality_low'] = int(a)/100.0
      else:
        print "Bad argument:", a, "must be a number"
    elif o == "--resize-quality-high":
      if a.isdigit():
        options['resize_quality_high'] = int(a)/100.0
      else:
        print "Bad argument:", a, "must be a number"
    elif o == "--gimp-program":
      options['gimp_program'] = a

  print_options()

  if options['thumbsize'] not in options['sizelist']:
    options['sizelist'].append(options['thumbsize'])
  # Fix a bug when decompressing -> compressing a jpeg file
  ImageFile.MAXBLOCK = 1000000 # default is 64k
 

  if args:
    for path in args:
      process_directory(path,"")
      # If we are using Gimp, process the file list
    if options['resize_plugin'] == "gimp" and len(gimp_list)>0:
      options['gimp_program'] = find_gimp_program()
      if options['gimp_program'] is None:
        print "Gimp not found\nAborted\n"
      else:
        options['tempdir'] = mkdtemp("","photon")
        gimp_resize_files(gimp_list)
        os.rmdir(options['tempdir'])
  else:
    usage()
    sys.exit()

# ------------------------------------------------------------------------ 
def usage(): # 
  """ Print information to use this program """
  print """
Usage: photon.py [OPTION]... [PATH]...

Options:
  -c NAME --comment               Name of the comment file (default .comments)
  -d NUM  --display-columns=NUM   Number of columns in index (default 3)
  -E      --no-exif               Don't include EXIF information in HTML file
  -f      --force                 Overwrite image files (default no)
  -h      --help                  Print this help
  -I      --no-index              Do not generate the high level index.html
  -J      --no-javascript         Do not use javascript (no shortcuts, ... )
  -l NUM  --display-lines=NUM     Number of lines in index (default 5)
  -o NAME --output-directory=NAME Name of the output directory
  -s LIST --sizelist=LIST         Image sizes (default 0,1024x768,800x600,640x480)
  -t SIZE --thumbsize=SIZE        Size of thumbnails (default 160x120)
  -V      --version               Print Photon version
  -v      --verbose               Be verbose
          --exif-bordercolor=COLOR  Exif window border color (default #008000)
          --exif-bgcolor=COLOR    Exif window background color (default #f0fff0)
          --exif-fgcolor=COLOR    Exif window text color (default 'black')
          --body-bgcolor=COLOR    Body background color (default #ccccff)
          --img-bgcolor=COLOR     Image background color (default 'white')
          --exclude=PATTERN       Exclude files matching PATTERN
          --resize-plugin=PLUG    Program use to create thumbnails
                                     internal: fastest method (default)
                                     gimp: use Gimp>1.x (better quality)
                                     magick: use ImageMagick (not implemented)
          --resize-quality-low=Q  quality for small image. 0 (bad) and 100 (good)
          --resize-quality-high=Q quality for big image 0 (bad) and 100 (good)
          --gimp-program=PROG     use PROG for gimp
          

Shortcuts while viewing an image:
  n/SPACE     Go to the next image (with the same resolution)
  p/BACKSPACE Go to the previous image (with the same resolution)
  s           Start/Stop the slideshow
  +/-         Increase/Decrease by one second the slideshow's period
  h           Show shortcup and help [NOT YET IMPLEMENTED]
  z           Change to the higher resolution [NOT YET IMPLEMENTED]

""" 
# ------------------------------------------------------------------------ 
def print_options():# 
  """ Print Options array that contains all configurable options """

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

  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):
    # Don't accept directory or file beginning with a dot
    if entry[0] == '.':
      continue
    pathname = os.path.join(sourcedir, entry)
    for pattern in options['exclude']:
      if fnmatch(pathname,pattern):
        print 'Excluding %s' % pathname
        break
    else:
      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 thumbnails and return the size of the image """

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

  # Keep only Jpeg file (python cores dump with some PCD (kodak) file
  if ((filename.lower().rfind(".jpg") == -1) and
      (filename.lower().rfind(".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 ratio
      pic['aspect'] = 34
      pic['ratio'] = float(im.size[1])/im.size[0]
    else:
      pic['aspect'] = 43
      pic['ratio'] = float(im.size[0])/im.size[1]

    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:
        # Resize the image with keeping the ratio
	if pic['aspect']==34:
          newsize = (int(h/pic['ratio']),w)
	else:
          newsize = (w,int(w/pic['ratio']))
          
        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] and w != options['thumbsize'][0]:
            # Don't generate thumbnail when original file is smaller
            print "Skipping", srcfile, "for resolution %dx%d" % newsize
            continue
          safe_mkdir(destdir)
          # We have 2 choices use Gimp or use Python Library
          if options['resize_plugin'] == "gimp":
            if w*h<64000:
              gimp_file = (srcfile,destfile,newsize,options['resize_quality_low'])
            else:
              gimp_file = (srcfile,destfile,newsize,options['resize_quality_high'])
            gimp_list.append(gimp_file)
          else: # Use the python internal module resize method
            try:
              im.resize(newsize, Image.BICUBIC).save(destfile, 'JPEG', optimize=1, progressive=1)
            except IOError, err:
              print "Error while writing thumbnail, will try without optimization..."
              print "Perhaps you 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 """

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

    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()
  except IOError:
    pass 

# ------------------------------------------------------------------------ 
def make_directory_html(relativepath, directories_list, images_list): # 
  """ Make all html page for index this directory """

  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, None, None)
    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 """

  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'))
  if options['javascript']:
    make_shortcut_js(os.path.join(options['output_directory'], relativepath, 'shortcuts.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)

      # Calculate the previous and next image/link
      if k == 0:
        previous_image = None
        previous_link  = None
      else:
        previous_image = images_list[k - 1]
        previous_link  = image_filename_to_image_htmlfilename(previous_image['filename'], resolution)

      if k + 1 >= len(images_list):
        next_image = None
        next_link  = None
      else:
        next_image = images_list[k + 1]
        next_link  = image_filename_to_image_htmlfilename(next_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'], previous_link, next_link)
      output_image_html_body(f, relativepath, images_list, k, resolution)
      if options['exif']:
        output_image_html_exif_window(f, image)
      if options['javascript']:
        output_image_html_help_layer(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, previous_link, next_link): # 
  """ Write in the file, header of an index.html page (body included) """

  if relativepath == "":
    html_title = "Albums";
  else:
    html_title = relativepath.split(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=%s">
""" % (html_title,options['charset']))

  if previous_link:
    f.write(" <link rel=\"prev\" href=\"%s\">" % previous_link)
  if next_link:
    f.write(" <link rel=\"next\" href=\"%s\">" % next_link)

  f.write("""
</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>
""" % (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 """

  column = 0

  if len(directories_list)==0:
    return

  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="%s/index.html"><b>%s</b></a><br><img width=%d height=1 src="blank.gif" alt=""></td>' % (urllib.quote(d),d,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 """
  
  column = 0
  row = 0

  if len(images_list)==0:
    return

  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']:
      row += 1
      f.write('  </tr>\n  <tr bgcolor="%s"></a>\n' % (options['img_bgcolor']));
      column = 0

    if pic['aspect'] == 34:
      thumbsize_height = options['thumbsize'][0]
      thumbsize_width = thumbsize_height / pic['ratio']
    else:
      thumbsize_width  = options['thumbsize'][0]
      thumbsize_height = thumbsize_width / pic['ratio']
 
    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"><img hspace=3 vspace=3 border=0 src="%s" alt="%s" width=%d height=%d></a></td></tr></table><br><a href="%s"> %s </a></td>\n' % (imghtmlurl,imgurl, pic['filename'], thumbsize_width, thumbsize_height,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 """

  items_per_page = options['display_columns'] * options['display_lines'];
  f.write('  <tr bgcolor="%s"><td colspan=%s><table border=0 width="100%%"><tr><td>' 
    % (options['img_bgcolor'],options['display_columns']))
  # 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("""
    </tr>
    </table>
   </td>
  </tr>
  </table>
 </td>
</tr>
</table>
<font size=-1>Generated by <a href="http://luc.saillard.free.fr/photon/">Photon %s</a></font>
</div>
</body>
</html>
""" % photon_version)
          
# ------------------------------------------------------------------------ 
def output_image_html_header(f, relativepath, imagefilename, previous_link, next_link): # 
  """ Write in the file, header of an image.html page (body included) """

  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=%s"> 
 <style type="text/css">
   #exifwindow {position:absolute; height:1; width:1; top:0; left:0;}
   #helpwindow {position:absolute; height:1; width:1; top:0; left:0;}
 </style>
""" % (imagefilename,options['charset']))

  if options['exif']:
    f.write (" <script type=\"text/javascript\" language=\"JavaScript1.2\" src=\"exif.js\"></script>\n")
  if options['javascript']:
    f.write (" <script type=\"text/javascript\" language=\"JavaScript1.2\" src=\"shortcuts.js\"></script>\n")
  if previous_link:
    f.write(" <link id=\"previous_image\" rel=\"prev\" href=\"%s\">\n" % previous_link)
  if next_link:
    f.write(" <link id=\"next_image\" rel=\"next\" href=\"%s\">\n" % next_link)

  f.write("</head>")

  if options['exif']:
    f.write("<body bgcolor=\"%s\" onload=\"exif_init()\">\n" % options['body_bgcolor'])
  else:
    f.write("<body bgcolor=\"%s\">\n" % options['body_bgcolor'])


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

  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']));

  vars = { 'img_bgcolor'     : options['img_bgcolor'],
           'display_columns' : options['display_columns'],
           'navbar'          : navbar_for_image_html(relativepath, images_list, index),
           'imgsrc'          : urllib.quote(os.path.join(resolution_string, imageinfo['filename'])),
           'imgalt'          : imageinfo['filename'],
           'version'         : photon_version,
           'body2'           : image_html_body_sub(imageinfo, resolution, previous_image, next_image)}
  
  body = """<div align=center>
<table bgcolor="black">
<tr>
 <td>
  <table width="100%%" cellpadding=4>
  <tr bgcolor="%(img_bgcolor)s">
   <td colspan=%(display_columns)s>%(navbar)s</td>
  </tr>
  <tr bgcolor="%(img_bgcolor)s">
   <td colspan=%(display_columns)s><center><table border=0><tr><td bgcolor=black><img hspace=3 vspace=3 border=0 src="%(imgsrc)s" alt="%(imgalt)s"></td></tr></table></center></td>
  </tr>
""" % vars

  if imageinfo.has_key('comments'):
    body += """
  <tr bgcolor="%s">
   <td colspan=%s><center>%s</center></td>
  </tr>""" % (options['img_bgcolor'],options['display_columns'],imageinfo['comments'])

  body += """
  <tr bgcolor="%(img_bgcolor)s">
   <td colspan=%(display_columns)s>%(body2)s</td>
  </tr>
  </table>
 </td>
</tr>
</table>
<font size=-1>Generated by <a href="http://luc.saillard.free.fr/photon/">Photon %(version)s</a></font>
</div>
""" % vars

  f.write(body)

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

  left_img = '<table border=0><tr><td valign=top width=%d>' % options['thumbsize'][0]
  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]
  left_img += '</td></tr></table>'

  right_img = '<table border=0><tr><td valign=top align=right width=%d>' % 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]
  right_img += '</td></tr></table>'

  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['aspect'] == 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']):

  return """
    <table border=0 width="100%%">
    <tr>
     <td valign=top>%s</td>
     <td valign=top align=center>%s</td>
     <td valign=top align=right>%s</td>
    </tr>
    </table>
   """ % (left_img,sizelist,right_img)


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

  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%%" bgcolor="%s"><tr><td><table width="300" 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_help_layer(f, imageinfo): # 
  """ Output the HTML code for the help window page """

  f.write("""
<div id="helpwindow" style="visibility:hidden">
  <table width="1%%" bgcolor="%s"><tr><td><table width="500" bgcolor="%s">
   <tr><td align="center" valign="top">Shortcuts:</td></tr>
   <tr><td align="left"><b>n/SPACE</b>: Go to the next image</td></tr>
   <tr><td align="left"><b>p/BACKSPACE</b>: Go to the previous image</td></tr>
   <tr><td align="left"><b>s</b>: Start/Stop the slideshow</td></tr>
   <tr><td align="left"><b>+/-</b>: Increase/Decrease by one second the slideshow's period</td></tr>
   <tr><td align="left"><b>h</b>: Show help</td></tr>
   <tr><td align="right" valign="bottom"><a href="" onclick="hide_help_layer(); return false;">Close this box</a></td></tr>
  </table></td></tr></table>
</div>
""" % (options['exif_bordercolor'], options['exif_bgcolor']))
    
# ------------------------------------------------------------------------ 
def output_image_html_footer(f): # 
  """ Output the footer for a image.html page """
  f.write("</body>\n</html>\n")
# ------------------------------------------------------------------------ 
#
# 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 + relativepath.count(os.sep)
  site_home = "../" * ndirs
  url = '<a href="%sindex.html">Albums</a>' % site_home

  for d in relativepath.split(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
  """

  # 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 + relativepath.count(os.sep)
  site_home = "../" * ndirs
  url = '<a href="'+site_home+'index.html">Albums</a>'

  for d in relativepath.split(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 = imagename.find(".")
  image_filename_without_ext = imagename[0:i]

  # if this image is the original size, do not append the resolution 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) """

  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_shortcut_js(pathname): # 
  """ Make a separate javascript file that contains shortcut functions """

  try :
    f = open(pathname, 'w')
  except OSError:
    return 0
  else:
    f.write("""
// Some variables to autodetect browser type
var ns=(document.layers);
var ie=(document.all);
var w3=(document.getElementById && !ie);

var timeout=5000;

// Return an object
function get_object(id)
{
 if(!ns && !ie && !w3) 
   return null;
 if (ie)
   e=eval("document.all." + id);
 else if (ns)
   e=eval('document.links[id]');
 else if (w3)
   e=eval('document.getElementById(id)');
 return e;
}

// Change the current page to the id found in the page
function jumpto(id)
{
  e = get_object(id);
  if ((e != null) && (e.href != null)) {
    if (mytimeout) {
      location.href = e.href + "?slideshow=" + timeout;
    } else {
      location.href = e.href;
    }
  }
}

// Change the current page
function next_page()
{
  jumpto('next_image');
}

function previous_page()
{
  jumpto('previous_image');
}

function show_help_layer()
{
  if (ie)
    help_layer=eval('document.all.helpwindow.style');
  else if (ns)
    help_layer=eval('document.layers["helpwindow"]');
  else if (w3)
    help_layer=eval('document.getElementById("helpwindow").style');

  if (ie)
   {
     documentWidth  =document.body.offsetWidth/2+document.body.scrollLeft-20;
     documentHeight =document.body.offsetHeight/2+document.body.scrollTop-20;
     help_layer.visibility="visible";
   }    
  else if (ns)
   {
     documentWidth=window.innerWidth/2+window.pageXOffset-20;
     documentHeight=window.innerHeight/2+window.pageYOffset-20;
     help_layer.visibility ="show";
   }
  else if (w3)
   {
     documentWidth=self.innerWidth/2+window.pageXOffset-20;
     documentHeight=self.innerHeight/2+window.pageYOffset-20;
     help_layer.visibility="visible";
   }
  help_layer.left=documentWidth-250;
  help_layer.top =documentHeight-125;
  help_isshow=1;
}

function hide_help_layer()
{
  if (ie||w3)
    help_layer.visibility="hidden";
  else
    help_layer.visibility="hide";
  help_isshow=0;
}

// Activate/Deactivate the slideshow
var mytimeout = 0;
function toggle_slideshow()
{
  if (!mytimeout)
   {
     mytimeout = setTimeout("next_page()",timeout);
     window.status='Slideshow set to ' + (timeout/1000) + ' seconds';
   }
  else
   {
     clearTimeout(mytimeout);
     mytimeout=0;
     window.status='Stopping Slideshow';
   }
}

// Manage timeout for the slideshow
function modify_timeout(t)
{
  timeout+=t;
  if (timeout<1000)
    timeout=1000;
  if (mytimeout)
  { // If the counter is active, reactivate it !
    toggle_slideshow();
    toggle_slideshow();
  }
  else
  {
     window.status='Slideshow timeout set to ' + (timeout/1000) + ' seconds';
  }
}

// Event Handler that receive Key Event
function getkey(e)
{
  if (e == null)
   { // IE
     kcode = window.event.keyCode;
   } 
  else
   { // Mozilla
     kcode = e.which;
   }
  key = String.fromCharCode(kcode).toLowerCase();
//  alert("pressed " + kcode + " <=> " + key);
  switch(key)
   {
     case "n":
     case " ":
       next_page();
       return false;
     case "p":
       previous_page();
       return false;
     case "s":
       toggle_slideshow();
       return false;
     case "+":
       modify_timeout(1000);
       return false;
     case "-":
       modify_timeout(-1000);
       return false;
     case "h":
       show_help_layer();
       return false;
   }
  switch(kcode)
   {
     case 8:
       previous_page();
       return false;
   }
  return true;
}

if(w3 || ie)
{
  document.onkeypress = getkey;
} 
else
{
  document.captureEvents(Event.KEYUP);
  document.onkeyup = getkey; 
  document.captureEvents(Event.KEYPRESS);
  document.onkeypress = getkey;
}

// Test if the slideshow is active
var argstr = location.search.substring(1, location.search.length)
var args = argstr.split('&');
for (var i = 0; i < args.length; i++)
{
  var arg = unescape(args[i]).split('=');
  if (arg[0] == "slideshow") 
   { // ... and set timeout according to the last value
     timeout=parseInt(arg[1]);
     toggle_slideshow();
   }
}

// Some code for preloading the next image
/*
e = get_object('next_image');
if ((e != null) && (e.href != null)) {
  preload_image = new Image();
  preload_image.onload = loadnextimage();
  preload_image.src = e.href;
}
*/
""")
    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

# ------------------------------------------------------------------------ 
def gimp_resize_files(fileslist,flush=0): # 
  """ Use Gimp to resize an images list"""

  # Test Gimp version, script-fu changes with gimp-2.0
  gimp_version = gimp_get_version(options['gimp_program'])
  if gimp_version is None:
    gimp_copy_image_function = "gimp-channel-ops-duplicate"  
  elif gimp_version >= 0x020000:
    gimp_copy_image_function = "gimp-image-duplicate"  
  else:
    gimp_copy_image_function = "gimp-channel-ops-duplicate"  

  # Create our batch file for gimp
  batchfile = os.path.join(options['tempdir'],'photon.scm')
  prefix_in = os.path.join(options['tempdir'],'in')
  prefix_out = os.path.join(options['tempdir'],'out')
  try :
    #f = open(batchfile, "wb")
    f = codecs.open(batchfile,"wb",'utf-8');
  except OSError:
    return 0
  else:
    f.write("""; photon.scm
; Copyright: Luc Saillard <luc(@)saillard.org> 2002-4
; Licence: Artistic License
; Gimp Script-Fu
; Plugin to resize all files in a batch using the best quality from the gimp

; create a thumbnail from a filename
(define (create-thumbnail filename_in filename_out tn_width tn_height jpeg_quality)
  (let* 
      ((image    (car (gimp-file-load 1 filename_in filename_in)))
       (drawable (car (gimp-image-active-drawable image))))
       
    (gimp-image-undo-disable image)
    (gimp-image-scale image tn_width tn_height)
    (file-jpeg-save 1 image drawable filename_out filename_out jpeg_quality 0.0 1 1 "" 0 1 0 0)
    (gimp-image-delete image)
    ))

; create a thumbnail with a already loaded image
(define (create-thumbnail-multiple image filename_out tn_width tn_height jpeg_quality)
  (let* 
      ((image_copy    (car (%s image)))
       (drawable_copy (car (gimp-image-active-drawable image_copy))))
       
    (gimp-image-undo-disable image_copy)
    (gimp-image-scale image_copy tn_width tn_height)
    (file-jpeg-save 1 image_copy drawable_copy filename_out filename_out jpeg_quality 0.0 1 1 "" 0 1 0 0)
    (gimp-image-delete image_copy)
    ))
""" % gimp_copy_image_function)

    #
    # Ok, for each files in fileslist, we generate a scrit-fu that:
    #    read the file (set! image (car (gimp-file-load 1 \"in.jpeg\" \"in.jpeg\")))
    #    create all thumbnails for this images
    #                  (create-thumbnail-multiple image \"out.jpeg\" 640 480 jpeg_quality)
    #    free memory for the last image
    # We have one function that do in one shot
    #                  (create-thumbnail "in.jpeg" "out" 640 480 jpeg_quality)
    # The big problem is Gimp 2.x: Gimp want utf-8 string, but some file can be with
    # another locale. If we convert filename in UTF-8, gimp can load the file (file not found)
    # So to fix this problem, we link in the tempdir, all the input file.
    #
    oldfile=""
    i=0
    while i < len(fileslist):
      file=fileslist[i]

      (nam,ext) = os.path.splitext(file[0])
      filein = "%s-%d%s" % (prefix_in,i,ext)
      fileout = "%s-%d%s" % (prefix_out,i,ext)
      os.symlink(os.path.abspath(file[0]),filein)
      os.symlink(os.path.abspath(file[1]),fileout)

      vars = {  
                'ifnam_uni'  : unicode(file[0],options['charset']),
                'ifnam'      : filein,
                'ofnam_uni'  : unicode(file[1],options['charset']),
                'ofnam'      : fileout,
                'img_cur'    : i,
                'img_max'    : len(fileslist)-1,
                'img_width'  : file[2][0],
                'img_height' : file[2][1],
                'img_qual'   : file[3]
      }

      if (file[0] == oldfile):
        # The next image is in the same sequence than the one present
        f.write("""
(gimp-message "Saving %(ofnam_uni)s  %(img_cur)d/%(img_max)d")
(create-thumbnail-multiple image "%(ofnam)s" %(img_width)d %(img_height)d %(img_qual)f)
""" % vars)
        if (i+1<len(fileslist)) and (file[0] != fileslist[i+1][0]):
          f.write("(gimp-image-delete image)\n")
      else:
        if (i+1<len(fileslist) and file[0] == fileslist[i+1][0]):
          # At least two images is pending
          f.write("""
(gimp-message "Loading %(ifnam_uni)s")
(set! image (car (gimp-file-load 1 "%(ifnam)s" "%(ifnam)s")))
(gimp-message "Saving %(ofnam_uni)s  %(img_cur)d/%(img_max)d")
(create-thumbnail-multiple image "%(ofnam)s" %(img_width)d %(img_height)d %(img_qual)f)
""" % vars)
        else:
          # The image and the next image is different
          f.write("""
(gimp-message "Loading %(ifnam_uni)s")
(gimp-message "Saving %(ofnam_uni)s  %(img_cur)d/%(img_max)d")
(create-thumbnail "%(ifnam)s" "%(ofnam)s" %(img_width)d %(img_height)d %(img_qual)f)
""" % vars)
      oldfile=file[0]
      i+=1

    f.write("(gimp-quit 0)\n\n")
    f.close()
    ret = os.system("env LANG=C LC_ALL=C %s --no-data --no-interface --verbose --batch '(load \"%s\")'" %
        (options['gimp_program'],batchfile))
    if os.WEXITSTATUS(ret):
      print "Can't execute gimp."
    # Clean up tempfile
    os.unlink(batchfile)
    i=0
    while i < len(fileslist):
      file=fileslist[i]
      (nam,ext) = os.path.splitext(file[0])
      os.unlink("%s-%d%s" % (prefix_in,i,ext))
      os.unlink("%s-%d%s" % (prefix_out,i,ext))
      i+=1
  


# ------------------------------------------------------------------------ 


# ------------------------------------------------------------------------ 
def gimp_get_version(prog): # 
  """ Launch gimp to query the version"""
  (size , version_string) = getstatusoutput("%s --version" % prog)
  if size:
    print "Gimp not found ? (ERROR:%s)\n" % version_string
    return None
  m = re.search("(\d+)\.(\d+)\.(\d+)",version_string)
  if m:
    return (  (int(m.group(1))<<16)
            + (int(m.group(2))<<8)
            + (int(m.group(3))))
  else:
    print "Bad version ? gimp is not installed ?\n"
    print "ERROR: %s\n" % version_string
    return None
# ------------------------------------------------------------------------ 

# ------------------------------------------------------------------------ 
def find_gimp_program(): # 
  """ Launch gimp to query the version"""
  for prog in [ options['gimp_program'] , 'gimp-2.0', 'gimp-1.2', 'gimp' ]:
    if gimp_get_version(prog) is not None:
      return prog
  return None
# ------------------------------------------------------------------------ 

# ------------------------------------------------------------------------ 
def is8bit(string): #
  return re.compile("[\x80-\xff]").search(string)
# ------------------------------------------------------------------------ 
  

# ------------------------------------------------------------------------ 
def mymkdtemp(suffix="", prefix="photon", dir=None): #
    """mkdtemp([suffix, [prefix, [dir]]])
    User-callable function to create and return a unique temporary
    directory.  The return value is the pathname of the directory.

    The directory is readable, writable, and searchable only by the
    creating user.

    Caller is responsible for deleting the directory when done with it.

    Note: stolen from python 2.3 and adapted to work for old python interpreter
    """

    from random import randrange

    if dir is None:
        dir = gettempdir()

    while 1:
      i = randrange(0,999999)
      file = os.path.join(dir, prefix + str(i) + suffix)
      try:
        os.mkdir(file, 0700)
        return file
      except OSError, e:
        if e.errno == _errno.EEXIST:
          continue # try again
        raise

# ------------------------------------------------------------------------ 

  




# Work around for python < 2.3
try:
  from tempfile import mkdtemp
except ImportError:
  mkdtemp = mymkdtemp

try:
  locale.setlocale(locale.LC_ALL,'')
except locale.Error, x:
    print >> sys.stderr, '*** Warning:', x
try:
  options['charset'] = locale.nl_langinfo(locale.CODESET)
except AttributeError:
  if os.getenv('CHARSET') is None:
    print "Warning: You have an old python interpreter, and you have not defined"
    print "CHARSET environment variable. I will use %s by default" % options['charset']
  else:
    options['charset'] = os.getenv('CHARSET')
 
if __name__ == "__main__":
#   import profile
#   profile.run('main()')
    main()


