这是系列文章的第二篇,参见系列中的相关内容。
上一篇文章 介绍了 PIL 的基本情况,以及 Image
模块的基本用法。这篇文章,我们讨论一下 ImageDraw
和 ImageFont
两个模块的基本用法,说说如何用 PIL 在现有的图片上涂涂改改。
ImageDraw
模块
ImageDraw
模块提供了 Draw
类,它能在 Image
实例上进行简单的 2D 绘图。当然复杂的绘图动作是由简单的动作合成而得的,理论上这些动作 ImageDraw
模块也能做,只是相对复杂。如果你想在 Image
实例上做复杂的绘图动作,最好是自行对 ImageDraw
模块提供的各种方法做一些封装。
创建一个 Draw
类的实例
要在 Image
实例上绘制新的图样,首先要做的就是创建一个 Draw
类的实例。
1 | from PIL import Image, ImageDraw |
代码前三行我们已经见过,唯一的差别在于 import
之后除了我们已经见过的 Image
模块,还有今次我们要使用的 ImageDraw
模块。
从画两条平行线开始
Draw
类提供了 line(xy, options)
方法绘制直线。
其中 xy
表示坐标列表,其形式可以是
[(x1, y1), (x2, y2), ...]
- 包含若干个元组的列表[x1, y1, x2, y2, ...]
- 按照顺序包含坐标信息的列表[x1, y1, (x2, y2), ...]
- 以上两种情况的混合((x1, y1), (x2, y2), ...)
- 包含若干个元组的元组(x1, y1, x2, y2, ...)
- 按照顺序包含坐标信息的元组(x1, y1, (x2, y2), ...)
- 以上两种情况的混合
options
中可用的选项有
fill = (R, G, B)
- 用于指定线条的颜色,其中R
、G
、B
都是 0 -- 255 的整数width = integer
- 用于指定线条的宽度,单位是像素
1 | from PIL import Image, ImageDraw |
这里我们在图片的两个三等分位置分别画了一条宽度为 3 像素的平行线。一条颜色为 (255, 100, 0),另一条则是 (255, 0, 0)。
值得注意的是代码的第 14 行,我们直接用 avatar.show()
来展现绘图的结果。可见**Draw
类的实例将直接在 Image
实例上进行操作**。
画一段弧
Draw
类也提供了 arc(xy, start, end, options)
方法来绘制弧。
这里的 xy
是一个长度为 4 的列表,用来表示一个 bounding box(参考上一篇文章)。start
和 end
则是弧的起止角度,单位是 °。其中水平向右的方向为 0°,竖直向下的方向为 90°,水平向左的方向为 180°,竖直向上的方向为 270°。
options
中可用的选项有
fill = (R, G, B)
- 用于指定线条的颜色,其中R
、G
、B
都是 0 -- 255 的整数
arc
方法将在内切于 bounding box 的椭圆中,按照给定的起止角度切下一段弧,并绘制于 Image
示例之上。
1 | from PIL import Image, ImageDraw |
在图片上写字
Draw
类提供了 text(position, string, options)
方法,该方法可以在 Image
实例上写字。
需要说明的是,position
指定的是文本左上角的顶点,而不是文本中心。这里可用的 options
有
font = ImageFont instance
- 指定字体,接受一个ImageFont
的实例fill = (R, G, B)
- 用于指定线条的颜色,其中R
、G
、B
都是 0 -- 255 的整数
1 | from PIL import Image, ImageDraw |
由于没有用 font
选项指定字体,这里使用了 ImageDraw
的默认字体。不难发现,相对图片,字体太小了。为了调整字体,我们需要借助 ImageFont
模块。
ImageFont
模块
ImageFont
模块很简单,它定义了一个同名的类。ImageFont
类的实例可以传给 ImageDraw
中 text
方法的 font
的参数,起到字体选择的作用。
ImageFont
模块中的 load
函数可以加载一个 Image 格式的字体,并返回 ImageFont
实例;其中的 truetype(fontfile, fontsize)
函数则可以加载 TrueType 或 OpenType 格式的字体,并返回 ImageFont
参数。不过 truetype
函数需要额外安装 _imagingft
模块。
配置好之后,我们可以对上一节末尾的代码稍作修改:
1 | from PIL import Image, ImageDraw, ImageFont |
这里我们引入了 ImageFont
模块,并且创建了 myFont
实例。创建实例的时候,传入的字体尺寸由图片大小决定。最后在图片上写字的位置也与字体大小有关。
这样以来,我们就在图片的右上角写了一个红色的数字,就好像微信未读消息提示的那种效果。
小结
ImageDraw
模块还有许多其他的功能,比如绘制椭圆、多边形、矩形等。限于篇幅,这里就不一一介绍了。感兴趣的读者可以参看官方文档: