Issue
For context, I am trying to make a 'sigma-male' meme generator. The idea is I can feed in a load of pre-defined 'sigma-male' jokes/quotes and overaly it on an image of a 'sigma-male'. The format of these pictures should be that in the center of the image there will be a line saying 'Sigma-Male Rule #X' and underneath there would be some bad life advice e.g. 'Don't be part of the problem, be the whole problem'. Here is the picture I am starting with (note that for my purposes all images are the same size, 1080x1080. So issues of variable image size shouldn't be a problem):
But when I try to add the 'life-advice' I end up with this: Character with text
As you can see, the text runs straight off of the image. One fix I have tried is by breaking it up into several lines: Character with text after breaking line up
Theoretically, this could be useful but the problem is I would manually have to adjust each different quote, which would stop this from being an automatic procedure.
Ideally, what I would like is an image like this: Desired output
Something else I would need to account for is if I have a short quote that's only one line, how can I also guarentee that this will be centered appropriatley relative to the 'Sigma Male Rule#X
Here is my code:
import numpy as np
import cv2
from PIL import Image, ImageDraw, ImageFont
import textwrap
my_image = Image.open("Bateman1Raw resized.jpg")
title_font = ImageFont.truetype('Bebas-Regular.ttf', 100)
title_text = "Sigma Male Rule #1"
text_test='Don\'t be part of the\n problem, be the whole problem'
image_editable = ImageDraw.Draw(my_image)
image_editable.text((200,400), title_text, (255, 255, 255), font=title_font,stroke_width=2,stroke_fill='black')
image_editable.text((0,500), words,(255, 255, 255),align='center',font=title_font,stroke_width=2,stroke_fill='black')
my_image.save("result.jpg")
Solution
ImageFont has getlength(text)
and getbbox(text)
which gives text length for selected font and size. You can use to split text to lines.
I first split all text to words and I add next word to text and check getlength(text)
. If it is shorter then I check with next word. If it is longer then I add this line to results and start with empty text to create new line.
width, height = my_image.size
text_test = "Don't be part of the problem, be the whole problem"
all_words = text_test.split(' ')
all_lines = []
line = []
while all_words:
word = all_words[0]
new_text = ' '.join(line + [word])
#print('>', word, new_text)
if title_font.getlength(new_text) > width:
# if longer then keep shorter line and start with new line
all_lines.append(' '.join(line))
line = []
else:
# if shorter then add word to line, and remove word from list
line += [word]
all_words = all_words[1:]
# add last line to results
if line:
all_lines.append(' '.join(line))
print(all_lines)
And next I can use for
-loop to draw lines:
x = 0
y = 500
for text in all_lines:
#x = (width - title_font.getlength(text))//2
image_editable.text((x, y), text, (255, 255, 255), align='center', font=title_font, stroke_width=2, stroke_fill='black')
y += 100
Full working code
from PIL import Image, ImageDraw, ImageFont
my_image = Image.open("lenna.jpg")
my_image = my_image.resize((1080,1080))
width, height = my_image.size
title_font = ImageFont.truetype('Arial.ttf', 100)
text_test = "Don't be part of the problem, be the whole problem"
all_words = text_test.split(' ')
all_lines = []
line = []
while all_words:
word = all_words[0]
new_text = ' '.join(line + [word])
print('>', word, new_text)
if title_font.getlength(new_text) > width:
all_lines.append(' '.join(line))
line = []
else:
line += [word]
all_words = all_words[1:]
if line:
all_lines.append(' '.join(line))
print(all_lines)
image_editable = ImageDraw.Draw(my_image)
title_text = "Sigma Male Rule #1"
image_editable.text((200, 400), title_text, (255, 255, 255), font=title_font, stroke_width=2, stroke_fill='black')
y = 500
for text in all_lines:
image_editable.text((0, y), text, (255, 255, 255), align='center', font=title_font, stroke_width=2, stroke_fill='black')
y += 100
my_image.save("result.jpg")
my_image.show()
Image Lenna from Wikipedia
BTW:
You can use getlength()
and getbbox()
also to test text with different font size to get text which fit in one line.
Answered By - furas
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.