Last Updated on July 14, 2022 by Jay
Do you know Python can help add text to an image? Although not a graphics editing software, Python is well capable of manipulating image files. In this tutorial, we’ll put a sample text “Python In Office ©” on multiple images. Instead of doing that manually, or using some expensive software, we can achieve the same result within minutes using Python!
Library
For this tutorial, we’ll use the PILLOW library (Python Imaging Library). We can use pip to install it from the command line:
pip install Pillow
The Pillow library allows us to open, modify, and save image files.
Note that we need to import PIL instead of Pillow.
import PIL # correct import
import Pillow # throws ModuleNotFoundError: No module named 'Pillow'
We’ll use 3 submodules from Pillow:
- Image: A class for the image file that allows for opening and saving image files.
- ImageDraw: A class for creating new images, we’ll use this to add text to an image.
- ImageFont: The text font.
Read An Image File Into Python
Let’s first read an image file into Python:
from PIL import (Image,
ImageFont,
ImageDraw)
img = Image.open('flower.jpg')
I’m using Jupyter Notebook, which has a built-in function display() to show images inside the notebook.
Fonts
We can choose different fonts to add to the image. I’m going to use a font that comes with the Windows OS. To find all available fonts on your computer, type “font” in your windows search bar, then Font settings.
In Font settings, we can see many different fonts. We can also download new fonts from the Internet and install them for later use.
The font I want to use is called “Algerian”, and we can find the font file location from the settings.
With this font file, we can now create a font object to draw on top of an image in Python. In the below line of code:
- The first argument is the URL to the font file.
- The second argument is the font size. I’m using 300 here because the sample image is quite big.
font = ImageFont.truetype(r'C:\Windows\Fonts\ALGER.TTF',300)
Python PILLOW – Add Text To An Image
Now we need to create an ImageDraw object to modify the image. The draw.text() below takes the following arguments:
- (10, 10) – the (x,y) coordinates of the starting position
- font – the ImageFont we just created
- fill – the RGB color value of the text (255 means white, 0 means black)
draw = ImageDraw.Draw(img)
draw.text((10,10),'Python In Office ©', font = font, fill = (255,255,255))
Note: the ImageDraw object actually modifies the Image object. To show the updated image, we can use display(img) again:
Putting Text On Bottom Right Corner
To put the text in the bottom right corner, we need to do a couple of things:
- Determine the size of the text, this should be set dynamically since each image will have different size.
- Also, dynamically determine the starting (x,y) coordinates for the text. The coordinates will vary given different image sizes.
We can get the image (i.e. canvas) size by calling the size attribute. In this example, our image is 3651 pixels wide and 2664 pixels tall.
We are going to set the text size such that the whole text line will take roughly 1/3 of the width of the image.
The default font size of an ImageFont object is size 10. To get the text dimensions (width and height) and also calculate the scaling factor:
default_font_size = 10
text = 'Python In Office ©'
text_width, text_height = ImageFont.truetype(r'C:\Windows\Fonts\ALGER.TTF').getsize(text)
## load image
img = Image.open('flower.jpg')
## get image dimensions
img_width, img_height = img.size
## calculate scaler such that the text takes about 1/3 of the image width
scaler = img_width/3/text_width
scaler
19.21578947368421
For this example, the scaler worked out to be roughly 19, which means our font size will be 10 * 19 = 190. The text width and height will also scale accordingly.
## Scale text font size, width and height
## used to find the starting x,y coordinates
scale_text_font = int(default_font_size * scaler)
scale_text_width = int(scaler * text_width)
scale_text_height = int(scaler * text_height)
## create font object with appropriate font size
font = ImageFont.truetype(r'C:\Windows\Fonts\ALGER.TTF', size = scale_text_font)
## re-draw new image and place text on it
draw = ImageDraw.Draw(img)
## starting x,y coords for the text
start_x = img_width - scale_text_width - 20
start_y = img_height - scale_text_height - 20
draw.text((start_x,start_y), text = text, font = font, fill = (255,255,255))
img.save('flower_w_text.jpg')
Adding Text To Multiple Images
To add text to multiple images, let’s place all images into the same folder. Then we can use os.listdir() to get all file names from the folder and process each one. The complete code is as follows:
import os
from PIL import (Image,
ImageFont,
ImageDraw)
## By: Jay @ Pythoninoffice
default_font_size = 10
text = 'Python In Office ©'
text_width, text_height = ImageFont.truetype(r'C:\Windows\Fonts\ALGER.TTF').getsize(text)
folder_path = r'C:\Users\jay\Desktop\PythonInOffice\python_add_text_to_multiple_images\images'
for f in os.listdir(folder_path):
img = Image.open(rf'{folder_path}\{f}')
img_width, img_height = img.size
scaler = img_width/2/text_width
scale_text_font = int(default_font_size * scaler)
scale_text_width = int(scaler * text_width)
scale_text_height = int(scaler * text_height)
font = ImageFont.truetype(r'C:\Windows\Fonts\ALGER.TTF', size=scale_text_font)
draw = ImageDraw.Draw(img)
start_x = img_width - scale_text_width - 20
start_y = img_height - scale_text_height - 20
draw.text((start_x,start_y), text = text, font = font, fill = (0,0,0))
file_name = f.split('.')[0] + '_w_text.jpg'
img.save(rf'{folder_path}\{file_name}')
## By: Jay @ Pythoninoffice
Below is an example of what the text looks like on images of different sizes.