def fill_image(final_image_size, pillow, crop_closeness=0): willow = PillowImage(pillow) width, height = final_image_size image_width, image_height = willow.get_size() focal_point = Rect(image_width / 2, image_height / 2, image_width / 2, image_height / 2) # Get crop aspect ratio crop_aspect_ratio = width / height # Get crop max crop_max_scale = min(image_width, image_height * crop_aspect_ratio) crop_max_width = crop_max_scale crop_max_height = crop_max_scale / crop_aspect_ratio # Initialise crop width and height to max crop_width = crop_max_width crop_height = crop_max_height # Use crop closeness to zoom in if focal_point is not None: # Get crop min crop_min_scale = max(focal_point.width, focal_point.height * crop_aspect_ratio) crop_min_width = crop_min_scale crop_min_height = crop_min_scale / crop_aspect_ratio # Sometimes, the focal point may be bigger than the image... if not crop_min_scale >= crop_max_scale: # Calculate max crop closeness to prevent upscaling max_crop_closeness = max( 1 - (width - crop_min_width) / (crop_max_width - crop_min_width), 1 - (height - crop_min_height) / (crop_max_height - crop_min_height) ) # Apply max crop closeness crop_closeness = min(crop_closeness, max_crop_closeness) if 1 >= crop_closeness >= 0: # Get crop width and height crop_width = crop_max_width + (crop_min_width - crop_max_width) * crop_closeness crop_height = crop_max_height + (crop_min_height - crop_max_height) * crop_closeness # Find focal point UV if focal_point is not None: fp_x, fp_y = focal_point.centroid else: # Fall back to positioning in the centre fp_x = image_width / 2 fp_y = image_height / 2 fp_u = fp_x / image_width fp_v = fp_y / image_height # Position crop box based on focal point UV crop_x = fp_x - (fp_u - 0.5) * crop_width crop_y = fp_y - (fp_v - 0.5) * crop_height # Convert crop box into rect rect = Rect.from_point(crop_x, crop_y, crop_width, crop_height) # Make sure the entire focal point is in the crop box if focal_point is not None: rect = rect.move_to_cover(focal_point) # Don't allow the crop box to go over the image boundary rect = rect.move_to_clamp(Rect(0, 0, image_width, image_height)) # Crop! willow = willow.crop(rect.round()) # Get scale for resizing # The scale should be the same for both the horizontal and # vertical axes aftercrop_width, aftercrop_height = willow.get_size() scale = width / aftercrop_width # Only resize if the image is too big if scale < 1.0: # Resize! willow = willow.resize((width, height)) return willow.get_pillow_image()