2

I would like to create a python script that dynamically adds text to fit within the center of the image, regardless of the amount of text. I have a working script that does this which I've pasted below. Now I would like to surround the text with a gray box.

What I've tried to do was create a gray image then add the text to it and then add that to the original image. But for whatever reason I can't get that image to resize to the text.

Here is the working script:

    from PIL import Image, ImageDraw, ImageFont
    import textwrap
    from string import ascii_letters

    img = Image.open(fp='background.jpg', mode='r')
    font = ImageFont.truetype(font='arial', size=50)
    draw = ImageDraw.Draw(im=img)
    text = """Simplicity--the art of maximizing the amount of work not done--is essential."""
    avg_char_width = sum(font.getsize(char)[0] for char in ascii_letters) / len(ascii_letters)
    max_char_count = int(img.size[0] * .83 / avg_char_width)
    text = textwrap.fill(text=text, width=max_char_count)
    draw.text(xy=(img.size[0]/2, img.size[1] / 2), text=text, font=font, fill='#000000', anchor='mm')
    img.show()

This is how I'd like the image to appear: enter image description here

1 Answer 1

2

It's not 100% elegant solution, but at least it works.

import textwrap
from string import ascii_letters
from PIL import Image, ImageDraw, ImageFont


def add_text_to_image(image, text, color):
    img = Image.open(fp=image, mode='r')
    img_temp = Image.new('RGB', (img.width, img.height), color='white')
    font = ImageFont.truetype(font='arial', size=50)
    draw = ImageDraw.Draw(im=img_temp)
    avg_char_width = sum(font.getsize(char)[0] for char in ascii_letters) / len(ascii_letters)
    max_char_count = int(img.size[0] * .83 / avg_char_width)
    text = textwrap.fill(text=text, width=max_char_count)
    draw.text(xy=(img_temp.size[0] / 2, img.size[1] / 2), text=text, font=font, fill='black', anchor='mm')
    pixels = img_temp.load()
    y_min = 0
    y_max = 0
    for y in range(img.height):
        for x in range(img.width):
            if pixels[x, y] == color and not y_min:
                y_min = y
            elif pixels[x, y] == color:
                y_max = y
    draw = ImageDraw.Draw(im=img)
    draw.rectangle(((0, y_min), (img.width, y_max)), fill='gray')
    draw.text(xy=(img.size[0] / 2, img.size[1] / 2), text=text, font=font, fill=color, anchor='mm')
    img.save('image.png')

Testing:

add_text_to_image(image='yellow.jpg', text='Simplicity--the art of maximizing the amount of work not done--is essential.', color=(0, 0, 0))

enter image description here

add_text_to_image(image='black.jpg', text='Старый конь борозды не испортит.', color=(0, 0, 0))

enter image description here

Sign up to request clarification or add additional context in comments.

3 Comments

Thank you for helping me out. I tried the code presented, and for whatever reason it doesn't seem to function. I also noticed that the y_max value is always 635, regardless of how long the text. Which doesn't make sense to me, y_max should be dynamically changing size according to the text size it seems. This is the image i'm getting: imgur.com/a/EBq0kvX
Okay so I did some more testing. It works, but only on some images. If there is black on the image in certain areas. It will just cover that area as well, with the grey rectangle.
@holograms I've fixed it. See my updated code.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.