mirror of
https://github.com/UiO-Gaming/mustafa.git
synced 2026-11-05 13:56:48 +01:00
improve font size calculation algorithm
This commit is contained in:
1 file changed
+53
-43
+53
-43
@@ -70,39 +70,7 @@ class Meme(commands.Cog):
|
||||
await interaction.followup.send(file=discord.File(output, "deepfry.jpg"))
|
||||
|
||||
@staticmethod
|
||||
def __format_text(text: str, textbox_width: int) -> tuple[str, ImageFont.FreeTypeFont]:
|
||||
"""
|
||||
Formats text to fit in a textbox of a given width.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
text (str): Text to be formatted.
|
||||
textbox_width (int): Width of the textbox.
|
||||
|
||||
Returns
|
||||
----------
|
||||
tuple[str, ImageFont.FreeTypeFont]: The formatted text and the font, with its size set, to be used.
|
||||
"""
|
||||
|
||||
if len(text) <= 1:
|
||||
font_size = 150
|
||||
else:
|
||||
font_size = textbox_width // (len(text) // 6)
|
||||
|
||||
if font_size < 20:
|
||||
font_size = 20
|
||||
elif font_size > 150:
|
||||
font_size = 150
|
||||
|
||||
font = ImageFont.truetype("./src/assets/fonts/RobotoMono-Medium.ttf", font_size)
|
||||
|
||||
line_length = int(textbox_width // font_size * 1.5)
|
||||
text = textwrap.fill(text, width=line_length)
|
||||
|
||||
return text, font
|
||||
|
||||
@staticmethod
|
||||
def __draw_text(image: Image.Image, text: str, font: ImageFont.FreeTypeFont, offset: tuple = (0, 0)):
|
||||
def __draw_text(image: Image.Image, text: str, offset: tuple = (0, 0)):
|
||||
"""
|
||||
Draws meme text on preferred meme template.
|
||||
|
||||
@@ -115,13 +83,59 @@ class Meme(commands.Cog):
|
||||
"""
|
||||
|
||||
box_size = (540, 540)
|
||||
|
||||
box = Image.new("RGB", box_size, (255, 255, 255))
|
||||
draw = ImageDraw.Draw(box)
|
||||
|
||||
text_box = draw.multiline_textbbox(
|
||||
(box_size[0], box_size[1]), text=text, font=font, align="center", anchor="mm"
|
||||
)
|
||||
font_path = "./src/assets/fonts/RobotoMono-Medium.ttf"
|
||||
|
||||
# Calculate initial font size
|
||||
# This is done by increasing the font size until the text is too wide
|
||||
max_width, max_height = box_size[0] * 0.9, box_size[1] * 0.9 # 90% of the box size
|
||||
|
||||
font_size = 20 # Initiale size. I consider this the smallest readable size
|
||||
font_width = 0 # Initiale width. This is just to make sure the while loop runs at least once
|
||||
while font_width < max_width:
|
||||
font = ImageFont.truetype(font_path, font_size)
|
||||
|
||||
font_box = font.getbbox(text)
|
||||
font_width = font_box[2] - font_box[0]
|
||||
|
||||
font_size += 2
|
||||
|
||||
# Wrap the text based on our current font size
|
||||
text = textwrap.fill(text, width=font_size)
|
||||
|
||||
# We then have to calculate the font size again
|
||||
#
|
||||
# The problem is, font.getbbox() doesn't work with multiline text so it returns the size without the linebreaks
|
||||
# We can get around this by calculating the size of the longest line in the text
|
||||
# and then increasing the font size until that line is too wide
|
||||
#
|
||||
# We also have to make sure it doesn't get too tall
|
||||
longest_line = max(text.split("\n"), key=len)
|
||||
longest_line_font_box = font.getbbox(longest_line)
|
||||
font_width = longest_line_font_box[2] - longest_line_font_box[0]
|
||||
|
||||
# Estimate font height
|
||||
# This is done by multiplying the height of the original non-wrapped text with the number of lines
|
||||
# and then adding 20 to account for the line spacing.
|
||||
# This of course is dependant on font size itself, but it's good enough for now
|
||||
font_height = (font_box[3] - font_box[1] + 20) * text.count("\n")
|
||||
max_height = box_size[1] * 0.9
|
||||
|
||||
while font_width < max_width and font_height < max_height:
|
||||
font = ImageFont.truetype(font_path, font_size)
|
||||
|
||||
longest_line_font_box = font.getbbox(longest_line)
|
||||
font_width = longest_line_font_box[2] - longest_line_font_box[0]
|
||||
|
||||
font_box = font.getbbox(text)
|
||||
font_height = (font_box[3] - font_box[1] + 20) * text.count("\n")
|
||||
|
||||
font_size += 2
|
||||
|
||||
# Draw textbox and text
|
||||
text_box = draw.multiline_textbbox(box_size, text=text, font=font, align="center", anchor="mm")
|
||||
text_box = box.size[0] // 2, box.size[1] // 2
|
||||
draw.multiline_text(text_box, text, font=font, fill=(0, 0, 0, 255), align="center", anchor="mm")
|
||||
|
||||
@@ -146,13 +160,9 @@ class Meme(commands.Cog):
|
||||
# Fetch meme template
|
||||
template = Image.open("./src/assets/misc/sivert_goodbad.jpg")
|
||||
|
||||
# Calculate font sizes
|
||||
top_text, top_font = Meme.__format_text(dårlig_tekst, 540)
|
||||
bottom_text, bottom_font = Meme.__format_text(bra_tekst, 540)
|
||||
|
||||
# Draw text
|
||||
Meme.__draw_text(template, top_text, top_font, offset=(540, 0))
|
||||
Meme.__draw_text(template, bottom_text, bottom_font, offset=(540, 540))
|
||||
Meme.__draw_text(template, dårlig_tekst, offset=(540, 0))
|
||||
Meme.__draw_text(template, bra_tekst, offset=(540, 540))
|
||||
|
||||
# Save image to buffer
|
||||
output = BytesIO()
|
||||
|
||||
Reference in new issue
Block a user