#!/usr/bin/python3 import argparse import re import subprocess from pathlib import Path from typing import Tuple OUTPUT_DIR = Path('output') IMAGE_SIZE_PATTERN = re.compile(r'^\d+x\d+$') def upper_first_letter(text: str) -> str: if not text: return text return text[0].upper() + text[1:] def format_filename(filename: str) -> Tuple[str, str]: parts = re.split(r'[-_.]', filename) # split filename into artist and image name # example content of parts: ['001', 'davinci', 'lona', 'lisa', 'jpg'] artist = parts[1] name = ' '.join(parts[2:-1]) return upper_first_letter(artist), upper_first_letter(name) def get_image_size(file: Path) -> Tuple[int, int]: # get the image size in pixel # example output from identify command: 1920x1080 progress = subprocess.run(['identify', '-format', '%[fx:w]x%[fx:h]', str(file)], stdout=subprocess.PIPE) result = progress.stdout.decode('utf-8') if not re.fullmatch(IMAGE_SIZE_PATTERN, result): return 0, 0 width, height = result.split('x') return int(width), int(height) def wrap_text(name: str, image_width: int) -> str: # split name into it words words = name.split(' ') # considering that a letter has 50 pixels on average word_widths = [(len(word) * 50) + 16 for word in words] # calculate if the image width is sufficient for the text if sum(word_widths) < image_width: return name start_index = 0 new_name = words[0] for index, word_width in enumerate(word_widths, start=1): if index == 1: continue sentence_width = sum(word_widths[start_index:index]) if sentence_width > image_width: print(' -- text wrapped', end='') start_index = index - 1 new_name += '\n' else: new_name += ' ' new_name += words[index - 1] return new_name def convert_image(file: Path): artist, name = format_filename(file.name) print(f'\nFilename: {file.name} -> Artist: {artist} -- Name: {name}', end='') # check if the image is in portrait mode is_portrait = False width, height = get_image_size(file) if height > width: print(' -- Portrait', end='') is_portrait = True name = wrap_text(name, width) # run ImageMagick args = [ 'convert', str(file), '-fill', '#fff', '-font', './font/Lato-Regular.ttf', '-pointsize', '90', '-gravity', 'NorthWest' if is_portrait else 'SouthWest', '-stroke', '#000a', '-strokewidth', '10', '-annotate', '+30+20', name, '-stroke', 'none', '-annotate', '+30+20', name, '-font', './font/BonheurRoyale-Regular.ttf', '-pointsize', '120', '-gravity', 'SouthEast', '-stroke', '#000a', '-strokewidth', '10', '-annotate', '+40+5', artist, '-stroke', 'none', '-annotate', '+40+5', artist, str(Path(OUTPUT_DIR, file.name)), ] subprocess.Popen(args) def main(source_dir: Path): # scan for all .jpg files source_files = source_dir.glob('*.jpg') for file in source_files: convert_image(file) print() # print a new line before exit if __name__ == '__main__': parser = argparse.ArgumentParser(description='Text ins Bild') parser.add_argument('source_dir', type=Path, help='source directory with images') args = parser.parse_args() source_dir = args.source_dir main(source_dir)