diff --git a/api/advent22_api/routers/days.py b/api/advent22_api/routers/days.py index af5cd36..8d020a8 100644 --- a/api/advent22_api/routers/days.py +++ b/api/advent22_api/routers/days.py @@ -1,3 +1,4 @@ +import colorsys import random from datetime import date from io import BytesIO @@ -57,10 +58,19 @@ async def get_picture(): async def load_picture_standard() -> Image.Image: - img = Image.open("hand.png") - width, height = img.size - square = min(img.size) + """ + Bild laden und einen quadratischen Ausschnitt + aus der Mitte nehmen + """ + # Bild laden + img = Image.open("hand.png") + + # Größen bestimmen + width, height = img.size + square = min(width, height) + + # Bild zuschneiden und skalieren img = img.crop(box=( int((width - square)/2), int((height - square)/2), @@ -73,6 +83,7 @@ async def load_picture_standard() -> Image.Image: resample=Image.ANTIALIAS, ) + # Farbmodell festlegen return img.convert("RGB") @@ -84,8 +95,16 @@ async def get_text_box( anchor: str | None = "mm", **text_kwargs, ) -> tuple[int, int, int, int] | None: + """ + Koordinaten (links, oben, rechts, unten) des betroffenen + Rechtecks bestimmen, wenn das Bild `img` mit einem Text + versehen wird + """ + + # Neues 1-Bit Bild, gleiche Größe mask = Image.new(mode="1", size=img.size, color=0) + # Text auf Maske auftragen ImageDraw.Draw(mask).text( xy=xy, text=text, @@ -95,6 +114,7 @@ async def get_text_box( **text_kwargs, ) + # betroffenen Pixelbereich bestimmen return mask.getbbox() @@ -102,6 +122,11 @@ async def get_average_color( img: Image.Image, box: tuple[int, int, int, int], ) -> tuple[int, int, int]: + """ + Durchschnittsfarbe eines rechteckigen Ausschnitts in + einem Bild `img` berechnen + """ + pixel_data = img.crop(box).getdata() mean_color: np.ndarray = np.mean(pixel_data, axis=0) @@ -116,9 +141,17 @@ 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) + """ + Bild für einen Tag erstellen + """ + # Font laden + font = ImageFont.truetype("Lena.ttf", 50) + + # Position des Buchstaben bestimmen + xy = (100, 150) + + # betroffenen Bildbereich bestimmen text_box = await get_text_box( img=img, xy=xy, @@ -127,11 +160,25 @@ async def get_picture_for_day( ) if text_box is not None: + # Durchschnittsfarbe bestimmen text_color = await get_average_color( img=img, box=text_box, ) + # etwas heller/dunkler machen + tc_h, tc_s, tc_v = colorsys.rgb_to_hsv(*text_color) + + if tc_v < 127: + tc_v += 3 + + else: + tc_v -= 3 + + text_color = colorsys.hsv_to_rgb(tc_h, tc_s, tc_v) + text_color = tuple(int(val) for val in text_color) + + # Buchstaben verstecken ImageDraw.Draw(img).text( xy=xy, text=letter, @@ -140,6 +187,7 @@ async def get_picture_for_day( fill=text_color, ) + # Bilddaten in Puffer laden img_buffer = BytesIO() img.save(img_buffer, format="PNG", quality=85) img_buffer.seek(0)