def main(show=False, test=""): start_time = time.time() doc = loads(open( os.path.join(get_project_root(), 'config', 'covers.toml'), ).read()) output_size = (doc['config']['output-size'], doc['config']['output-size']) logo_size = get_logo_size(output_size) padded_logo_location = get_logo_location(output_size) w_base = resize_and_fade_logo(get_white_logo(), logo_size, output_size, padded_logo_location, logo_transparency_percentage) b_base = resize_and_fade_logo(get_black_logo(), logo_size, output_size, padded_logo_location, logo_transparency_percentage) if test != "": test_image = get_test_image(output_size, test) else: test_image = None for cover in doc['cover']: try: cover_image = get_cover_image(cover) # Add alpha channel so mode matches images with transparency, # allowing us to use alpha_composite if cover_image.mode == 'RGB': cover_image.putalpha(255) # If scale defined, resize cover to scaled size, using pad to # avoid any cropping, otherwise scale to output size to fit if cover.get('scale'): cover_image = scale_and_pad_cover(cover_image, output_size, cover.get('scale'), cover.get('position')) else: cover_image = ImageOps.fit( cover_image, output_size, Image.ANTIALIAS) # If a background colour is defined, create a new image with # that colour, and composite the cover onto it. if cover.get('bg-colour'): base = Image.new('RGBA', output_size, cover.get('bg-colour')) cover_image = Image.alpha_composite(base, cover_image) if cover.get('colour-gradient'): if not cover.get('do-not-greyscale', False): cover_image = cover_image.convert('L').convert('RGBA') gradient_image = ImageOps.fit(get_gradient(cover.get('colour-gradient')), output_size, Image.ANTIALIAS) gradient_image.putalpha(255) opacity = cover.get('gradient-opacity', 70)/100 cover_image = Image.blend(cover_image, gradient_image, opacity) # Composite the logo watermark on top, black logo as default if cover.get('use-white-logo'): if cover.get('logo-opacity'): cover_image = Image.alpha_composite(cover_image, resize_and_fade_logo(get_white_logo(), logo_size, output_size, padded_logo_location, cover.get('logo-opacity'))) else: cover_image = Image.alpha_composite(cover_image, w_base) else: if cover.get('logo-opacity'): cover_image = Image.alpha_composite(cover_image, resize_and_fade_logo(get_black_logo(), logo_size, output_size, padded_logo_location, cover.get('logo-opacity'))) else: cover_image = Image.alpha_composite(cover_image, b_base) # Write text if cover.get('main-text'): size = 1 font = ImageFont.truetype('CircularStd-Bold.otf', size) max_area = get_text_area(output_size) max_height = get_text_height(output_size) main_text_line = cover.get('main-text') # Calculate maximum font size. Increase size until width of text exceeds defined max area, # or height of an example text with no dangling letters, e.g. "Genre Glitch", at that size # exceeds defined maximum. draw = ImageDraw.Draw(cover_image) while (draw.textsize(main_text_line, font)[0] < max_area and draw.textsize(text_height_example_string, font)[1] < max_height): size += 1 font = ImageFont.truetype('CircularStd-Bold.otf', size) # Put in a variable so sub-text can use to calculate area already covered main_text_size = draw.textsize(main_text_line, font) if cover.get('centre-text'): text_location = calculate_centred_font_location(output_size, font, main_text_line, draw) else: text_location = calculate_font_location(output_size, font, main_text_line, draw) draw.text(text_location, main_text_line, cover.get('font-colour', 'white'), font, align="center") if cover.get('sub-text'): size = 1 font = ImageFont.truetype('CircularStd-Bold.otf', size) max_area = get_text_area(output_size) max_height = get_sub_text_height(output_size) main_text_line = cover.get('sub-text') # Calculate maximum font size. Increase size until width of text exceeds defined max area, # or height of an example text with no dangling letters, e.g. "Genre Glitch", at that size # exceeds defined maximum. draw = ImageDraw.Draw(cover_image) while (draw.textsize(main_text_line, font)[0] < max_area and draw.textsize(text_height_example_string, font)[1] < max_height): size += 1 font = ImageFont.truetype('CircularStd-Bold.otf', size) if cover.get('sub-text-above'): main_start = text_location[1] sub_text_location = (int(output_size[0]/2 - draw.textsize(main_text_line, font)[0]/2), main_start - get_padding_height(output_size) - draw.textsize(text_height_example_string, font)[1]) else: main_end = text_location[1] + main_text_size[1] sub_text_location = (int(output_size[0]/2 - draw.textsize(main_text_line, font)[0]/2), get_padding_height(output_size) + main_end) draw.text(sub_text_location, main_text_line, cover.get('sub-font-colour', 'white'), font, align="center") except IOError: print("Unable to load image") sys.exit(1) if show: cover_image.show() else: if not os.path.exists(os.path.join(get_project_root(), 'images', 'covers')): os.makedirs(os.path.join(get_project_root(), 'images', 'covers')) # Ensure unique filenames by first trying to append config strings, then appending numbers if the file still exists already parts = [cover.get('main-text'), cover.get('sub-text'), cover.get('bg-image'), cover.get('colour-gradient')] parts = [i for i in parts if i is not None] i = 0 file_name = "" while i < len(parts): file_name += parts[i] file_path = os.path.join(get_project_root(), 'images', 'covers', sanitize_filename(file_name + ".jpg")) if os.path.exists(file_path) and os.path.getmtime(file_path) > start_time: i += 1 file_name += "_" else: break else: x = 0 while os.path.exists(file_path) and os.path.getmtime(file_path) > start_time: x += 1 file_path = os.path.join(get_project_root(), 'images', 'covers', sanitize_filename(file_name + str(x) + ".jpg")) cover_image.convert("RGB").save(file_path, quality=95) if test_image is not None: Image.blend(cover_image, test_image, 0.65).show()
def get_cover_image(cover): return Image.open(os.path.join(get_project_root(), 'images', cover['bg-image']))
def get_gradient(gradient_name): return Image.open(os.path.join(get_project_root(), 'images', 'gradient', gradient_name + '.jpg'))
def get_black_logo(): return Image.open(os.path.join(get_project_root(), 'images', 'logo', 'Spotify_Icon_RGB_Black.png'))
def get_white_logo(): return Image.open(os.path.join(get_project_root(), 'images', 'logo', 'Spotify_Icon_RGB_White.png'))
def get_test_image_3(): return Image.open(os.path.join(get_project_root(), 'images', 'test', 'test_3.jpg'))