pythonpython-3.ximage-processingpython-imaging-library

Draw a rectangle and a text in it using PIL


I want to draw a rectangle and a text in it, here's a part of my code and it's a bit obfuscated:

from PIL import Image
from PIL import ImageFont
from PIL import ImageDraw
from PIL import ImageEnhance

  source_img = Image.open(file_name).convert("RGB")

  img1 = Image.new("RGBA", img.size, (0,0,0,0))
  draw1 = ImageDraw.Draw(watermark, "RGBA")
  draw1.rectangle(((0, 00), (100, 100)), fill="black")
  img_rectangle = Image.composite(img1, source_img, img1)

  draw2 = ImageDraw.Draw(img1, "RGBA")
  draw2.text((20, 70), "something123", font=ImageFont.truetype("font_path123"))

  Image.composite(img1, source_img, img1).save(out_file, "JPEG")

This draws them both, but they're separate: the text is under the rectangle. Whereas I want a text to be drawn inside the rectangle. How can I do that? Should I necessarily compose them or what?


Solution

  • You can do it without composite() (and using only RGB instead of RGBA)

    from PIL import Image, ImageFont, ImageDraw, ImageEnhance
    
    # (2024) no need RGBA if you don't use `composite()` (besides JPG can't write RGBA)
    source_img = Image.open(file_name).convert("RGB")  # .convert("RGBA")
    
    draw = ImageDraw.Draw(source_img)
    draw.rectangle(((0, 00), (100, 100)), fill="black")
    draw.text((20, 70), "something123", font=ImageFont.truetype("font_path123"))
    
    # source_img = source_img.convert("RGB")  # (2024) if you used "RGBA" at start and want to save as JPG
    source_img.save(out_file, "JPEG")
    

    You can create empty image with size of button and put text on it and later put this image on source_img. This way long text will be cut to size of button.

    from PIL import Image, ImageFont, ImageDraw, ImageEnhance
    
    source_img = Image.open("source.jpg").convert("RGBA")
    
    # create image with size (100,100) and black background
    button_img = Image.new('RGBA', (100,100), "black")
    
    # put text on image
    button_draw = ImageDraw.Draw(button_img)
    button_draw.text((20, 70), "very loooooooooooooooooong text", font=ImageFont.truetype("arial"))
    
    # put button on source image in position (0, 0)
    source_img.paste(button_img, (0, 0))
    
    # save in new file
    source_img = source_img.convert("RGB")  # (2024) if you want to save as JPG
    source_img.save("output.jpg", "JPEG")
    

    EDIT: I use ImageFont.getsize(text) to get text size and create button with correct size.

    from PIL import Image, ImageFont, ImageDraw, ImageEnhance
    
    source_img = Image.open("input.jpg").convert("RGBA")
    
    
    font = ImageFont.truetype("arial")
    
    text = "very loooooooooooooooooong text"
    
    # get text size
    text_size = font.getsize(text)
    
    # set button size + 10px margins
    button_size = (text_size[0]+20, text_size[1]+20)
    
    # create image with correct size and black background
    button_img = Image.new('RGBA', button_size, "black")
    
    # put text on button with 10px margins
    button_draw = ImageDraw.Draw(button_img)
    button_draw.text((10, 10), text, font=font)
    
    # put button on source image in position (0, 0)
    source_img.paste(button_img, (0, 0))
    
    # save in new file
    source_img = source_img.convert("RGB")  # (2024) if you want to save as JPG
    source_img.save("output.jpg", "JPEG")