Files
api/src/background_jobs/flight_title_photo.py
T

83 lines
3.4 KiB
Python

from PIL import Image, ImageDraw, ImageOps
from sqlalchemy import select
from database import models
from database.transaction import get_session
async def add_circular_avatar(base_image_path, avatar_image_path, output_image_path):
# Load the base image
base_image = Image.open(base_image_path)
base_width, base_height = base_image.size
# Calculate the new dimensions for cropping to a 1.9:1 aspect ratio
new_width = base_width
new_height = int(new_width / 1.9)
if new_height > base_height:
new_height = base_height
new_width = int(new_height * 1.9)
# Center crop the base image to the new dimensions
left = (base_width - new_width) // 2
top = (base_height - new_height) // 2
right = (base_width + new_width) // 2
bottom = (base_height + new_height) // 2
base_image = base_image.crop((left, top, right, bottom))
base_width, base_height = base_image.size
# Load the avatar image
avatar_image = Image.open(avatar_image_path)
avatar_size = int(base_height * 0.3) # Set the size of the avatar
avatar_image = avatar_image.resize((avatar_size, avatar_size), Image.LANCZOS)
# Create a mask to make the avatar circular
mask = Image.new('L', (avatar_size, avatar_size), 0)
draw = ImageDraw.Draw(mask)
draw.ellipse((0, 0, avatar_size, avatar_size), fill=255)
# Apply the mask to the avatar image
avatar_image = ImageOps.fit(avatar_image, mask.size, centering=(0.5, 0.5))
avatar_image.putalpha(mask)
# Create a border around the avatar
border_size = int(avatar_size * 0.03)
border_image = Image.new('RGBA', (avatar_size + 2 * border_size, avatar_size + 2 * border_size), (255, 255, 255, 0))
border_mask = Image.new('L', (avatar_size + 2 * border_size, avatar_size + 2 * border_size), 0)
border_draw = ImageDraw.Draw(border_mask)
border_draw.ellipse((0, 0, avatar_size + 2 * border_size, avatar_size + 2 * border_size), fill=255)
border_draw.ellipse((border_size, border_size, avatar_size + border_size, avatar_size + border_size), fill=0)
avatar_margin = int(avatar_size * 0.1)
border_image.putalpha(border_mask)
border_image.paste(avatar_image, (border_size, border_size), avatar_image)
# Calculate the position to paste the avatar (bottom right corner)
position = (base_width - avatar_size - 2 * border_size - avatar_margin, base_height - avatar_size - 2 * border_size - avatar_margin)
# Paste the avatar with border onto the base image
base_image.paste(border_image, position, border_image)
# Save the result
base_image.save(output_image_path)
async def generate_flight_title_photo(flight_id: int, photo_id: int):
async with get_session() as db:
photo = await models.Photo.get_one(db, id=photo_id)
pilot = (await db.scalars(
select(models.User)
.select_from(models.Flight)
.join(models.Flight.created_by)
.filter(models.Flight.id == flight_id)
)).one()
photo_filename, photo_ext = photo.filename, photo.filename_extension
pilot_id, avatar_filename = pilot.id, pilot.avatar_image_filename
await add_circular_avatar(
base_image_path=f'/app/uploads/photos/{flight_id}/{photo_filename}.{photo_ext}',
avatar_image_path=f'/app/uploads/profile/{pilot_id}/{avatar_filename}',
output_image_path=f'/app/uploads/photos/{flight_id}/title_photo.jpg',
)