专栏名称: 编程派
Python程序员都在看的公众号,跟着编程派一起学习Python,看最新国外教程和资源!
目录
相关文章推荐
Python爱好者社区  ·  见证历史,79万封神 ·  昨天  
Python开发者  ·  字节回应大模型训练被实习生攻击 ·  3 天前  
Python爱好者社区  ·  某211副教授自爆“评职称”历程:评审内幕堪 ... ·  1 周前  
Python爱好者社区  ·  48k*15薪!进字节了! ·  1 周前  
Python爱好者社区  ·  1885页Python电子书 ·  1 周前  
51好读  ›  专栏  ›  编程派

使用Pillow对图像进行编辑修改

编程派  · 公众号  · Python  · 2017-01-17 11:52

正文

接昨天那篇,更深入地学习Pillow的用法。

作者:liam0205

原文:http://liam0205.me/2015/04/22/pil-tutorial-basic-usage/index.html


上一篇文章介绍了 PIL 的基本情况,以及 Image 模块的基本用法。这篇文章,我们讨论一下 ImageDraw 和 ImageFont 两个模块的基本用法,说说如何用 PIL 在现有的图片上涂涂改改。

ImageDraw 模块

ImageDraw 模块提供了 Draw 类,它能在 Image 实例上进行简单的 2D 绘图。当然复杂的绘图动作是由简单的动作合成而得的,理论上这些动作 ImageDraw 模块也能做,只是相对复杂。如果你想在 Image 实例上做复杂的绘图动作,最好是自行对 ImageDraw 模块提供的各种方法做一些封装。

创建一个 Draw 类的实例

要在 Image 实例上绘制新的图样,首先要做的就是创建一个 Draw 类的实例。

  1. from PIL import Image, ImageDraw

  2. sourceFileName = "source.png"

  3. avatar = Image.open(sourceFileName)

  4. drawAvatar = ImageDraw.Draw(avatar)

代码前三行我们已经见过,唯一的差别在于 import 之后除了我们已经见过的 Image 模块,还有今次我们要使用的 ImageDraw 模块。

从画两条平行线开始

Draw 类提供了 line ( xy , options ) 方法绘制直线。

其中 xy 表示坐标列表,其形式可以是

  • [ ( x 1, y 1), ( x 2, y 2), ... ] - 包含若干个元组的列表

  • [1, y 1, x 2, y 2, ... ] - 按照顺序包含坐标信息的列表

  • [1, y 1, ( x 2, y 2), ... ] - 以上两种情况的混合

  • (( x 1, y 1), ( x 2, y 2), ...) - 包含若干个元组的元组

  • ( x 1, y 1, x 2, y 2, ...) - 按照顺序包含坐标信息的元组

  • ( x 1, y 1, ( x 2, y 2), ...) - 以上两种情况的混合

options 中可用的选项有

  • fill = ( R , G , B )- 用于指定线条的颜色,其中 R 、 G 、 B 都是 0 - 255 的整数

  • width = integer- 用于指定线条的宽度,单位是像素

  1. from PIL import Image, ImageDraw

  2. sourceFileName = "source.png"

  3. avatar = Image.open(sourceFileName)

  4. drawAvatar = ImageDraw.Draw(avatar)

  5. xSize, ySize = avatar.size

  6. drawAvatar.line([0, 0.33 * ySize, xSize, 0.33 * ySize],

  7.                fill=(255, 100, 0), width=3)

  8. drawAvatar.line([0, 0.67 * ySize, xSize, 0.67 * ySize],

  9.                fill=(255, 0, 0), width=3)

  10. del drawAvatar

  11. avatar.show()

这里我们在图片的两个三等分位置分别画了一条宽度为 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

  2. sourceFileName = "source.png"

  3. avatar = Image.open(sourceFileName)

  4. drawAvatar = ImageDraw.Draw(avatar)

  5. xSize, ySize = avatar.size

  6. drawAvatar.arc([0, 0, xSize, ySize], 0, 90,

  7.               fill=(255, 100, 255))

  8. del drawAvatar

  9. avatar.show()

在图片上写字

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

  2. sourceFileName = "source.png"

  3. avatar = Image.open(sourceFileName)

  4. drawAvatar = ImageDraw.Draw(avatar)

  5. xSize, ySize = avatar.size

  6. drawAvatar.text([0.9 * xSize, 0.1 * ySize - drawAvatar.textsize("3")[1]],

  7.                "3", fill=(128, 0, 128))

  8. del drawAvatar

  9. avatar.show()

由于没有用 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

  2. sourceFileName = "source.png"

  3. avatar = Image.open(sourceFileName)

  4. drawAvatar = ImageDraw.Draw(avatar)

  5. xSize, ySize = avatar.size

  6. fontSize = min(xSize, ySize) // 11

  7. myFont = ImageFont.truetype("/Library/Fonts/OsakaMono.ttf", fontSize)

  8. drawAvatar.text([0.9 * xSize, 0.1 * ySize - fontSize],

  9.                "3", fill=(255, 0, 0), font=myFont)

  10. del drawAvatar

  11. avatar.show()

这里我们引入了 ImageFont 模块,并且创建了 myFont 实例。创建实例的时候,传入的字体尺寸由图片大小决定。最后在图片上写字的位置也与字体大小有关。

这样以来,我们就在图片的右上角写了一个红色的数字,就好像微信未读消息提示的那种效果。

小结

ImageDraw 模块还有许多其他的功能,比如绘制椭圆、多边形、矩形等。限于篇幅,这里就不一一介绍了。感兴趣的读者可以参看官方文档:

http://effbot.org/imagingbook/imagedraw.htm#methods


题图:pexels,CC0 授权。

点击阅读原文,查看更多 Python 教程和资源。

推荐文章
Python爱好者社区  ·  见证历史,79万封神
昨天
Python开发者  ·  字节回应大模型训练被实习生攻击
3 天前
Python爱好者社区  ·  48k*15薪!进字节了!
1 周前
Python爱好者社区  ·  1885页Python电子书
1 周前
灼见  ·  写给25+女孩的10条建议
7 年前
读万卷书聚正能量  ·  谈话让别人舒服的程度,决定你的高度!
7 年前
南周知道  ·  女孩,别再错过每一次新生的机会
7 年前