Small improvements in wrvalidators.py.
[philipp/winterrodeln/wrpylib.git] / scripts / createthumbnails.py
1 #!/usr/bin/python3
2 """Creates the image thumbnails or icons for sledruns to be used in the sledmap or other application.
3 Can be used in a python session or at the command line.
4
5 usage: createthumbnails.py [-h] {thumbnail,icon} inifile [inifile ...]
6
7 Creates the image thumbnails or icons for sledruns to be used in the sledmap
8 application.
9
10 positional arguments:
11   {thumbnail,icon}  thumbnails or icons?
12   inifile           inifile.ini (See:
13                     https://www.winterrodeln.org/trac/wiki/ConfigIni)
14
15 optional arguments:
16   -h, --help        show this help message and exit
17
18
19 Command line usage:
20 $ export LANG=de_AT.utf8
21 $ export LC_CTYPE=de_AT.utf8
22 $ python createthumbnails.py thumbnail inifile1.ini ...
23 $ # or:
24 $ python createthumbnails.py icon inifile1.ini ...
25
26 One or more .ini configuration files can be given.
27 At the end, the following entries have to be present:
28
29     [mysql]
30     host=localhost
31     dbname=philipp_winterrodeln_wiki
32     user_name=philipp_www
33     user_pass=YYYYYY
34
35     [mediawiki]
36     imagedir=/home/philipp/www/winterrodeln.org/mediawiki/images
37
38     [sledmap]
39     sledrunimagedir=/home/philipp/www/winterrodeln.org/karte/mediawiki_images
40     sledrunicondir=/home/philipp/www/winterrodeln.org/karte/mediawiki_icons
41
42 """
43 import argparse
44 import configparser
45 import os
46 import hashlib
47 import MySQLdb
48 from PIL import Image, ImageFilter
49
50
51 def image_to_icon(im, width, height):
52     """The icon will have a size of width times height and contains a centered sub-part of the image."""
53     if im.size[0] / float(width) > im.size[1] / float(height):
54         # scale image to height
55         im.thumbnail((int(round(im.size[0] * im.size[1] / height)), height), Image.ANTIALIAS)
56         # crop image (left, upper, right (excl), lower (excl))
57         left = (im.size[0] - width) // 2
58         im = im.crop((left, 0, left + width, height))
59     else:
60         # scale image to width
61         im.thumbnail((width, int(round(im.size[1] * im.size[0] / width))), Image.ANTIALIAS)
62         # crop image (left, upper, right (excl), lower (excl))
63         upper = (im.size[1] - height) // 2
64         im = im.crop((0, upper, width, upper + height))
65     # sharpen
66     im = im.filter(ImageFilter.SHARPEN)
67     return im
68
69
70 def image_to_thumbnail(im, width, height):
71     """The thumbnail will have a equal or smaller width and height as given. The aspect ratio stays the same."""
72     im.thumbnail((width, height), Image.ANTIALIAS)
73     im = im.filter(ImageFilter.SHARPEN)
74     return im
75
76
77 def update_image_dir(mcon, mediawiki_image_dir, dest_dir, image_function, ignore_existing=True):
78     """Takes all image names from the mysql database (mcon), reads it from mediawiki_image_dir, 
79     processed it as given in the image_function and stores it in the dest_dir with the original filename.
80     It does not delete the images that might be present in dest_dir, but overwrites the images with the 
81     same filenames.
82
83     :param mcon: mysql connection
84     :param mediawiki_image_dir: directory of the mediawiki image directory
85     :param dest_dir: output directory
86     :param image_function: python function that takes a PIL Image as parameter and returns a modified PIL Image.
87     :param ignore_existing: True (default) if already existing image file names in the dest dir should be ignored.
88     """
89     cu = mcon.cursor()
90     sql = "select image from wrsledruncache where image is not null order by image"
91     cu.execute(sql)
92     for image, in cu:
93         image = image.replace(' ', '_')
94         # Create md5sum out of the image filename
95         md5 = hashlib.md5()
96         md5.update(image.encode('UTF8'))
97         hd = md5.hexdigest()
98         # Build source and destination path names
99         source_file = os.path.join(mediawiki_image_dir, hd[0], hd[0:2], image)
100         dest_file = os.path.join(dest_dir, image)
101         if ignore_existing and os.path.exists(dest_file): continue
102         print(('{0}...'.format(image)))
103         im = Image.open(source_file)
104         im = image_function(im)
105         im.save(dest_file, "JPEG")
106
107
108 def update_image_dir_by_inifile(inifile, mode):
109     """ Same as update_image_dir but reads the arguments from an .ini file.
110
111     :param inifile: filename of an .ini file or a list of .ini files.
112     :param mode: 'thumbnail' or 'icon'
113     """
114     config = configparser.ConfigParser()
115     config.read(inifile)
116
117     host = config.get('mysql', 'host')
118     dbname = config.get('mysql', 'dbname')
119     user = config.get('mysql', 'user_name')
120     passwd = config.get('mysql', 'user_pass')
121     mcon = MySQLdb.connect(host=host, db=dbname, user=user, passwd=passwd, charset='utf8mb4')
122
123     mediawiki_image_dir = config.get('mediawiki', 'imagedir')
124     if mode == 'thumbnail':
125         dest_dir = config.get('sledmap', 'sledrunimagedir')
126         image_function = lambda img: image_to_thumbnail(img, 200, 200)
127     elif mode == 'icon':
128         dest_dir = config.get('sledmap', 'sledrunicondir')
129         image_function = lambda img: image_to_icon(img, 80, 80)
130     update_image_dir(mcon, mediawiki_image_dir, dest_dir, image_function)
131
132     mcon.close()
133
134
135 if __name__ == '__main__':
136     parser = argparse.ArgumentParser(
137         description='Creates the image thumbnails or icons for sledruns to be used in the sledmap application.')
138     parser.add_argument('type', choices=['thumbnail', 'icon'], help='thumbnails or icons?')
139     parser.add_argument('inifile', nargs='+', help='inifile.ini, see: https://www.winterrodeln.org/trac/wiki/ConfigIni')
140     args = parser.parse_args()
141
142     update_image_dir_by_inifile(args.inifile, args.type)