import math import json import yaml from PIL import Image, ImageDraw, ImageFilter from pathlib import Path def circular_mask(img): center_x = int(img.width / 2) center_y = int(img.height / 2) mask = Image.new('L', img.size, 0) draw = ImageDraw.Draw(mask) draw.ellipse((2, 2 ,img.width-3,img.height-3),fill=255) img.putalpha(mask.filter(ImageFilter.GaussianBlur(radius=1))) return img def arrange_images_in_circle(images, spacing=5, min_radius=0): d = images[0].size[0] dis = d + spacing theta = 2*math.pi / len(images) radius = max(dis/2/math.sin(theta/2), min_radius) imgWidth, imgHeight = (int(d+radius*2), int(d+radius*2)) masterImage = Image.new("RGBA", (imgWidth, imgHeight), (255,255,255,0)) #we want the circle to be as large as possible. #but the circle shouldn't extend all the way to the edge of the image. #If we do that, then when we paste images onto the circle, those images will partially fall over the edge. #so we reduce the diameter of the circle by the width/height of the widest/tallest image. circleCenterX = imgWidth / 2 circleCenterY = imgHeight / 2 for i, curImg in enumerate(images): angle = i * theta dx = int(radius * math.cos(angle)) dy = int(radius * math.sin(angle)) #dx and dy give the coordinates of where the center of our images would go. #so we must subtract half the height/width of the image to find where their top-left corners should be. pos = ( int(circleCenterX + dx - curImg.size[0]/2), int(circleCenterY + dy - curImg.size[1]/2) ) curMask = curImg.split()[-1] masterImage.paste(curImg, pos, curMask) return masterImage def create_circle(image_paths): # Resize all images to 64x64 pixels shrunk_images = [Image.open(path).resize((64, 64)) for path in image_paths] # Cut out a circle from each image circular_images = [circular_mask(img) for img in shrunk_images] circular_images[-1].save('circle.png') if len(circular_images) == 1: circular_images[0].save(output_path) return if len(circular_images) < 7: output_img = arrange_images_in_circle(circular_images) ow, oh = output_img.size else: inner_img = arrange_images_in_circle(circular_images[:4]) iw, ih = inner_img.size mask = inner_img.split()[-1] dr = circular_images[0].size[0]//2 + iw//2 output_img = arrange_images_in_circle(circular_images[4:],min_radius=dr) ow, oh = output_img.size output_img.paste(inner_img,((ow-iw)//2,(oh-ih)//2),mask) draw = ImageDraw.Draw(output_img) dr = 3 draw.ellipse((ow//2-dr, oh//2-dr, ow//2+dr, oh//2+dr),fill=(255,0,0),outline=False) return output_img def generateWeek(week, persons, locations, output_path=Path('.')): loc = {} for person in persons: print(person) if week in person['weeks'].keys(): cur_name = person['name'] cur_image = person['image'] for task in person['weeks'][week]: cur_loc = task['location'] cur_tasks = task['tasks'] if cur_loc not in loc.keys(): loc[cur_loc] = {} if cur_name not in loc[cur_loc].keys(): loc[cur_loc][cur_name] = { 'image': cur_image, 'tasks': [] } loc[cur_loc][cur_name]['tasks'] += cur_tasks week_json = [] w,y = week.split('/') json_file = "cw_%s_%s.json" % (w,y) for cur_loc, cur_persons in loc.items(): print(cur_loc) print(cur_persons) png_file = "%s_%s_%s.png" % (cur_loc.lower(),w,y) [print(x) for x in cur_persons] image_paths = [("persons/%s" % x['image']) for n,x in cur_persons.items()] img = create_circle(image_paths) img.save(output_path / Path(png_file)) popup = "