-
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Showing
9 changed files
with
140 additions
and
24 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
from flask import Blueprint, request | ||
from piggy.thumbnails import create_thumbnail | ||
from piggy.utils import serve_pil_image | ||
|
||
api_routes = Blueprint("api", __name__, url_prefix="/api") | ||
|
||
|
||
@api_routes.route("/generate_thumbnail/<string:text>") | ||
def generate_thumbnail(text: str): | ||
""" | ||
Generate a thumbnail from the given heading. | ||
:param heading: The heading to generate a thumbnail for | ||
:return: A thumbnail image | ||
""" | ||
# get query parameters from the request | ||
bg_color = request.args.get("bg_color", "") | ||
text_color = request.args.get("text_color", "") | ||
width = request.args.get("width", 500) | ||
height = request.args.get("height", 200) | ||
|
||
# c is a hash of the text to get a color combination | ||
gibberish = request.args.get("c", "") | ||
|
||
# Text, Background combinations | ||
color_palettes = [ | ||
("ffffff", "85144b"), | ||
("aaaaaa", "000000"), | ||
("001f3f", "39cccc"), | ||
("ff851b", "001f3f"), | ||
("2ecc40", "001f3f"), | ||
("39cccc", "001f3f"), | ||
("7fdbff", "85144b"), | ||
("ff851b", "001f3f"), | ||
] | ||
|
||
if gibberish and not bg_color and not text_color: | ||
# use a simple hashing function to get a color combination from the gibberish | ||
text_color, bg_color = color_palettes[hash(gibberish) % len(color_palettes)] | ||
|
||
if not bg_color: | ||
bg_color = "111111" | ||
if not text_color: | ||
text_color = "fefefe" | ||
|
||
# sanitize the query parameters, text is max 50ch | ||
_text = text[:50] | ||
if len(_text) < len(text): | ||
_text += "..." | ||
bg_color = bg_color.lstrip("#") | ||
text_color = text_color.lstrip("#") | ||
width = min(int(width), 1000) | ||
height = min(int(height), 1000) | ||
|
||
# create the thumbnail | ||
img = create_thumbnail(_text, bg_color, text_color, (width, height)).convert("RGB") | ||
return serve_pil_image(img) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Binary file not shown.
Binary file not shown.
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,30 +1,32 @@ | ||
{# Card Container #} | ||
<a | ||
href="{{ abspath }}/{{ item }}" | ||
class="card-container block p-3 rounded-xl border border-slate-500" | ||
href="{{ abspath }}/{{ item }}" | ||
class="card-container block p-3 rounded-xl border border-slate-500" | ||
> | ||
{# Card Title #} | ||
<div class="text-2xl font-extrabold text-center pb-2"> | ||
{{ data.meta.name }} | ||
</div> | ||
{# Card Title #} | ||
<div class="text-2xl font-extrabold text-center pb-2"> | ||
{{ data.meta.name }} | ||
</div> | ||
|
||
{# Card Thumbnail #} | ||
<div class="thumbnail-container"> | ||
<img | ||
class="w-full h-36 object-cover rounded-xl shadow-lg" | ||
src="{{ media_abspath }}/{{ item }}/media/header.{{ img_fmt }}" | ||
alt="Header image for {{ item }}" | ||
/> | ||
{# Card Thumbnail #} | ||
<div class="thumbnail-container"> | ||
<img | ||
class="w-full h-36 object-cover rounded-xl shadow-lg" | ||
{% if data.meta.thumbnail %} | ||
src="{{ abspath }}/{{ item }}/{{ data.meta.thumbnail }}" | ||
{% else %} | ||
src="{{ url_for('api.generate_thumbnail', text=data.level_name) }}?c={{ data.assignment_name }}" | ||
{% endif %} | ||
alt="Header image for {{ item }}" | ||
/> | ||
|
||
{# TEMP | ||
<div class="thumbnail-text-overlay"> | ||
{{ data.meta.description }} | ||
</div> | ||
#} | ||
</div> | ||
<div class="thumbnail-text-overlay"> | ||
Level {{ data.level }} - {{ data.level_name }} | ||
</div> | ||
</div> | ||
|
||
{# Card Description #} | ||
<div class="mt-4 description-container font-semibold"> | ||
{{ data.meta.description }} | ||
</div> | ||
</a> | ||
{# Card Description #} | ||
<div class="mt-4 description-container font-semibold"> | ||
{{ data.meta.description }} | ||
</div> | ||
</a> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
from pathlib import Path | ||
|
||
import PIL.Image | ||
import PIL.ImageDraw | ||
import PIL.ImageFont | ||
import textwrap | ||
|
||
|
||
# TODO: this is a mess. | ||
|
||
|
||
def create_thumbnail( | ||
title: str, bg_color: str = "111111", text_color: str = "fefefe", size: tuple[int, int] = (700, 300) | ||
) -> PIL.Image: | ||
"""Returns the image data for a thumbnail of the given image.""" | ||
im = PIL.Image.new("RGB", size, "#" + bg_color) | ||
box = (0, 0, size[0], size[1]) | ||
draw = PIL.ImageDraw.Draw(im) | ||
|
||
margin = 40 | ||
|
||
# Plays better with the text overlay | ||
y_offset = 10 | ||
|
||
text = textwrap.fill(title, width=30) | ||
font_size = 180 | ||
size = None | ||
|
||
# Get the font path relative to this file | ||
font_path = Path(__file__).parent / "resources/fonts/Lato-Bold.ttf" | ||
font = PIL.ImageFont.truetype(font_path.as_posix(), font_size) | ||
recursions = 0 | ||
while ( | ||
(size is None or size[2] > box[2] - margin or size[3] > box[3] - margin) and font_size > 0 and recursions < 50 | ||
): | ||
font = font.font_variant(size=font_size) | ||
size = draw.multiline_textbbox((0, 0), text, font=font, align="center") | ||
font_size -= 5 | ||
recursions += 1 | ||
|
||
box = (box[2] / 2, box[3] / 2 - y_offset) | ||
|
||
draw.multiline_text(box, text, font=font, fill="#" + text_color, align="center", anchor="mm") | ||
|
||
return im |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
from flask import send_file | ||
from io import BytesIO | ||
|
||
|
||
def serve_pil_image(pil_img): | ||
img_io = BytesIO() | ||
pil_img.save(img_io, "webp", quality=100) | ||
img_io.seek(0) | ||
return send_file(img_io, mimetype="image/webp") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters