from string import Template
#PictureGallery.py, This version released on 26th July 2012

#This allows you to creates a gallery of pictures from a file of image names.
#you need to install the Image module also known as the Python Imaging Library
# from here http://www.pythonware.com/products/pil/
#you need to edit the test code after the "if __name__=="__main__"

#to do: load images+information as JSON files

import os.path
import os
import re
import Image

def combine_dicts(dict1,dict2):
    return dict(dict1.items()+dict2.items())

def file_extension(path):
    pos = path.rfind(".")
    if pos == -1:
        return ""
    else:
        return path[pos:].lower()

def without_extension(path):
    pos = path.rfind(".")
    if pos == -1:
        return path
    else:
        return path[:pos]

def get_image_base(path):
    return without_extension(os.path.basename(path))

def get_image_size(image_path):
    "returns a tuple of (with,height) giving the real size of the image in pixels"
    im = Image.open(image_path)
    size = im.size
    return size

class PictureGallery(object):
    def __init__(self, title):
        self.title = title #use this for title bar
        #self.nb_levels = nb_levels #the number of zoom levels: to do
        self.index_header_template = Template('''<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<meta name="GENERATOR" content="SnapBrowser, http://snapageno.free.fr">
<title>$title</title>
</head>
<body bgcolor="$bg_colour" text="$text_colour"
					link="#aaaaaa" vlink="#aaaaaa" alink="#aaaaaa">
<center>
<h1>$h1_title</h1>
$click_message
$extra_message
<hr>''')
        self.index_footer = """
<hr>
</center>
</body>
</html>
"""
        self.image_page_template = Template('''<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<meta name="GENERATOR" content="SnapBrowser, snapageno.free.fr">
<title>$image_base</title>
</head>
<body bgcolor="$bg_colour" text="$text_colour" link="#aaaaaa" vlink="#aaaaaa" alink="#aaaaaa">
<center>$BeforePrev  Prev $after_prev | <a href="index.htm">Index</a>|&nbsp;<a href="http://snapageno.free.fr">Home</a> |$before_next Next $after_next </center>

<p>
<table>

<tr>
<td align="right">
	<table border bordercolorlight="#aaaaaa">
	<tr>
	<td><img src="$image_base$std_suffix.jpg" width="$std_width" height="$std_height" title="" alt=""></td>
	</tr>
	</table>
<font size="-1">Copyright &copy; $year, </font>
</td></tr></table>
<p>

<p>
</center>
<p><H2>$image_footer</H2></p>
</body>
</html>''')

        self.bg_colour = "black"#default
        self.text_colour = "grey"
        self.h1_title = title #default
        self.year="2012"
        self.std_suffix = "_std"#default string to add to end of image name
        self.std_size = [1500,1500]#default size of box containing standard image, this is a recommended size, the real one may be different
        self.thumb_suffix = "_thm"#default
        self.thumb_size = [150,150]#default size of box containing thumb, this is a recommended size, the real one may be different
        self.click_message = "Click on thumbnails"
        self.extra_message = ""
        self.overwrite = False#by default forbid overwriting a file by one with the same name during generation
        self.thumb_template = Template('<img src="$image_base$thumb_suffix.jpg" vspace="5" hspace="5" width="$thumb_width" height="$thumb_height" border="1" title="" alt="">')
        self.before_thumb_template = Template('<a href="$image_base$std_suffix.htm">')
        self.after_thumb='</a>\r\n'
        self.images = [] #have to load them
        


    def load_from_directory(self, dirpath):
        "loads all image files in a given directory, in that order"
        self.images.extend([os.path.join(dirpath,entry) for entry in os.listdir(dirpath) if file_extension(entry) in [".jpg",".tif",".bmp"]])
        
        
    def load_from_text_file(self, path):
        """loads the image file names from a text file, each image path is on a separate line.
        You call this repeatedly to add more image files. ignores empty lines and lines beginning with #.
"""
        ifh = open(path,"r")
        lines = ifh.readlines()
        ifh.close()
        self.images.append([line.strip() for line in lines if len(line)>0 and line[0]!='#'])
        
    def reduce_image(self,path_original, size_reduced, path_reduced):
        "use size_reduced as a box to reduce the images"
        if os.path.exists(path_reduced) and not self.overwrite:
            return
        #print "reduce_image(",original,size,reduced,")"
        statv = os.stat(path_original)
        atime = statv.st_atime
        mtime = statv.st_mtime
        if path_reduced == path_original:
                print "reduce_image called on same input and output",original
                sys.exit(1)
        img = Image.open(path_original)
        img.thumbnail(size_reduced,Image.ANTIALIAS)
        img.save(path_reduced,"JPEG")
        os.utime(path_reduced,(atime,mtime))#copy time 
        return mtime
#you will be likely to use this one        
    def set_h1_title(self, h1_title):
        self.h1_title = h1_title
    def set_std_size(size):
        self.std_size= size # size of box containing standard image, this is a recommended size, the real one may be different
    def set_thumb_size(size):
        self.thumb_size= size # size of box containing standard image, this is a recommended size, the real one may be different
    def set_bg_colour(self, bg_colour):
        self.bg_color = bg_colour
#it's unlikely you will use these:
    def set_thumb_suffix(suffix):
        self.thumb_suffix = suffix
    def set_std_suffix(suffix):
        self.std_suffix = suffix
 
    def write(self,target_directory):
        self.target_dir = target_directory
        "Writes both the HTML of the index, the individual HTML pages perm image and the image files"
        ofh = open(os.path.join(target_directory,"index.htm"),"w")
        header = self.index_header_template.substitute(self.__dict__)
        footer = self.index_footer
        ofh.write(header)
        image_counter = 1
        nb_images = len(self.images)
        for image_path in self.images:
            print "image_path",image_path 
            single_image_page = SingleImagePage(image_path,self,image_counter,nb_images - image_counter)
            single_image_page.write_images()#write images first so we know real sizes of thumbs and standard images
            single_image_page.write_HTML()
            ofh.write(self.before_thumb_template.substitute(combine_dicts(self.__dict__, single_image_page.__dict__)))
            ofh.write(self.thumb_template.substitute(combine_dicts(self.__dict__, single_image_page.__dict__)))
            ofh.write(self.after_thumb)
            image_counter += 1
        ofh.write(footer)
        ofh.close()

class SingleImagePage(object):
    def __init__(self,image_path,parent,imageNb,nbLeft):
        
        self.image_path=image_path
        self.image_base = get_image_base(image_path)
        #print "image_base" ,self.image_base
        self.parent = parent
        self.image_nb = imageNb
        if self.image_nb == 1:
            self.BeforePrev = ""
            self.after_prev = ""
        else:
            self.BeforePrev = '<a href="%s.htm">'%(get_image_base(parent.images[imageNb -2])+self.parent.std_suffix)
            self.after_prev = "</a>"
        self.nb_left = nbLeft
        if self.nb_left== 0:
            self.before_next = ""
            self.after_next = ""
        else:
            self.before_next = '<a href="%s.htm">'%(get_image_base(parent.images[imageNb])+self.parent.std_suffix)
            self.after_next = "</a>"
        self.image_footer=""
                      
    def get_thumb_path(self):
        return os.path.join(self.parent.target_dir,self.image_base+self.parent.thumb_suffix+".jpg")
                      
    def get_std_path(self):
        return os.path.join(self.parent.target_dir,self.image_base+self.parent.std_suffix+".jpg")
        
    def write_HTML(self):
        "writes the html file to display the standard image"
        ofh = open(os.path.join(self.parent.target_dir,self.image_base+self.parent.std_suffix+".htm"),"w")
        page_string = self.parent.image_page_template.substitute(combine_dicts(self.__dict__ ,self.parent.__dict__ ))
        ofh.write(page_string)
        ofh.close()
    def write_images(self):
        "writes thumb and standard size images"
        thumb_target_path = self.get_thumb_path()
        self.parent.reduce_image(self.image_path,self.parent.thumb_size,thumb_target_path)
        thumb_size = get_image_size(thumb_target_path)
        self.thumb_width = thumb_size[0]
        self.thumb_height = thumb_size[1]
        std_target_path = self.get_std_path()
        self.parent.reduce_image(self.image_path,self.parent.std_size,std_target_path)
        std_size = get_image_size(std_target_path)
        self.std_width = std_size[0]
        self.std_height = std_size[1]

#below is sample test code
if __name__ == "__main__":
    g = PictureGallery("Craon")
    g.set_h1_title("Le chateau de Craon")
    #g.image_page_template.substitute(g.__dict__, image_base="",BeforePrev="",after_prev="",before_next="",after_next="",image_footer="")
    
    g.load_from_directory(r"E:\Mes images\Chateaux\Craon\BestOf")
    g.write(r"E:\Mes images\Chateaux\Craon\BestOf\HTML")#the directory had to be created first
    
