Skip to content

How to Add Text to Images in Python (via PIL Library)

Adding text to images using Python (PIL)

Introduction

In this Python tutorial we will show how to add text to images in Python using the PIL image manipulation library.

Our tutorial will gradually get more sophisticated and we will supplement it with creative examples towards the end for inspiration and as demonstration of more advanced Python applications.

We are going to be using Image, the ImageDraw and the ImageFont module from the PIL library mainly. We will also refer to ImageColor to see some available built-in color options. So, let’s start with importing those Python libraries first.

from PIL import Image, ImageDraw, ImageFont, ImageColor

Adding Text on Images with Python in 4 Steps

We can break up adding text to images to 4 steps.

Step 1: Creating a New Image

You can create a new image using PIL’s .new() method as below. It’s important to pay attention to color modes here as they can significantly impact the image manipulations that can be done on them as well as image saving options.

Here is a new image example with .new() method. First parameter is the color mode of the image while the second parameter in a tuple is the dimensions (how to get dimensions of an image) of the image.

We are going to also need an image object to write text on. We have a couple options for obtaining an image object in pillow image manipulation library.

Using the PIL library, we can “create a new image” or we can “open an existing image” as an image object in Python. Let’s start with creating a simple image object for the sake of simplicity.

Here is a new image example using PIL’s or pillow’s Image module. So, mode and size arguments are mandatory while we can also pass an optional color argument as below to energize this Python tutorial a bit.


img = Image.new(mode="RGBA", size=(400,300), color='darkorange')
img.show()
400x600 pixel RGBA image in darkorange color opened with PIL's Image module.

You can see a full list of available color names and their hex codes in the Python color tutorial below as well as discover various colormaps and how to derive discrete colors from them.

Additionally, we have an in-depth Python tutorial about color modes and how to use them with Python images using the PIL (pillow) digital image editing library.

Step 2: Creating a Draw Object

Creating a draw object is as simple as it gets. We will use ImageDraw module we’ve already imported and Draw class from this module.

The most important nuance at this point is the fact that we are using Draw class on the image we have already created (or opened). This Draw class item will act as a handle to write our text in the following steps.

Here is the Python code to create a draw object with PIL.

(And we have an extensive, well-researched tutorial about drawing geometric shapes in images with Python.)

draw = ImageDraw.Draw(img)

Step 3: Preparing Text Elements

Next we can assign our text to a variable.

text = "Hello World!"

Alternatively, you can pass a string directly to the draw function below without using an additional variable.

Step 4: Adding Text to the Image

Finally, using the draw object we’ve created earlier, we can add our text element to the image. Here, we need to pass minimum two arguments. These are x, y coordinates of the text and the text itself.

draw.text((140, 100), text)
img.show()
Simple text placed on darkorange image using PIL's ImageDraw module.

So, at the most basic level Python code for adding text to images looks like this:

img = Image.new(mode="RGBA", size=(400,300), color='darkorange')
draw = ImageDraw.Draw(img)

draw.text((140, 100), "Hello World!")
img.show()

Built-in Color Names in PIL (Pillow)

Darkorange is a lovely built-in color name in pillow’s color repertoire. Moreover you can choose from a plethora of cool built-in colors that are available in PIL.ImageColor class.

Pillow uses a superset of HTML 4.0 color names used in CSS 1. To get a full list of these color names you can refer to the colormap attribute inside ImageColor module. Here is the Python code for that:

colors=ImageColor.colormap
for i in colors.keys():
    print(i)

* keys() is a useful method for dictionaries in Python that provides only the keys in a dictionary. Since colormap attribute of ImageColor class is a dictionary of key-value pairs where keys are built-in color names and values are their hex codes. You can visit our dictionary exercises and dictionary lessons if you need to polish your Python dictionary knowledge.

aliceblue
antiquewhite
aqua
aquamarine
azure
beige
bisque
black
blanchedalmond
blue
blueviolet
brown
burlywood
cadetblue
chartreuse
chocolate
coral
cornflowerblue
cornsilk
crimson
cyan
darkblue
darkcyan
darkgoldenrod
darkgray
darkgrey
darkgreen
darkkhaki
darkmagenta
darkolivegreen
darkorange
darkorchid
darkred
darksalmon
darkseagreen
darkslateblue
darkslategray
darkslategrey
darkturquoise
darkviolet
deeppink
deepskyblue
dimgray
dimgrey
dodgerblue
firebrick
floralwhite
forestgreen
fuchsia
gainsboro
ghostwhite
gold
goldenrod
gray
grey
green
greenyellow
honeydew
hotpink
indianred
indigo
ivory
khaki
lavender
lavenderblush
lawngreen
lemonchiffon
lightblue
lightcoral
lightcyan
lightgoldenrodyellow
lightgreen
lightgray
lightgrey
lightpink
lightsalmon
lightseagreen
lightskyblue
lightslategray
lightslategrey
lightsteelblue
lightyellow
lime
limegreen
linen
magenta
maroon
mediumaquamarine
mediumblue
mediumorchid
mediumpurple
mediumseagreen
mediumslateblue
mediumspringgreen
mediumturquoise
mediumvioletred
midnightblue
mintcream
mistyrose
moccasin
navajowhite
navy
oldlace
olive
olivedrab
orange
orangered
orchid
palegoldenrod
palegreen
paleturquoise
palevioletred
papayawhip
peachpuff
peru
pink
plum
powderblue
purple
rebeccapurple
red
rosybrown
royalblue
saddlebrown
salmon
sandybrown
seagreen
seashell
sienna
silver
skyblue
slateblue
slategray
slategrey
snow
springgreen
steelblue
tan
teal
thistle
tomato
turquoise
violet
wheat
white
whitesmoke
yellow
yellowgreen

Adjusting Text Color

Adjusting the color of the text being added to the image is also very simple. Just use fill argument and pass a built-in color name or a hex color code to this optional argument when using the draw function.

draw.text((140, 100), text, fill='black')
img.show()
Honeydew colored new image with black text.
Using draw.text() method from ImageDraw module.

Example 1: Font Size and Type

So far we covered a minimalist Python implementation to add text on images which can be achieved with a few lines of Python code. Our code up to this point uses whatever default font and font size can be recalled by the pillow library since we didn’t assign any specific font settings.

However, there can be many merits to defining a specific font type and a font size while using the draw function to add text to an image or a manipulate batch of images.

text="Hello World!"
font = ImageFont.truetype('Inconsolata-Light.ttf', 162)
draw.text((1240, 1600), text, font=font, fill='white')
img.show()
Text placed on image with specific font type and font size using PIL & Python

With proper image and font style the result looks a lot more appealing already.

Managing Fonts for Python PIL - (Linux)

A quick font file explanation might be useful here. We are using Inconsolata-Light.ttf that’s already installed in our Linux system.

If you are using Linux, you can check out the available fonts installed in your system by running fc-list command in your terminal.

You can simply install new font files by placing .ttf or .otf font files in your system’s /usr/share/fonts directory. Don’t forget to run fc-cache command to refresh your font registry and then you can list available font by running fc-list again.

There are incredibly cool font options for free at Google Fonts. You can also search for specific font styles such as Serif, Sans Serif, Display, Handwriting or Monospace. You can download the font’s zip file and then extract it in your operating system.

Managing Fonts for Python PIL - (Mac OS & Windows)

Users of Mac OS operating system can use the terminal to manage fonts although the Font Book software makes it a breeze to install new fonts to the system and all the user has to do is click install font after opening a new font file.

Similarly, Windows users can open the Font tool under Settings > Control Panel where they can see, list, manage, install and uninstall new font files.

Google Fonts offers a rich repository of open source and free fonts ready to be downloaded.
You can filter font categories: Serif, Sans Serif, Display, Handwriting, Monospace

You are free to install new fonts however, you can also just extract your fonts to a specific local folder and then specify that font’s full directory in the PIL code as well. Both ways should work fine.

Here is a quick explanation of font families:

  • Serif: Serifs are the little pieces and tails attached to characters in a font. Serif font families appear authoritative and give a classic look to your text. They can be suitable for literature, legal and professional content.
  • Sans Serif: Sans means “without” in French and Sans Serif are modern font families that give text a sleek, minimalist and modern look. Sans Serif fonts can be useful for tech, computer science, sports, fashion, gaming and any other content where author wishes to have a modern look.
  • Handwriting: Self-explanatory handwriting fonts can be used for decorative text elements.
  • Display: Display fonts are suitable for large size applications such as posters and big displays, big slogans, big titles etc.
  • Monospace: Every character has the same width. Useful for environments without graphic servers such as computer terminals.

This is a quick rundown of font families and of course you can mix and match different font families and get as creative as you wish with fonts.

Here is a Python – PIL code that utilizes three different fonts in harmony: Cantarell VF, Inconsolata Light and Sacramento Regular.

file_dir='/home/usa/Downloads/Wallpaperz/'
file_name='billy-williams-8wz1Q4Q_XAg-unsplash.jpg'

img = Image.open(file_dir+file_name)
draw = ImageDraw.Draw(img) 

text1 = "100"
text2 = 'Python'
text3 = 'Tips & Tricks'

font1 = ImageFont.truetype('Cantarell-VF.otf', 280)
font2 = ImageFont.truetype('Inconsolata-Light.ttf', 280)
font3 = ImageFont.truetype('Sacramento-Regular.ttf', 280)

draw.text((140, 100), text1, font=font1, fill='black')
draw.text((540, 120), text2, font=font2, fill='gray')
draw.text((140, 520), text3, font=font3, fill='yellow')

img.show()

And here is the result:

Cantarell, Inconsolata and Sacramento Fonts added to beautiful landsacape photo.
Image credit: Billy Williams @Unsplash

Example 2: Text Position

Sometimes, especially when working on scale, you might want to use dynamic positioning instead of providing manual text coordinates.

We can easily do this by getting the image size first.
Image size can be acquired using .size method in PIL with Python. For example img.size would return two values; the width and the height of the image.
 

Here is an example where Python code takes the coordinates of text to be placed on the image dynamically based on the image’s 2-dimensional size values.

x, y = img.size
print(x,y)

3502, 1970

text = "Sustainability\nReport 2023"
font = ImageFont.truetype('WorkSans-Regular.ttf', 282)

textwidth, textheight = draw.textsize(text, font=font)
print(textwidth, textheight)

1866, 530

So, we know both the image dimensions and the text dimensions. If we use the formula below:
 
(x/2 – textwidth/2) can be the x coordinate of the text it will be aligned to center horizontally. We can do the same to set the vertical aligment to center as well.
 
That is the gist of dynamic positioning (or relative positioning) of text on images.
 
Here is an example.
from PIL import Image, ImageDraw

img = Image.open(mountain.png)
font = ImageFont.truetype('WorkSans-Bold.ttf', 282)
text = "#REDEFINE"
draw = ImageDraw.Draw(img)

textwidth, textheight = draw.textsize(text, font)
width, height = img.size 
x=width/2-textwidth/2
y=height/2-textheight/2

draw.text((x, y), text, font=font, fill='DeepPink')
img.show()
Text on image dynamically centered with Python.

Example 3: Rotating Text

We can also create rotated text at any angle. The recipe to do that is to create a transparent image first. Write the text on that image and rotate that image.

Then we can paste that rotated image (which will also rotate the text on it). Then we can paste this image on another image using the paste method.

Below, you can find a step by step implementation of rotated text with Python and the full Python code example.

from PIL import Image, ImageDraw, ImageFont
img = Image.open(mountain.png)
A text layer is created using the new image method from PIL below. The creation of this image has a few little nuances. For example, the color mode is RGBA so it can be transparent and its filled with RGBA: 255, 255, 255, 0. Last number 0 is used to create a 100% transparent image. RGB values don’t matter much since the transparency is 100%.
 
Another part is the size of the image. We want it to be the same size as our base image but with the dimensions swapped so when we rotate the image with the text it will have the same size as the base image. This is achieved by assigning the image size to x and y and creating the new image with y and x instead.
x, y = img.size
txt_layer = Image.new("RGBA", (y, x), (255, 255, 255, 0))

Then we can create a draw object on this text layer we created. We can write our text which will end up with vertical orientation. Another point here is that the y values will define the margin between the text and the right side of the image (in this case it is 50 pixel, see below.)

draw = ImageDraw.Draw(txt_layer)
draw.text((100, 50), "ESG Assets Under Management", font=font, fill=('orangered'))
draw.text((1220, 50), "tel: 212 563 90x8", font=font, fill=('white'))

We can now rotate the image with the text. .transpose() method can be useful for that. Additionally, 270 degrees is required for the result we are looking to achieve which can be implemented with Image.ROTATE_270 object which goes inside the .transpose() method. We will then have a rotated text.

Final step is to merge the layer with rotated text and the actual image. We can use the alpha_composite method since both layers (or images in this case) have the same dimensions.

You can visit our pasting, merging, combining images with Python tutorial to see a lot more technical details about the alpha_composite method and its alternatives.

flip_img = txt_layer.transpose(Image.ROTATE_270)
new_img = Image.alpha_composite(img, flip_img)
new_img.show()

Python example demonstrating text title on mountain image with vertical text pasted across the right side of the image

Here is the full Python code.

* This code is missing the part about the title text which can be implemented with the previous sections of this tutorial.

from PIL import Image, ImageDraw, ImageFont

img = Image.open(mountain.png)

x, y = img.size
txt_layer = Image.new("RGBA", (y, x), (255, 255, 255, 0))

font = ImageFont.truetype('WorkSans-Regular.ttf', 62)
draw = ImageDraw.Draw(txt_layer)
draw.text((100, 50), "ESG Assets Under Management", font=font, fill=('orangered'))
draw.text((1220, 50), "tel: 212 563 90x8", font=font, fill=('white'))

flip_img = txt_layer.transpose(Image.ROTATE_270)
new_img = Image.alpha_composite(img, flip_img)
new_img.show()

Example 4: Text Transparency

We can achieve transparent text by a similar technique to text rotation.

If you draw a text with transparent color and directly apply it to the image it will lose transparency.

Instead we will create a fully transparent layer. Draw our partially transparent text on this layer. And then paste this transparent layer with semi-transparent text on top of the base image. This way our transparency will be preserved during and after the process.
 
Below you can find a Python example that establishes the same thing.
from PIL import Image, ImageDraw, ImageFont

img = Image.open('mountain.png').convert("RGBA")

text = "Sustainability\nReport 2023"
font = ImageFont.truetype('WorkSans-Regular.ttf', 282)

x, y = img.size
txt_layer = Image.new("RGBA", (x,y), (255, 255, 255, 0))

draw = ImageDraw.Draw(txt_layer)
draw.text((300, 900), text, font=font, fill=(2,157,229, 130))

new_img = Image.alpha_composite(img, txt_layer)
new_img.show()

A few notes about the Python code above:
 
* Our text includes an \n character. This character establishes the new line function.
** We are using WorkSans font sourced from Google Fonts.
*** Our text has a opacity of 130 and a shade of sky blue.
**** We are again using the alpha_composite method.
Python example: Transparent text drawn on image. (RGBA: 2, 157, 229, 130)

Example 5: Text filled with patterns or images

It’s also possible to use .text method from ImageDraw module to create text objects filled with images and patterns. This is just another example to creative programming which can be quite inspiring for artists and businesspeople.
 
Check out the Python examples below.

You can fill your text with the reef pattern for instance.

Python text object filled with reef image

or stunning fall foliage.

Python text object filled with fall foliage image

To learn how to create design elements like above using Python, you can visit our tutorial: How to crop images in text shapes using Python.

Image Grids with Text

Finally, to create an image grid with text objects similar to the one near the headline of this Python tutorial, you can refer to our tutorial about creating Image Collages with Python.

Image grid (collage) created with Python using text objects.

show() vs save() Showing and/or Saving Python images

When we use .show() method, a temporary .png file gets displayed by the default image opening application on the computer. If there is no such application the graphic server might default to the default browser as well as browsers are capable of opening images.

Once you close the image this temporary .png file gets removed automatically which is convenient if you are making a series of tests and have no interest in keeping these images.

.save() method can be used alternatively to view as well as keep these image files after image editing takes place. .save() method’s usage is very simple. Simple use it on the image that needs to be saved and pass the file name (optionally with the full directory) as a string inside it. For example:

img.show()

If you are using Windows, you might need to experiment with backslash or even double backslashes because single backslash needs to be escaped during the Python source code interpretation and raw string usage might also be useful. Check out this alternative directory format for Windows users:

For Windows:

img.save(r"C:\\Users\\HP\\Documents\\Cover.jpg")

We are using raw string for Windows. Windows directory structure is a bit complicated and you might need to play around with double slashes back/forward slashes etc..

For Linux you can just use regular slash in your full path.

For Linux:

img.save("/home/HP/Documents/Cover.jpg")

Benefits of adding text on images with Python

Compared to image editing software, adding text using Python has quite a few fundamentally advantageous benefits.

  1. Speed: While image editing software takes up lots cpu and memory resources, they will still freeze and hang even on the most powerful computers from time to time. Python PIL library usually doesn’t suffer from such shortcomings and handles image operations at blazing speeds. Furthermore, image editing software such as GIMP or Adobe Photoshop loads up tons of modules and files which you might not need to the memory during startup. If your code is ready, you might be able to apply it to 1000 images during the time image editing software is loading up at startup, that’s true power!
  2. Scalability: Once you got your Python script coded to perfection you can apply it to thousands or even millions of images. All you have to do is acquire the images and create a for loop or while loop to apply the same text-on-image technique to all of the images you need.
  3. High-degree of freedom: What image editing software offers is a user interface that allows you to choose, click and drag objects and execute image editing tasks through buttons and windows. Although it can be convenient, there can be many limitations of this approach. Basically you will be limited by the limits implied by the creators of such software whereas while using Python you are free to edit the image to the absolute basics including the tiniest details at pixel level or regarding various image formats and modes. When you have such pixel-level control of an image, if you can imagine an image editing task you can likely achieve it using Python programming.
  4. 100% Free: Despite its many benefits, Python programming language is completely free (Excluding electricity cost and depreciation of hardware) whereas image editing software can come with hefty license costs or even subscription fees that can make it difficult for students and entrepreneurs to freely get them.
  5. More fun & educative: Programming image manipulation tasks is lots of fun with Python. Moreover, you end up excelling your basic programming skills so it can also be seen as a personal investment and a practice to acquire high-value, high-income skills.

Summary

In this Python Tutorial we learned how to add text to images.

We demonstrated this tutorial with the most simplistic example first. After that we elaborated on various different text-related adjustments including adjustment of text size, text color, text position, text transparency, rotated text, horizontal and vertical aligning, font size, font type and font style using the Python programming language.

Moreover, we included a number of elaborate examples to demonstrate creative opportunities for using text placements on images in a programmatic way.

If you’d like to explore something different you can check out Holypython’s programming tutorials under other sections such as: