From fe69b6354efa3c52bea1edc2ec79e6cc7dc71bb9 Mon Sep 17 00:00:00 2001 From: mbe Date: Sat, 19 Jul 2014 08:40:52 +0200 Subject: [PATCH] Initial commit. --- .gitattributes | 22 ++++++++++ .gitignore | 2 + psthumbgen.py | 117 +++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 141 insertions(+) create mode 100644 .gitattributes create mode 100644 .gitignore create mode 100644 psthumbgen.py diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..412eeda --- /dev/null +++ b/.gitattributes @@ -0,0 +1,22 @@ +# Auto detect text files and perform LF normalization +* text=auto + +# Custom for Visual Studio +*.cs diff=csharp +*.sln merge=union +*.csproj merge=union +*.vbproj merge=union +*.fsproj merge=union +*.dbproj merge=union + +# Standard to msysgit +*.doc diff=astextplain +*.DOC diff=astextplain +*.docx diff=astextplain +*.DOCX diff=astextplain +*.dot diff=astextplain +*.DOT diff=astextplain +*.pdf diff=astextplain +*.PDF diff=astextplain +*.rtf diff=astextplain +*.RTF diff=astextplain diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4e0bbdf --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +venv/ +.idea/ diff --git a/psthumbgen.py b/psthumbgen.py new file mode 100644 index 0000000..d009545 --- /dev/null +++ b/psthumbgen.py @@ -0,0 +1,117 @@ +import sys +import os +import re +import argparse +import errno +import time +from PIL import Image +from multiprocessing import Pool +from multiprocessing import Value + + +class State(object): + def __init__(self): + self.counter = Value('i', 0) + self.start_ticks = Value('d', time.process_time()) + + def increment(self, n=1): + with self.counter.get_lock(): + self.counter.value += n + + @property + def value(self): + return self.counter.value + + @property + def start(self): + return self.start_ticks.value + + +def init(args): + global state + state = args + + +def main(): + args = parse_args() + state = State() + + files = find_files(args.directory) + + with Pool(processes=4, initializer=init, initargs=(state, )) as pool: + pool.map(process_file, files) + + print("{0} files processed in total.".format(state.value)) + + +def parse_args(): + parser = argparse.ArgumentParser( + description="Create thumbnails for Synology Photo Station.") + parser.add_argument("--directory", required=True, + help="Directory to generate thumbnails for. " + "Subdirectories will always be processed.") + + return parser.parse_args() + + +def find_files(dir): + valid_exts = ('jpeg', 'jpg', 'bmp', 'gif') + valid_exts_re = "|".join( + map((lambda ext: ".*\\.{0}$".format(ext)), valid_exts)) + + for root, dirs, files in os.walk(dir): + for name in files: + if re.match(valid_exts_re, name, re.IGNORECASE) \ + and not name.startswith('SYNOPHOTO_THUMB'): + yield os.path.join(root, name) + + +def print_progress(): + global state + state.increment(1) + processed = state.value + if processed % 10 == 0: + print("{0} files processed so far, averaging {1:.2f} files per second." + .format(processed, float(processed) / + (float(time.process_time() - state.start)))) + + +def process_file(file_path): + print(file_path) + + (dir, filename) = os.path.split(file_path) + thumb_dir = os.path.join(dir, 'eaDir_tmp', filename) + ensure_directory_exists(thumb_dir) + + create_thumbnails(file_path, thumb_dir) + + print_progress() + + +def ensure_directory_exists(path): + try: + os.makedirs(path) + except OSError as exception: + if exception.errno != errno.EEXIST: + raise + + +def create_thumbnails(source_path, dest_dir): + im = Image.open(source_path) + + to_generate = (('SYNOPHOTO_THUMB_XL.jpg', 1280), + ('SYNOPHOTO_THUMB_B.jpg', 640), + ('SYNOPHOTO_THUMB_M.jpg', 320), + ('SYNOPHOTO_THUMB_PREVIEW.jpg', 160), + ('SYNOPHOTO_THUMB_S.jpg', 120)) + + for thumb in to_generate: + if os.path.exists(os.path.join(dest_dir, thumb[0])): + continue + + im.thumbnail((thumb[1], thumb[1]), Image.ANTIALIAS) + im.save(os.path.join(dest_dir, thumb[0])) + + +if __name__ == "__main__": + sys.exit(main())