Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

PIL

PIL - Pillow

Install Pillow

pip install pillow

Create First Image

  • Image
  • size
  • color
from PIL import Image

img = Image.new('RGB', size=(100, 60), color='#eb8634')
img.save('first.png')
img.show()     # Using ImageMagic on Linux
  • Color can be one of the well-known names e.g. "red"
  • Color can be RGB in decimal or hex. (RGB=Red Green Blue)

Write Text on Image

from PIL import Image, ImageDraw

img = Image.new('RGB', size=(100, 60), color='#eb8634')

draw = ImageDraw.Draw(img)
draw.text(
    text="Some text",
    xy=(10, 20),
)

img.save('first.png')
img.show()

Select font for Text on Image

from PIL import Image, ImageDraw, ImageFont

img = Image.new(mode='RGB', size=(300, 60), color='#eb8634')
font = ImageFont.truetype('Pillow/Tests/fonts/FreeMono.ttf', 20)
#font = ImageFont.truetype(f'c:\Windows\Fonts\Candara.ttf', 30)
#font = ImageFont.truetype(f'c:\Windows\Fonts\Candarab.ttf', 30)
#font = ImageFont.truetype(f'c:\Windows\Fonts\david.ttf', 30)


draw = ImageDraw.Draw(img)
draw.text(
    text="Some text",
    xy=(10, 20),
    font=font,
)

img.save('first.png')
img.show()

Font directories

Linux: /usr/share/fonts/
Max OS: /Library/Fonts/
Windows: C:\Windows\fonts

Get size of an Image

from PIL import Image
import sys

if len(sys.argv) !=2:
    exit(f"Usage: {sys.argv[0]} FILENAME")

in_file = sys.argv[1]

img = Image.open(in_file)
print(img.size)    # a tuple
print(img.size[0]) # width
print(img.size[1]) # height

print(sys.getsizeof(img)) # The size of the variable
print(sys.getsizeof(img.tobytes())) # The payload

Get size of text

    font = ImageFont.truetype(
        'path/to/font.ttf', size
    )
    size = font.getsize(text)

Resize an existing Image

from PIL import Image

in_file = 'in.png'
out_file = 'new.png'

img = Image.open(in_file)

size = (img.size[0] / 2, img.size[1] / 2)
img.thumbnail(size)

img.save(out_file)

Crop an existing Image

from PIL import Image

in_file = 'in.png'
out_file = 'out.png'

img = Image.open(in_file)
width, height = img.size
width, height = img.size

# crop
# 10 pixels from the left
# 20 pixels from the top
# 30 pixels from the right
# 40 pixels from the bottom

cropped = img.crop((10, 20, width - 30, height - 40))
cropped.save(out_file)
cropped.show()

Combine two images

  • Load one image from file
  • Create a plain background
  • Put the loaded image on the background
  • Save the combined image

Rotated text

from PIL import Image, ImageDraw, ImageFont, ImageOps

img = Image.new(mode='RGB', size=(400, 200), color='#eb8634')

font = ImageFont.truetype('Pillow/Tests/fonts/FreeSansBold.ttf', 30)

text_layer = Image.new('L', (330, 50))
draw = ImageDraw.Draw(text_layer)
draw.text( (30, 0), "Text slightly rotated",  font=font, fill=255)

rotated_text_layer = text_layer.rotate(10.0, expand=1)
img.paste( ImageOps.colorize(rotated_text_layer, (0,0,0), (10, 10,10)), (42,60),  rotated_text_layer)
img.show()

Rotated text in top-right corner

TODO: fix this

from PIL import Image, ImageDraw, ImageFont, ImageOps

width = 400
height = 200
start = 100
end   = 50

img = Image.new(mode='RGB', size=(width, height), color='#FAFAFA')

stripe_color = "#eb8634"
draw = ImageDraw.Draw(img)
draw.polygon([(width-start, 0), (width-end, 0), (width, end), (width, start) ], fill=stripe_color)


font = ImageFont.truetype('Pillow/Tests/fonts/FreeSansBold.ttf', 30)
text_layer = Image.new('RGB', size=(100, 100), color=stripe_color)

draw = ImageDraw.Draw(text_layer)
text = "Free"
size = draw.textsize(text=text, font=font)
# print(size)
draw.text( xy=(20, 0), text=text,  font=font, fill=1)
#
rotated_text_layer = text_layer.rotate(-45.0, expand=0)
rotated_text_layer.show()
#img.paste( ImageOps.colorize(rotated_text_layer, (0,0,0), (10, 10,10)), (42,60),  rotated_text_layer)
#img.paste(im = rotated_text_layer, box=(300, 0))
#img.paste(im = text_layer, box=(300, 0))
#img.show()

Embed image (put one image on another one)

from PIL import Image

in_file = 'python.png'

width = 600
height = 300
background = Image.new(mode='RGB', size=(width, height), color='#AAFAFA')

img = Image.open(in_file)
(emb_width, emb_height) = img.size
print(emb_width)
print(emb_height)

# slightly off the lower right corner of the background image
# using the image as the mask makes its background transparent
background.paste(im = img, box=(width-emb_width-10, height-emb_height-10), mask=img)

background.show()

Draw a triangle

from PIL import Image, ImageDraw

img = Image.new(mode='RGB', size=(800, 450), color='#eb8634')

draw = ImageDraw.Draw(img)
draw.polygon([(790, 275), (790, 430), (300, 430) ])

img.save('first.png')
img.show()

Draw a triangle and write text in it

from PIL import Image, ImageDraw, ImageFont

img = Image.new(mode='RGB', size=(800, 450), color='#eb8634')

draw = ImageDraw.Draw(img)
draw.polygon([(800, 275), (800, 450), (300, 450) ], fill = (255, 255, 255))

font = ImageFont.truetype('Pillow/Tests/fonts/FreeSansBold.ttf', 30)

draw.text((500, 400), 'Hello from Python', (0, 0, 0), font=font)


img.save('first.png')
img.show()

Draw a triangle and write rotated text in it

from PIL import Image, ImageDraw, ImageFont, ImageOps

img = Image.new(mode='RGB', size=(400, 200), color='#eb8634')

# #draw = ImageDraw.Draw(img)
# #draw.polygon([(800, 275), (800, 450), (300, 450) ], fill = (255, 255, 255))
#
#
#font = ImageFont.load_default()
font = ImageFont.truetype('Pillow/Tests/fonts/FreeSansBold.ttf', 30)
# txt = Image.new('L', (500, 500))
# d = ImageDraw.Draw(txt)
# d.text((300, 400), 'Hello from Python', font=font, color="white")
# w=txt.rotate(17.5,  expand=1)
#
# #img.paste(txt)
# img.paste( ImageOps.colorize(w, (0,0,0), (255,255,84)), (242,60),  w)
# # img.save('first.png')
# img.show()
#

text_layer = Image.new('L', (300, 50))
draw = ImageDraw.Draw(text_layer)
draw.text( (30, 0), "Text slightly rotated",  font=font, fill=255)

rotated_text_layer = text_layer.rotate(10.0, expand=1)
img.paste( ImageOps.colorize(rotated_text_layer, (0,0,0), (10, 10,10)), (42,60),  rotated_text_layer)
img.show()

Draw a rectangle

from PIL import Image, ImageDraw

img = Image.new('RGB', size=(100, 100))

draw = ImageDraw.Draw(img)
draw.rectangle((10, 10, 90, 90), fill="yellow", outline="red")
img.show()

Draw circle

from PIL import Image, ImageDraw

img = Image.new('RGB', (200, 200))

draw = ImageDraw.Draw(img)
draw.ellipse((50, 50, 150, 150), fill="#F00F4F")
img.show()

Draw heart

from PIL import Image, ImageDraw

def heart(size, fill):
    width, height = size
    img = Image.new('RGB', size, (0, 0, 0, 0))
    draw = ImageDraw.Draw(img)
    polygon = [
        (width / 10, height / 3),
        (width / 10, 81 * height / 120),
        (width / 2, height),
        (width - width / 10, 81 * height / 120),
        (width - width / 10, height / 3),
    ]
    draw.polygon(polygon, fill=fill)
    #img.show()

    draw.ellipse((0, 0,  width / 2, 3 * height / 4), fill=fill)
    draw.ellipse((width / 2, 0,  width, 3 * height / 4), fill=fill)
    return img

img = heart((50, 40), "red")
img.show()

Some samples, including this one, originally by Nadia Alramli

Rectangle with rounded corners

from PIL import Image, ImageDraw


def round_corner(radius, fill):
    """Draw a round corner"""
    corner = Image.new('RGB', (radius, radius), (0, 0, 0, 0))
    draw = ImageDraw.Draw(corner)
    draw.pieslice((0, 0, radius * 2, radius * 2), 180, 270, fill=fill)
    return corner


def round_rectangle(size, radius, fill):
    """Draw a rounded rectangle"""
    width, height = size
    rectangle = Image.new('RGB', size, fill)
    corner = round_corner(radius, fill)
    rectangle.paste(corner, (0, 0))
    rectangle.paste(corner.rotate(90), (0, height - radius))  # Rotate the corner and paste it
    rectangle.paste(corner.rotate(180), (width - radius, height - radius))
    rectangle.paste(corner.rotate(270), (width - radius, 0))
    return rectangle


img = round_rectangle((50, 50), 10, "yellow")

img.show()

Some samples, including this one, originally by Nadia Alramli

TODO

  • http://web.archive.org/web/20130115175340/
  • http://nadiana.com/pil-tutorial-basic-advanced-drawing
  • Make the background color change from top to bottom
  • Add straight lines to existing images
  • Blur image
  • Add rectangle to area on existing image
  • Draw other simple images