advent22/api/advent22_api/routers/days.py

150 lines
3.3 KiB
Python

import random
from datetime import date
from io import BytesIO
import numpy as np
from fastapi import APIRouter, Depends
from fastapi.responses import StreamingResponse
from PIL import Image, ImageDraw, ImageFont
router = APIRouter(prefix="/days", tags=["days"])
loesungswort = "ABCDEFGHIJKLMNOPQRSTUVWX"
async def shuffle(string: str) -> str:
rnd = random.Random(loesungswort)
return "".join(rnd.sample(string, len(string)))
@router.on_event("startup")
async def narf() -> None:
print(loesungswort)
print(await shuffle(loesungswort))
@router.get("/letter/{index}")
async def get_letter(
index: int,
) -> str:
return (await shuffle(loesungswort))[index]
@router.get("/date")
def get_date() -> int:
return date.today().day
@router.get(
"/picture",
response_class=StreamingResponse,
)
async def get_picture():
img = Image.open("hand.png").convert("RGBA")
d1 = ImageDraw.Draw(img)
font = ImageFont.truetype("Lena.ttf", 50)
d1.text((260, 155), "W", font=font, fill=(0, 0, 255))
# d1.text(xy=(400, 210), text="Deine Hände auch?",
# font=Font, fill=(255, 0, 0))
img_buffer = BytesIO()
img.save(img_buffer, format="PNG", quality=85)
img_buffer.seek(0)
return StreamingResponse(
content=img_buffer,
media_type="image/png",
)
async def load_picture_standard() -> Image.Image:
img = Image.open("hand.png")
width, height = img.size
square = min(img.size)
img = img.crop(box=(
int((width - square)/2),
int((height - square)/2),
int((width + square)/2),
int((height + square)/2),
))
img = img.resize(
size=(400, 400),
resample=Image.ANTIALIAS,
)
return img.convert("RGB")
async def get_text_box(
img: Image.Image,
xy: tuple[float, float],
text: str | bytes,
font: "ImageFont._Font",
anchor: str | None = "mm",
**text_kwargs,
) -> tuple[int, int, int, int] | None:
mask = Image.new(mode="1", size=img.size, color=0)
ImageDraw.Draw(mask).text(
xy=xy,
text=text,
font=font,
anchor=anchor,
fill=1,
**text_kwargs,
)
return mask.getbbox()
async def get_average_color(
img: Image.Image,
box: tuple[int, int, int, int],
) -> tuple[int, int, int]:
pixel_data = img.crop(box).getdata()
mean_color: np.ndarray = np.mean(pixel_data, axis=0)
return tuple(mean_color.astype(int).tolist())
@router.get(
"/picture/{index}",
response_class=StreamingResponse,
)
async def get_picture_for_day(
letter: str = Depends(get_letter),
img: Image.Image = Depends(load_picture_standard),
) -> StreamingResponse:
font = ImageFont.truetype("Lena.ttf", 50)
xy = (200, 150)
text_box = await get_text_box(
img=img,
xy=xy,
text=letter,
font=font,
)
if text_box is not None:
text_color = await get_average_color(
img=img,
box=text_box,
)
ImageDraw.Draw(img).text(
xy=xy,
text=letter,
font=font,
anchor="mm",
fill=text_color,
)
img_buffer = BytesIO()
img.save(img_buffer, format="PNG", quality=85)
img_buffer.seek(0)
return StreamingResponse(
content=img_buffer,
media_type="image/png",
)