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
We can break up adding text to images to 4 steps.
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()
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.
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)
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.
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()
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()
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 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()
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()
With proper image and font style the result looks a lot more appealing already.
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.
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.
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:
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:
Sometimes, especially when working on scale, you might want to use dynamic positioning instead of providing manual text coordinates.
.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
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()
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)
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()
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()
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.
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()
You can fill your text with the reef pattern for instance.
or stunning fall foliage.
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.
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.
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")
You can also visit our Open, show, save images with Python tutorial.
Compared to image editing software, adding text using Python has quite a few fundamentally advantageous benefits.
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: