ImageDraw() in Python pillow

Pillow is a fork for the Python Imaging Library, PIL, that provides various image-processing features to manipulate images and apply different filters. ImagDraw() is one of the modules in the Pillow library which allows drawing on an image, including shapes and text. This helps to obtain different shape objects that can be overlayed on an image to obtain a new image.

Let's draw different types of shapes in an image using PIL library and show it in Pyplot.

Note: We can also add text on an image. Read an answer on how to add text on images in Python pillow to learn further about it.

Required imports

We will use the PIL library to manipulate the image and then use matplotlib to display the results once the code is executed successfully.

import matplotlib.pyplot as plt
from PIL import Image, ImageDraw, ImageFont
import requests
from io import BytesIO
  • matplotlib: To create visualizations and plots in the Python library.

  • matplotlib: To create visualizations and plots in the Python library.

  • PIL: Computer vision library to apply operations on images.

    • Image: To enhance the image properties that change its appearance.

    • ImageDraw: To draw on the image, e.g., adding text in this case.

  • requests: To send the requests over the HTTP server to the website.

  • BytesIO: To handle the binary data as an in-memory system.

Sample code

This is a sample code structure that can be used in all the codes to manipulate images by adding different overlay shapes using ImageDraw().

#this is a basic code structure, we can add the shape functions on line 23
# importing image object from PIL
import matplotlib.pyplot as plt
from PIL import Image, ImageDraw
import requests
from io import BytesIO
image_url = "https://images.pexels.com/photos/2680270/pexels-photo-2680270.jpeg?auto=compress&cs=tinysrgb&w=300"
# Fetch image
response = requests.get(image_url)
image_data = BytesIO(response.content)
original_image = Image.open(image_data).convert('RGBA')
w, h = 200, 180
shape = [(40, 40), (w - 10, h - 10)]
img = Image.new("RGBA", original_image.size, (0, 0, 0, 0))
# Create pieslice image
myShape = ImageDraw.Draw(img)
#Specify the shape that we want to draw
new_image = Image.alpha_composite(original_image, img)
plt.figure(figsize=(10, 5))
plt.subplots_adjust(wspace=0.4, hspace=0.1)
plt.subplot(1, 3, 1)
plt.imshow(original_image)
plt.axis('off')
plt.title('Original Image')
plt.subplot(1, 3, 2)
plt.imshow(img)
plt.axis('off')
plt.title('Shape Image')
plt.subplot(1, 3, 3)
plt.imshow(new_image)
plt.axis('off')
plt.title('Composite Image')
plt.show()

Code explanation

  • Lines 2–6: Import the required libraries and modules.

  • Line 8: Store the link of the image that is to be used on image_url. We can also use a local image file and give its exact name.

  • Lines 11–12: Use request to fetch the image from the server and open it using the Image.open() method and pass the converted image to it.

  • Lines 13: Convert the image to the RGBA format, open it, and save it in the original_image object.

  • Lines 15–16: Specify the width and height of the shape and set a bounding box for it. The specified range is saved in shape attribute.

  • Line 19: Create transparent blank images that will contain the text.

  • Lines 22: Create an ImageDraw() object and pass the transparent blank image we want to draw on as a parameter to Draw().

  • Lines 23: Use the required shape's function from the ImageDraw() module and pass the start angle, end angle, fill, and outline color as parameters.

  • Lines 25: Use composite() to join the original image and the corresponding transparent image on which the text is added.

  • Lines 27–28: Specify the figure size that is to appear in the plot and assign the grid size.

  • Lines 30–33: Display the image using imshow() and pass the original image to it, turn off the x-axis labels, and specify the title in the title().

  • Lines 35–38: Display the image using imshow() and pass the shape image to it, turn off the x-axis labels, and specify the title in the title().

  • Lines 40–43: Display the image using imshow() and pass the composite image to it, turn off the x-axis labels, and specify the title in the title().

  • Line 45: Show the resultant plot.

Now let's use the sample code and code different shapes using ImageDraw().

Pie slice

A pie slice is a sector of a circle that represents a specific area of the whole pie. The size of the pie slice corresponds to the proportion of the pie that it represents. We use the following code to draw a pie slice.

myShape.pieslice(shape, start=50, end=260, fill="#A7C7E7", outline="#A7C7E7")

The output of the code with the following specifications should be as follows:

Adding a pieslice to an image.
Adding a pieslice to an image.

Example code

In this example code, we draw a pie slice using a pieslice() method and specify the start value as 50 and the end value as 260. We can change these values to obtain different pie slice shapes.

import matplotlib.pyplot as plt
from PIL import Image, ImageDraw
import requests
from io import BytesIO

image_url = "https://images.pexels.com/photos/2680270/pexels-photo-2680270.jpeg?auto=compress&cs=tinysrgb&w=300"

# Fetch image
response = requests.get(image_url)
image_data = BytesIO(response.content)
original_image = Image.open(image_data).convert('RGBA')

w, h = 200, 180
shape = [(40, 40), (w - 10, h - 10)]

img = Image.new("RGBA", original_image.size, (0, 0, 0, 0))

# Create pieslice image
myShape = ImageDraw.Draw(img)
myShape.pieslice(shape, start=50, end=260, fill="#A7C7E7", outline="#A7C7E7")

new_image = Image.alpha_composite(original_image, img)

plt.figure(figsize=(10, 5))
plt.subplots_adjust(wspace=0.4, hspace=0.1)

plt.subplot(1, 3, 1)
plt.imshow(original_image)
plt.axis('off')
plt.title('Original Image')

plt.subplot(1, 3, 2)
plt.imshow(img)
plt.axis('off')
plt.title('Shape Image')

plt.subplot(1, 3, 3)
plt.imshow(new_image)
plt.axis('off')
plt.title('Composite Image')

plt.show()
Add a pieslice shape on an image.

Rectangle

A rectangle is a four-sided shape. The size of the rectangle corresponds to the proportion of the specified width and length of the sides. We use the following code to draw a rectangle.

myShape.rectangle(shape, fill ="#ADD8E6", outline ="#ADD8E6")

The output of the code with the following specifications should be as follows:

Adding a rectangle to an image.
Adding a rectangle to an image.

Example code

In this example code, we draw a circle using rectangle() method and specify fill and outline colors. We can change these values to obtain different colors of the circle shapes.

import matplotlib.pyplot as plt
from PIL import Image, ImageDraw
import requests
from io import BytesIO

image_url = "https://images.pexels.com/photos/2680270/pexels-photo-2680270.jpeg?auto=compress&cs=tinysrgb&w=300"

# Fetch image
response = requests.get(image_url)
image_data = BytesIO(response.content)
original_image = Image.open(image_data).convert('RGBA')

w, h = 200, 180
shape = [(40, 40), (w - 10, h - 10)]

img = Image.new("RGBA", original_image.size, (0, 0, 0, 0))

# Create pieslice image
myShape = ImageDraw.Draw(img)
myShape.rectangle(shape, fill ="#ADD8E6", outline ="#ADD8E6")

new_image = Image.alpha_composite(original_image, img)

plt.figure(figsize=(10, 5))
plt.subplots_adjust(wspace=0.4, hspace=0.1)

plt.subplot(1, 3, 1)
plt.imshow(original_image)
plt.axis('off')
plt.title('Original Image')

plt.subplot(1, 3, 2)
plt.imshow(img)
plt.axis('off')
plt.title('Shape Image')

plt.subplot(1, 3, 3)
plt.imshow(new_image)
plt.axis('off')
plt.title('Composite Image')

plt.show()
Add a rectangle shape on an image.

Ellipse

An ellipse is like a flattened circle representing the set of all points in a plane. The sum of the distance of these points from two fixed points is constant. We use the following code to draw a pie slice.

myShape.ellipse(shape, fill ="#ADD8E6", outline ="#ADD8E6")

The output of the code with the following specifications should be as follows:

Adding an ellipse to an image.
Adding an ellipse to an image.

Example code

In this example code, we draw a flattened circle using ellipse() method and specify fill and outline colors. We can change these values to obtain different colors of the circle shapes.

import matplotlib.pyplot as plt
from PIL import Image, ImageDraw
import requests
from io import BytesIO

image_url = "https://images.pexels.com/photos/2680270/pexels-photo-2680270.jpeg?auto=compress&cs=tinysrgb&w=300"

# Fetch image
response = requests.get(image_url)
image_data = BytesIO(response.content)
original_image = Image.open(image_data).convert('RGBA')

w, h = 200, 180
shape = [(40, 40), (w - 10, h - 10)]

img = Image.new("RGBA", original_image.size, (0, 0, 0, 0))

# Create pieslice image
myShape = ImageDraw.Draw(img)
myShape.ellipse(shape, fill ="#ADD8E6", outline ="#ADD8E6")

new_image = Image.alpha_composite(original_image, img)

plt.figure(figsize=(10, 5))
plt.subplots_adjust(wspace=0.4, hspace=0.1)

plt.subplot(1, 3, 1)
plt.imshow(original_image)
plt.axis('off')
plt.title('Original Image')

plt.subplot(1, 3, 2)
plt.imshow(img)
plt.axis('off')
plt.title('Shape Image')

plt.subplot(1, 3, 3)
plt.imshow(new_image)
plt.axis('off')
plt.title('Composite Image')

plt.show()
Add an ellipse shape on an image.

Polygon

A polygon is a 2D shape with a set number of straight lines joined on vertices to form a closed shape. Each edge intersects exactly two other edges. The polygon's size is determined by the number of sides specified for it. We use the following code to draw a polygon.

side = 6
shift_amount = 20
xy = [
((math.cos(th) + 1) * 90 + shift_amount,
(math.sin(th) + 1) * 60 + shift_amount)
for th in [i * (2 * math.pi) / side for i in range(side)]
]
polygon_img = ImagePath.Path(xy).getbbox()
size = list(map(int, map(math.ceil, polygon_img[2:])))

For drawing a polygon, we import the math module and calculate the shape coordinates using the sine and cosine functions. The coordinates are then used to calculate the bounding box and store its width and height in the list.

The output of the code with the following specifications should be as follows:

Adding a polygon to an image.
Adding a polygon to an image.

Example code

In this example code, we draw a polygon using a polygon() method to specify fill and outline colors. We can change these values to obtain different colors of the polygon shapes.

import matplotlib.pyplot as plt
from PIL import Image, ImageDraw, ImagePath
import requests
from io import BytesIO
import math

# Fetch image
image_url = "https://images.pexels.com/photos/2680270/pexels-photo-2680270.jpeg?auto=compress&cs=tinysrgb&w=300"

response = requests.get(image_url)
image_data = BytesIO(response.content)
original_image = Image.open(image_data).convert('RGBA')

polygon_image = Image.new("RGBA", original_image.size, (0, 0, 0, 0))

side = 6
shift_amount = 20  
xy = [
    ((math.cos(th) + 1) * 90 + shift_amount,
     (math.sin(th) + 1) * 60 + shift_amount)
    for th in [i * (2 * math.pi) / side for i in range(side)]
]

polygon_img = ImagePath.Path(xy).getbbox()
size = list(map(int, map(math.ceil, polygon_img[2:])))

polygon_draw = ImageDraw.Draw(polygon_image)
polygon_draw.polygon(xy, fill="#A7C7E7", outline="#A7C7E7")

new_image = Image.alpha_composite(original_image, polygon_image)

plt.figure(figsize=(10, 4))
plt.subplots_adjust(wspace=0.3)

plt.subplot(1, 3, 1)
plt.imshow(original_image)
plt.axis('off')
plt.title('Original Image')

plt.subplot(1, 3, 2)
plt.imshow(polygon_image)
plt.axis('off')
plt.title('Polygon Image')

plt.subplot(1, 3, 3)
plt.imshow(new_image)
plt.axis('off')
plt.title('Composite Image')

plt.show()
Add a polygon shape on an image.

Arc

An arc is a curve segment that forms a circle's boundary. It represents a portion of the circle's circumference, a curve between two points. We use the following code to draw an arc.

myShape.arc(shape, start = 20, end = 140, fill ="#00FFFF" ,width=5)

The output of the code with the following specifications should be as follows:

Adding an arc to an image.
Adding an arc to an image.

Example code

In this example code, we draw an arc using a arc() method and specify the start value as 20, the end value as 140, and the thickness as 5. We can change these values to obtain different arc shapes.

import matplotlib.pyplot as plt
from PIL import Image, ImageDraw
import requests
from io import BytesIO

image_url = "https://images.pexels.com/photos/2680270/pexels-photo-2680270.jpeg?auto=compress&cs=tinysrgb&w=300"

# Fetch image
response = requests.get(image_url)
image_data = BytesIO(response.content)
original_image = Image.open(image_data).convert('RGBA')

w, h = 200, 180
shape = [(40, 40), (w - 10, h - 10)]

img = Image.new("RGBA", original_image.size, (0, 0, 0, 0))

# Create pieslice image
myShape = ImageDraw.Draw(img)
myShape.arc(shape, start = 20, end = 140, fill ="#00FFFF" ,width=5)

new_image = Image.alpha_composite(original_image, img)

plt.figure(figsize=(10, 5))
plt.subplots_adjust(wspace=0.4, hspace=0.1)

plt.subplot(1, 3, 1)
plt.imshow(original_image)
plt.axis('off')
plt.title('Original Image')

plt.subplot(1, 3, 2)
plt.imshow(img)
plt.axis('off')
plt.title('Shape Image')

plt.subplot(1, 3, 3)
plt.imshow(new_image)
plt.axis('off')
plt.title('Composite Image')

plt.show()
Add an arc shape on an image.

Line

A line is a straight stretched segment from one point to another. Depending on the requirement, it can be horizontal, vertical, or diagonal. We use the following code to draw an arc.

myShape.line(shape, fill ="#00FFFF" ,width=5)

The output of the code with the following specifications should be as follows:

Adding a line to an image.
Adding a line to an image.

Example code

In this example code, we draw a diagonal line using a line() method and specify the fill and width of the shape. We can change these values to obtain different widths and colors of a line.

import matplotlib.pyplot as plt
from PIL import Image, ImageDraw
import requests
from io import BytesIO

image_url = "https://images.pexels.com/photos/2680270/pexels-photo-2680270.jpeg?auto=compress&cs=tinysrgb&w=300"

# Fetch image
response = requests.get(image_url)
image_data = BytesIO(response.content)
original_image = Image.open(image_data).convert('RGBA')

w, h = 200, 180
shape = [(40, 40), (w - 10, h - 10)]

img = Image.new("RGBA", original_image.size, (0, 0, 0, 0))

# Create pieslice image
myShape = ImageDraw.Draw(img)
myShape.line(shape, fill ="#00FFFF" ,width=5)

new_image = Image.alpha_composite(original_image, img)

plt.figure(figsize=(10, 5))
plt.subplots_adjust(wspace=0.4, hspace=0.1)

plt.subplot(1, 3, 1)
plt.imshow(original_image)
plt.axis('off')
plt.title('Original Image')

plt.subplot(1, 3, 2)
plt.imshow(img)
plt.axis('off')
plt.title('Shape Image')

plt.subplot(1, 3, 3)
plt.imshow(new_image)
plt.axis('off')
plt.title('Composite Image')

plt.show()
Add a line shape on an image.

Summary

ImageDraw() is a rich pillow module that provides a variety of shapes that can be drawn on an existing image or as standalone images to obtain a figure as per requirement. We can combine different shapes to make a new shape and attractively illustrate our content.

Free Resources

Copyright ©2025 Educative, Inc. All rights reserved