PIL Tutorial: From Basic to Advanced Drawing
The ImageDraw module provides simple 2D graphics for Image
objects. You can use it to create new images, annotate or retouch existing images, and generate graphics on the fly for usage on the web. In this tutorial I'm going to show you how to use this module to draw 2D graphics. I'll start with basic shapes and then move on to fairly complicated ones.
The Draw Object
To draw on an image, you need to create an ImageDraw
object first. This is what the Draw
method is for:
Draw(image) => Draw instance
This object will enable you to draw on the given image. You can use it to draw as many shapes as needed, and the image will be modified in place.
Drawing a Rectangle
draw.rectangle(box, fill=None, outline=None)
The box can be any sequence object containing either 2-tuples [(x1, y1), (x2, y2)]
or numeric values [x1, y1, x2, y2]
. It should contain two pairs of coordinates. The outline is the color to use for the rectangle's outline. The fill is the color to use for the rectangle's interior.
Example:
from PIL import Image, ImageDraw im = Image.new('RGBA', (100, 100), (0, 0, 0, 0)) # Create a blank image draw = ImageDraw.Draw(im) # Create a draw object draw.rectangle((10, 10, 90, 90), fill="yellow", outline="red")
Here I used color names to specify fill and outline colors. You can also use tuples or hexadecimal color specifiers as #rrggbb. Refer to ImageDraw documentation for the full list of supported color formats.
Tip: To draw a rectangle with a specific outline width that is greater than 1px, you can draw two rectangles on top of each other with the inner box slightly smaller. Fill the outer rectangle with the outline color and the inner one with the fill color:
from PIL import Image, ImageDraw def rectangle(input, box, fill, outline, width): draw = ImageDraw.Draw(input) draw.rectangle(box, fill=outline) # The outer rectangle draw.rectangle( # The inner rectangle (box[0] + width, box[1] + width, box[2] - width, box[3] - width), fill=fill ) input = Image.new('RGBA', (40, 40), (0, 0, 0, 0)) rectangle(input, (0, 0, 39, 39), "lightblue", "blue", 5)
The result will look like this:
Drawing a Circle
draw.ellipse(box, fill=None, outline=None)
Draws an ellipse inside the given bounding box. If width is equal to height, the result will be a circle:
im = Image.new('RGBA', (100, 100), (0, 0, 0, 0)) # Create a blank image draw = ImageDraw.Draw(im) # Create a draw object draw.ellipse((0, 0, 100, 100), fill=(255, 255, 255)) # Draw a circle
To specify the outline width you can use the same tip as in the rectangle example.
Drawing a Polygon
draw.polygon(coordinates, fill=None, outline=None)
The polygon outline consists of straight lines between the given coordinates, plus a straight line between the last and the first coordinate.
The coordinate list can be any sequence object containing either 2-tuples [ (x, y), ... ] or numeric values [ x, y, ... ]. It should contain at least three coordinates.
The following will draw a regular pentagon:
im = Image.new('RGBA', (100, 100), (0, 0, 0, 0)) # Create a blank image draw = ImageDraw.Draw(im) lines = [(50, 0), (0, 40), (20, 100), (80, 100), (100, 40)] draw.polygon(lines, fill="black")
Drawing Text
text(position, text, fill=None, font=None)
Draws the string at the given position. The position gives the upper left corner of the text. The font option is used to specify which font to use. It should be an instance of the ImageFont class, typically loaded from file using the load or truetype method in the ImageFont module. The fill option specifies the color to use for the text:
im = Image.new('RGBA', (100, 100), (0, 0, 0, 0)) # Create a blank image draw = ImageDraw.Draw(im) draw.text((10, 50), 'Hello World!')
You can use the ImageFont.truetype
method to create a font object for drawing text.
ImageFont.truetype(font_path, size) => Font instance
This will load a TrueType or OpenType font file, and create a font object. This function loads a font object from the given file, and creates a font object for a font of the given size. On Windows, if the given file name does not exist, the loader also looks in Windows fonts directory.
Here are the default font directory paths:
Linux: /usr/share/fonts/ Max OS: /Library/Fonts/ Windows: C:\Windows\fonts
Example:
from PIL import ImageDraw, ImageFont font = ImageFont.truetype( 'path/to/font.ttf', 30 ) draw.text((10, 50), 'Logo', font=font, fill="blue")
If you want to draw text that fits exactly inside an image, then you can use the handy font.getsize
method:
def draw_text(text, size, fill=None): font = ImageFont.truetype( 'path/to/font.ttf', size ) size = font.getsize(text) # Returns the width and height of the given text, as a 2-tuple. im = Image.new('RGBA', size, (0, 0, 0, 0)) # Create a blank image with the given size draw = ImageDraw.Draw(im) draw.text((0, 0), text, font=font, fill=fill) #Draw text return im img = draw_text('Google', 30, (82, 124, 178))
Output:
Drawing Text at an Angle
The text
method doesn't support writing at an angle. But we can achieve rotation by simply rotating the resulting image. Here is the modified version:
def draw_text(text, size, angle=0, fill=None): font = ImageFont.truetype( 'path/to/font.ttf', size ) size = font.getsize(text) # Returns the width and height of the given text, as a 2-tuple. im = Image.new('RGBA', size, (0, 0, 0, 0)) # Create a blank image with the given size draw = ImageDraw.Draw(im) draw.text((0, 0), text, font=font, fill=fill) #Draw text return im.rotate(angle, expand=True) img = draw_text('Google', 30, 45, (82, 124, 178))
Output:
Drawing Rounded Corners Rectangle
The idea is simple enough: draw a rectangle then paste a rounded corner on top of each corner.
def round_corner(radius, fill): """Draw a round corner""" corner = Image.new('RGBA', (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('RGBA', 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")
The result:
Drawing a Heart
The heart shape can be a little tricky. You need to get the calculations right. The following method draws a polygon and two ellipses, like this:
+ =>
def heart(size, fill): width, height = size im = Image.new('RGBA', size, (0, 0, 0, 0)) draw = ImageDraw.Draw(im) 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) draw.ellipse((0, 0, width / 2, 3 * height / 4), fill=fill) draw.ellipse((width / 2, 0, width, 3 * height / 4), fill=fill) return im im = heart((50, 40), "red")
Comments
Drawing
You can also create nice antialiased graphics with pycairo:
http://www.cairographics.org/samples/
this is very useful thanks
this is very useful thanks
Thank you
I love theses
Post new comment