summaryrefslogtreecommitdiff
path: root/trunk/gallery/dimbola-gallery.py
blob: 04a5b6fd88e50fcb181c5140c5e2fd4627da7740 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
#!/usr/bin/python

import os
import subprocess
import sys

import pyexiv2

class DefaultDict(dict):

    def __getitem__(self, key):
        if key in self:
            return dict.__getitem__(self, key)
        else:
            return ""

class App(object):

    def run(self):
        self.target_dir = sys.argv[2]
        self.root = os.path.abspath(sys.argv[1])
        self.index_template = self.read_template("index")
        self.image_template = self.read_template("image")
        self.index_image_template = self.read_template("indeximage")
        self.index_dir_template = self.read_template("indexdir")
        for parent, dirname, subdirs, images in self.find_images(self.root):
            self.generate_html_for_dir(parent, dirname, subdirs, images)

    def read_template(self, basename):
        return file(basename + ".template").read()
        
    def find_images(self, root):
        for dirname, dirnames, filenames in os.walk(root, topdown=False):
            filenames = [x for x in filenames if self.is_image_file(dirname, x)]
            dirnames = [x for x in dirnames if self.has_image_files(dirname, x)]
            if dirnames or filenames:
                if dirname == root:
                    parent = None
                else:
                    parent = self.chop_root(root, os.path.dirname(dirname))
                dirname = self.chop_root(root, dirname)
                yield parent, dirname, dirnames, filenames

    def chop_root(self, root, pathname):
        if pathname == root:
            return "."
        if not root.endswith(os.sep):
            root += os.sep
        if pathname == root:
            return "."
        assert pathname.startswith(root), "%s %s" % (pathname, root)
        return pathname[len(root):]

    def is_image_file(self, dirname, basename):
        return basename.lower().endswith(".jpg")
        
    def has_image_files(self, dirname, basename):
        fullname = os.path.join(dirname, basename)
        basenames = os.listdir(fullname)
        for x in basenames:
            if self.is_image_file(fullname, x):
                return True
        return False

    def generate_html_for_dir(self, parent, dirname, subdirs, images):
        if not os.path.exists(self.target(dirname)):
            os.makedirs(self.target(dirname))
        self.generate_html_for_index(parent, dirname, subdirs, images)
        for i in range(len(images)):
            image = images[i]
            prev = images[i-1]
            next = images[(i+1) % len(images)]
            self.generate_html_for_image(dirname, image, prev, next)

    def target(self, pathname, *args):
        return os.path.join(self.target_dir, pathname, *args)

    def generate_html_for_index(self, parent, dirname, subdirs, images):
        imagelist = self.generate_snippet_for_index_image_list(dirname, images)
        subdirlist = self.generate_snippet_for_subdir_list(parent, dirname, 
                                                           subdirs)
        values = {
            "directorydescription": os.path.abspath(dirname),
            "indeximagelist": imagelist,
            "subdirlist": subdirlist,
        }
        self.apply_template(dirname, "index.html", self.index_template, values)

    def generate_snippet_for_index_image_list(self, dirname, images):
        snippet = []
        
        for image in images:
            basename, suffix = os.path.splitext(image)
            target_dirname = self.target(dirname)
            image_path = os.path.join(self.root, dirname, image)
            thumb = os.path.basename(self.thumbnail_path(dirname, image))
            values = {
                "imagebasename": basename,
                "thumbnailname": thumb,
                "imagepathname": self.relative_path(target_dirname, image_path)
            }
            snippet.append(self.index_image_template % values)
        
        return "".join(snippet)

    def generate_snippet_for_subdir_list(self, parent, dirname, subdirs):
        snippet = []
        
        if parent:
            target_dirname = self.target(dirname)
            target_parent = self.target(parent)
            relative_parent = self.relative_path(target_dirname, target_parent)
            subdirs = [relative_parent] + subdirs
        
        for subdir in subdirs:
            values = {
                "subdirname": subdir,
            }
            snippet.append(self.index_dir_template % values)
        
        return "".join(snippet)

    def generate_html_for_image(self, dirname, image, prev, next):
        basename, suffix = os.path.splitext(image)
        target_dirname = self.target(dirname)
        image_path = os.path.join(self.root, dirname, image)
        prev_basename, suffix = os.path.splitext(os.path.basename(prev))
        next_basename, suffix = os.path.splitext(os.path.basename(next))
        values = DefaultDict({
            "description": basename,
            "imagepathname": self.relative_path(target_dirname, image_path),
            "nextimage": next_basename + ".html",
            "previmage": prev_basename + ".html",
        })
        img = pyexiv2.Image(image_path)
        img.readMetadata()
        for key in img.exifKeys() + img.iptcKeys():
            values[key] = img[key]
        self.apply_template(dirname, basename + ".html", self.image_template,
                            values)
        self.create_thumbnail(dirname, image)

    def common_ancestor(self, path1, path2):
        """Find the common ancestor directory of two paths.
        
        Both paths must be absolute.
        
        """
        
        parts1 = path1.split(os.sep)
        parts2 = path2.split(os.sep)
        parts = []
        while parts1 and parts2 and parts1[0] == parts2[0]:
            parts.append(parts1[0])
            del parts1[0]
            del parts2[0]
        return os.sep.join(parts) + os.sep

    def relative_path(self, dirname, pathname):
        """Create a relative path from dirname to pathname.
        
        For example, if dirname is '/home/liw/public_html/gallery' and
        pathname is '/home/liw/public_html/images/lamola/img_1234.jpg',
        this function would return '../images/lamola/img_1234.jpg'.
        
        """

        dirname = os.path.abspath(dirname)
        pathname = os.path.abspath(pathname)
        if not dirname.endswith(os.sep):
            dirname += os.sep
        common_ancestor = self.common_ancestor(dirname, pathname)
        dirname_relative = dirname[len(common_ancestor):]
        dirname_relative = [".." for x in dirname_relative.split(os.sep) if x]
        dirname_relative = os.sep.join(dirname_relative)
        pathname_relative = pathname[len(common_ancestor):]
        return os.path.join(dirname_relative, pathname_relative)

    def apply_template(self, dirname, filename, template, values):
        self.write(self.target(dirname, filename), template % values)

    def write(self, filename, contents):
        f = file(filename, "w")
        f.write(contents)
        f.close()

    def thumbnail_path(self, dirname, image):
        basename, suffix = os.path.splitext(image)
        return os.path.join(self.target_dir, dirname, 
                            basename + "_thumbnail.jpg")

    def create_thumbnail(self, dirname, image):
        image_path = os.path.join(self.root, dirname, image)
        subprocess.check_call(["convert", "-geometry", "200x200", image_path,
                               self.thumbnail_path(dirname, image)])

if __name__ == "__main__":
    App().run()