forked from rleh/static-photogallery
-
Notifications
You must be signed in to change notification settings - Fork 0
/
gallery.py
executable file
·139 lines (122 loc) · 5.72 KB
/
gallery.py
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
#!/usr/bin/env python3
import glob, os
import collections
import jinja2
import shutil
from PIL import Image, ExifTags
from multiprocessing import Pool
import argparse
parser = argparse.ArgumentParser(description='Statically generated photogallery')
parser.add_argument('source', type=str, help='Source directory of images.')
parser.add_argument('-d', '--destination', type=str, default='./html/',
help='Destination directory for generated HTML and thumbnails.')
parser.add_argument('-s', '--static', type=str, default="",
help='Web URL (absolute path) to static folder.')
parser.add_argument('-o', '--original', type=str, default="",
help='Web URL (absolute path) to original images.')
parser.add_argument('-j', '--jobs', type=int, default=8,
help='Specifies the number of thumbnail generation jobs to run simultaneously.')
parser.add_argument('-t', '--title', type=str, default="Static Photogallery",
help='Prefix for the HTML page title.')
args = parser.parse_args()
GalleryItem = collections.namedtuple('GalleryItem', 'name dir path thumbnail_small thumbnail_large')
templateLoader = jinja2.FileSystemLoader(searchpath="./")
templateEnv = jinja2.Environment(loader=templateLoader)
rootpath = args.source
output_path = args.destination + '/'
output_static_path = os.path.join(output_path, 'static')
output_thumbnail_path = output_path
web_static_path = args.static
web_original_path = args.original
def recurse_files(path):
item_list = []
dir_list = []
hash_list = []
for inode in sorted(glob.iglob(path + '/**', recursive=False)):
hash_list.append((os.path.basename(inode), os.path.getmtime(inode)))
if os.path.isfile(inode):
thumbnail, thumbnail_large = generate_thumbnail(inode)
item_list.append(GalleryItem(os.path.relpath(inode, path), False, inode, thumbnail, thumbnail_large))
elif os.path.isdir(inode):
#item_list.append(GalleryItem(os.path.relpath(inode, path), True, inode, 'folder-icon', 'folder-icon'))
dir_list.append(str(os.path.basename(inode)))
recurse_files(inode)
else:
print(inode + " is neither a file nor a directory. Skipping...")
generate_gallery_page(path, item_list, dir_list, str(hash(frozenset(hash_list))))
def generate_gallery_page(path, item_list, dir_list, directory_hash):
if web_static_path is "":
static_relpath = os.path.relpath(output_static_path, path)
else:
static_relpath = web_static_path
template = templateEnv.get_template('gallery_page.html.jinja2')
os.makedirs(os.path.join(output_path, os.path.relpath(path, rootpath)), exist_ok=True)
item_list_html = []
for item in item_list:
item_path = os.path.relpath(item.path, rootpath)
thumbnail_small = os.path.relpath(item.thumbnail_small, path)
thumbnail_large = os.path.relpath(item.thumbnail_large, path)
item_list_html.append(GalleryItem(item.name, False, item_path, os.path.basename(thumbnail_small), os.path.basename(thumbnail_large)))
filename = os.path.join(output_path, os.path.relpath(path, rootpath), 'index.html')
with open(filename, 'w') as fh:
fh.write(template.render(
items=item_list_html,
dirs=dir_list,
page_title=os.path.basename(path),
page_title_prefix=args.title,
static_path=static_relpath,
original_path=web_original_path,
)
)
ThumbnailItem = collections.namedtuple('ThumbnailItem', 'src small large')
thumbnail_list = []
def generate_thumbnail(image):
destination = os.path.join(output_thumbnail_path, os.path.relpath(image, rootpath))
directory, _ = os.path.split(destination)
os.makedirs(directory, exist_ok=True)
small = destination + '.small.jpg'
large = destination + '.large.jpg'
if (not os.path.isfile(small)) or (not os.path.isfile(large)):
thumbnail_list.append(ThumbnailItem(image, small, large))
return small, large
def process_thumbnail(param):
try:
im = Image.open(param.src)
if im.mode in ('RGBA', 'LA') or (im.mode == 'P' and 'transparency' in im.info):
# Need to convert to RGBA if LA format due to a bug in PIL (http://stackoverflow.com/a/1963146)
alpha = im.convert('RGBA').getchannel('A')
im = im.convert('RGB')
try:
for orientation in ExifTags.TAGS.keys():
if ExifTags.TAGS[orientation] == 'Orientation': break
exif = dict(im._getexif().items())
if exif[orientation] == 3:
im = im.rotate(180, expand=True)
elif exif[orientation] == 6:
im = im.rotate(270, expand=True)
elif exif[orientation] == 8:
im = im.rotate(90, expand=True)
except Exception as e:
print('Error while rotate image {} according to EXIF data: {}'.format(param.src, str(e)))
im.thumbnail((1920,1200),Image.ANTIALIAS)
im.save(param.large,optimize=True,quality=85)
im.thumbnail((400,250),Image.ANTIALIAS)
im.save(param.small,optimize=True,quality=70)
return True
except Exception as e:
print('Error while creating thumbnail for image {}: {}'.format(param.src, str(e)))
shutil.copyfile('./static/no-thumbnail.jpg', param.small)
shutil.copyfile('./static/no-thumbnail.jpg', param.large)
return e
def batch_process_thumbnails():
pool = Pool(args.jobs)
results = pool.map(process_thumbnail, thumbnail_list)
def copy_static_files():
destination = output_static_path
if os.path.exists(destination):
shutil.rmtree(destination)
shutil.copytree('./static/', destination)
if __name__ == "__main__":
recurse_files(rootpath)
copy_static_files()
batch_process_thumbnails()