Permalink
Switch branches/tags
Nothing to show
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
278 lines (203 sloc) 9.96 KB
#!/usr/bin/python3
# -*- coding: utf-8; mode: python -*-
"""Create an automatically generated dummy cover to be used during testing.
If available, the program uses metadata found in the publication. An
image for the cover is chosen randomly.
"""
__version__ = "1.0"
__date__ = "20170323"
__author__ = "kthoden@mpiwg-berlin.mpg.de"
import os
import sys
import logging
import configparser
import textwrap
import argparse
from PIL import Image, ImageFont, ImageDraw
logging.basicConfig(level=logging.INFO, format=' %(asctime)s - %(levelname)s - %(message)s')
DIMENSIONS = (2000, 2844) # ratio of 0.703205791106515
BACKGROUND = 0, 0, 0
METADATA_DICT = {'eoa_series': 'Studies', 'eoa_number': '125',
'eoa_authors': ['Klaus Thoden'], 'eoa_title':
'Der ewige Testband', 'eoa_subtitle':
'Experimentell'}
SERIES_COLOURS = {"sources" : (40, 96, 49),
"studies" : (13, 40, 72),
"proceedings" : (173, 54, 50),
"textbooks" : (210, 182, 35)}
def get_cover_image(image_path):
"""Choose a random landscape image from publications in this volume"""
import random
candidates = os.listdir(image_path)
for image in candidates:
if image == ".DS_Store":
candidates.remove(image)
continue
tmp_image = Image.open(image_path + "/" + str(image))
ratio = calculate_ratio(tmp_image)
if ratio < 1:
candidates.remove(image)
chosen_image = random.choice(candidates)
return chosen_image
# def get_cover_image ends here
def calculate_ratio(image_object):
"""Determine the aspect ratio of an image"""
width, height = image_object.size
ratio = float(width)/float(height)
return ratio
# def calculate_ratio ends here
def resize_image(image_object, max_size, dimension):
"""Resize an image, preserve ratio.
Takes three arguments, an image object, the maximal size and the
dimension (width or height).
https://stackoverflow.com/questions/273946/how-do-i-resize-an-image-using-pil-and-maintain-its-aspect-ratio
"""
width, height = image_object.size
if dimension == "height":
height_percent = (max_size/float(height))
wsize = int((float(width)*float(height_percent)))
resized_image = image_object.resize((wsize, max_size), Image.ANTIALIAS)
elif dimension == "width":
width_percent = (max_size/float(width))
hsize = int((float(height)*float(width_percent)))
resized_image = image_object.resize((max_size, hsize), Image.ANTIALIAS)
else:
print("You must either specify height or width as dimension. Exiting.")
sys.exit(0)
return resized_image
# def resize_image ends here
def format_authors(authors_list):
"""Format the list of authors
Input is the start and end point of the authors in a list. Return
both a formatted string and the pure list of authors.
"""
if len(authors_list) == 0:
authors_as_string = ""
if len(authors_list) == 1:
authors_as_string = """%s""" % (authors_list[0])
elif len(authors_list) == 2:
authors_as_string = """%s and %s""" % (authors_list[0], authors_list[1])
elif len(authors_list) > 2:
authors_as_string = """%s""" % authors_list[0]
for author in range(1, len(authors_list) - 1):
authors_as_string += ", " + authors_list[author]
authors_as_string += " and %s" % (authors_list[-1])
return authors_as_string
# def format_authors ends here
def add_watermark(image, watermarkstring):
"""Add a string of text across the cover. Return a rotated image object"""
# https://codenhagen.wordpress.com/2015/12/04/putting-rotated-text-on-images-with-pillow-python/
base_image = Image.open(image)
tmp_img = Image.new("RGBA", (DIMENSIONS[1], DIMENSIONS[0]), (0,0,0,0))
font_colour = (255,0,0)
big_red_font = ImageFont.truetype("Helvetica", 200)
text_canvas = ImageDraw.Draw(tmp_img)
text_canvas.text((0, 0), watermarkstring, font=big_red_font, fill=font_colour)
slanted_image = tmp_img.rotate(60, expand=True)
# add third parameter as transparent mask
# https://stackoverflow.com/questions/5324647/how-to-merge-a-transparent-png-image-with-another-image-using-pil
base_image.paste(slanted_image, (200, 100), slanted_image)
base_image.save(image)
logging.info("Added a watermark to %s." % image)
# return slanted_image
# def add_watermark ends here
def centered(textstring, font_spec):
"""Return coordinates for a centered string."""
tmp_draw = ImageDraw.Draw(Image.new("RGB", DIMENSIONS, BACKGROUND))
string_width, string_height = tmp_draw.textsize(textstring, font=font_spec)
coordinate = DIMENSIONS[0] / 2 - string_width / 2
return coordinate
# def centered ends here
def create_cover(metadata_dict, image_directory, cover_filename, image_is_file):
"""Create a cover using PIL"""
img = Image.new("RGB", DIMENSIONS, BACKGROUND)
upper_part = Image.new("RGB", (DIMENSIONS[0], int(DIMENSIONS[1]/3)), SERIES_COLOURS[metadata_dict['eoa_series'].lower()])
img.paste(upper_part, (0, 0))
title_text = metadata_dict['eoa_title']
subtitle_text = metadata_dict['eoa_subtitle']
authors_text = format_authors(metadata_dict['eoa_authors'])
if len(metadata_dict['eoa_zusatz']) > 0:
authors_text += " {}".format(metadata_dict['eoa_zusatz'])
series_number_text = "{0} {1}".format(metadata_dict['eoa_series'], metadata_dict['eoa_number'])
if metadata_dict['eoa_series'].lower() == "sources":
press_text = "Edition Open Sources"
else:
press_text = "Max Planck Research Library for the History and Development of Knowledge"
if metadata_dict['eoa_series'].lower() == "textbooks":
fill_colour_top = (0, 0, 0)
else:
fill_colour_top = (255, 255, 255)
big_bold_font = ImageFont.truetype(font="Times New Roman Bold", size=120)
medium_font = ImageFont.truetype(font="Times New Roman", size=100)
small_font = ImageFont.truetype(font="Times New Roman", size=80)
text_draw = ImageDraw.Draw(img)
# these will eventually also become candidates for multilines
# text_draw.text((centered(title_text, big_bold_font), 200), title_text, font=big_bold_font, fill=fill_colour_top)
title_text_lines = textwrap.wrap(title_text, width=30)
title_text_joined = "\n".join(title_text_lines)
ttcenter = centered(title_text_joined, big_bold_font)
text_draw.multiline_text((ttcenter, 200), title_text_joined, font=big_bold_font, align="center")
if len(subtitle_text) > 0:
text_draw.text((centered(subtitle_text, medium_font), 350), subtitle_text, font=medium_font, fill=fill_colour_top)
authors_text_lines = textwrap.wrap(authors_text, width=50)
authors_text_joined = "\n".join(authors_text_lines)
ttcenter = centered(authors_text_joined, small_font)
text_draw.multiline_text((ttcenter, int(DIMENSIONS[1]/3)-200), authors_text_joined, font=small_font, align="center")
# text_draw.text((centered(authors_text, small_font), int(DIMENSIONS[1]/3)-200), authors_text, font=small_font, fill=fill_colour_top)
press_text_lines = textwrap.wrap(press_text, width=40)
press_text_lines.append(series_number_text)
press_text_joined = "\n".join(press_text_lines)
ptcenter = centered(press_text_joined, small_font)
text_draw.multiline_text((ptcenter,DIMENSIONS[1]-400), press_text_joined, font=small_font, align="center")
if image_is_file == False:
image_on_cover = Image.open(os.path.join(image_directory, get_cover_image(image_directory)))
else:
image_on_cover = Image.open(image_directory)
MAXIMUM_HEIGHT = 1200
resized_image = resize_image(image_on_cover, MAXIMUM_HEIGHT, "height")
coord = DIMENSIONS[0]/2 - resized_image.width/2
img.paste(resized_image, (int(coord), 1200))
img.save(cover_filename)
logging.info("Wrote %s." % cover_filename)
# def create_cover ends here
if __name__ == '__main__':
parser = argparse.ArgumentParser()
parser.add_argument("image_dir_or_image", help="Path to directory with potential images or a single file.")
parser.add_argument("-c", "--config", help="File that contains the publication data.", default="publication.cfg")
parser.add_argument("-o", "--output", help="Name of output file.", default="Cover.jpg")
parser.add_argument("-nw", "--nowatermark", help="Do not add a watermark to the image.", action="store_true")
args = parser.parse_args()
if args.config:
# if os.path.exists("publication.cfg"):
logging.info("Using %s as publication config" % (args.config))
config = configparser.ConfigParser()
config.read(args.config)
list_of_authors = []
for entry in range(0, 5):
author_label = "Author" + str(entry + 1)
tmp_author = config['Authors'][author_label]
if len(tmp_author) > 0:
list_of_authors.append(tmp_author)
METADATA_DICT.update({'eoa_series' : config['Technical']['Serie']})
METADATA_DICT.update({'eoa_number' : config['Technical']['Number']})
METADATA_DICT.update({'eoa_title' : config['Technical']['Title']})
METADATA_DICT.update({'eoa_subtitle' : config['Technical']['Subtitle']})
METADATA_DICT.update({'eoa_authors' : list_of_authors})
METADATA_DICT.update({'eoa_zusatz' : config['Authors']['Zusatz']})
else:
logging.info("Using the built-in metadata as publication config")
OUTFILE = args.output
IMAGES = args.image_dir_or_image
if os.path.isfile(IMAGES):
image_is_file = True
elif os.path.isdir(IMAGES):
image_is_file = False
else:
print("No valid image or directory given. Exiting.")
sys.exit()
create_cover(METADATA_DICT, IMAGES, OUTFILE, image_is_file)
if args.nowatermark:
logging.info("No watermark. Be careful. This is not meant to be an official cover.")
else:
add_watermark(OUTFILE, "Automatically generated cover.\nDo not use in production!")
# finis