第四篇:画笔生花:图像的绘图与文字 (创意篇)
开篇提问:
你有没有想过,在照片上涂鸦,或者给图片加上可爱的文字,让它们变得独一无二? 就像在纸上绘画一样,我们也可以在图像上“画画”和“写字”! PIL 库就为我们提供了这样的“画笔”和“颜料”,让我们可以在图像上自由创作,添加各种个性化的元素和信息。 今天,就让我们拿起 PIL 的“画笔”,一起在图像上“画”出精彩,“写”出创意!
核心概念讲解 (费曼式解释):
-
ImageDraw 模块: “我们的数字画布和画笔”
想要在图像上绘图,首先我们需要一个 “画布” 和一套 “画笔”。 PIL 库的
ImageDraw
模块就扮演着这样的角色。 它就像一个 绘图工具箱,里面装满了各种绘图工具,可以让我们在 PIL 图像对象上绘制各种图形和文字。要使用
ImageDraw
模块,首先需要 创建一个Draw
对象,这个对象就相当于我们的 “画布”,所有的绘图操作都会在这个画布上进行。 创建Draw
对象很简单,只需要导入ImageDraw
模块,并调用ImageDraw.Draw(img)
函数,传入你要绘图的 PIL 图像对象img
就可以了。from PIL import Image, ImageDraw # 打开一张图片作为画布 image_path = "your_image.jpg" img = Image.open(image_path) # 创建 Draw 对象,img 就是我们的画布 draw = ImageDraw.Draw(img) # 接下来我们就可以使用 draw 对象进行各种绘图操作了!
-
绘制基本图形: “点线面,绘出万千世界”
有了画布和画笔,我们就可以开始绘制各种基本图形了。
ImageDraw
模块提供了丰富的绘图函数,可以绘制 点、线、矩形、椭圆、多边形 等各种基本形状。 就像我们小时候用铅笔和尺子画画一样,只不过现在我们用的是数字画笔!-
点 (Point): “星星点点,勾勒细节”
draw.point(xy, fill=color)
函数用于绘制 点。xy
参数是点的 坐标,可以是一个 坐标元组(x, y)
,或者一个 坐标列表[(x1, y1), (x2, y2), ...]
,可以一次绘制多个点。fill
参数是点的 颜色。# 绘制一个红色的点 (坐标 (100, 100)) draw.point((100, 100), fill="red") # 绘制多个绿色的点 (坐标 (150, 150), (200, 200), (250, 250)) draw.point([(150, 150), (200, 200), (250, 250)], fill="green")
-
线 (Line): “一笔划过,连接你我”
draw.line(xy, fill=color, width=width)
函数用于绘制 线段 或 折线。xy
参数是 线段的端点坐标 或 折线的顶点坐标,可以是一个 坐标列表[(x1, y1), (x2, y2)]
(线段) 或[(x1, y1), (x2, y2), (x3, y3), ...]
(折线)。fill
参数是线的 颜色,width
参数是线的 宽度 (像素)。# 绘制一条蓝色的直线 (从 (50, 50) 到 (300, 50),宽度 3 像素) draw.line([(50, 50), (300, 50)], fill="blue", width=3) # 绘制一条紫色的折线 (连接 (50, 100), (100, 150), (150, 100), (200, 150)) draw.line([(50, 100), (100, 150), (150, 100), (200, 150)], fill="purple")
-
矩形 (Rectangle): “方方正正,规规矩矩”
draw.rectangle(xy, fill=color, outline=outline_color, width=outline_width)
函数用于绘制 矩形。xy
参数是矩形的 左上角和右下角坐标,是一个 坐标元组(x0, y0, x1, y1)
。fill
参数是矩形的 填充颜色 (可以为空,表示空心矩形),outline
参数是矩形的 边框颜色,width
参数是矩形的 边框宽度 (像素)。# 绘制一个黄色的实心矩形 (左上角 (100, 200),右下角 (200, 300)) draw.rectangle((100, 200, 200, 300), fill="yellow") # 绘制一个红色边框的空心矩形 (左上角 (250, 200),右下角 (350, 300),边框宽度 5 像素) draw.rectangle((250, 200, 350, 300), outline="red", width=5)
-
椭圆 (Ellipse): “圆润饱满,婀娜多姿”
draw.ellipse(xy, fill=color, outline=outline_color, width=outline_width)
函数用于绘制 椭圆 (包括圆形)。xy
参数是椭圆的 外接矩形的左上角和右下角坐标,也是一个 坐标元组(x0, y0, x1, y1)
。 其他参数fill
,outline
,width
与draw.rectangle()
函数类似。 如果外接矩形是正方形,则绘制的是圆形。# 绘制一个橙色的实心椭圆 (外接矩形 左上角 (50, 350),右下角 (200, 450)) draw.ellipse((50, 350, 200, 450), fill="orange") # 绘制一个绿色边框的空心圆形 (外接正方形 左上角 (250, 350),右下角 (350, 450),边框宽度 3 像素) draw.ellipse((250, 350, 350, 450), outline="green", width=3)
-
多边形 (Polygon): “千变万化,自由组合”
draw.polygon(xy, fill=color, outline=outline_color)
函数用于绘制 多边形。xy
参数是多边形的 顶点坐标,是一个 坐标列表[(x1, y1), (x2, y2), (x3, y3), ...]
。fill
参数是多边形的 填充颜色 (可以为空,表示空心多边形),outline
参数是多边形的 边框颜色。# 绘制一个蓝色的实心三角形 (顶点坐标 (100, 500), (150, 600), (200, 500)) draw.polygon([(100, 500), (150, 600), (200, 500)], fill="blue") # 绘制一个红色边框的空心五边形 (顶点坐标 ...) draw.polygon([(250, 500), (300, 520), (330, 580), (270, 600), (220, 550)], outline="red")
-
-
添加文字 (Text): “字字珠玑,传递信息”
draw.text(xy, text, fill=color, font=font)
函数用于在图像上 添加文字。xy
参数是 文字的左上角坐标。text
参数是要 绘制的文本内容 (字符串)。fill
参数是 文字颜色。font
参数是 字体对象,需要使用ImageFont.truetype()
或ImageFont.load_default()
函数 创建字体对象。 如果不指定font
参数,则使用 默认字体 (通常不太美观,建议指定字体)。-
字体 (Font): “文字的 “外衣””
字体决定了文字的 外观 风格。 PIL 库使用
ImageFont
模块来处理字体。 要使用 TrueType 字体文件 (.ttf, .otf),需要使用ImageFont.truetype(font_path, size)
函数 加载字体文件。font_path
是 字体文件的路径,size
是 字体大小 (像素)。 如果你没有特定的字体文件,可以使用ImageFont.load_default()
函数 加载默认字体。from PIL import Image, ImageDraw, ImageFont # ... (打开图像, 创建 Draw 对象) ... # 1. 使用默认字体 (不推荐,通常比较丑) draw.text((50, 50), "Hello, PIL! (Default Font)", fill="black") # 2. 加载 TrueType 字体文件 (需要指定字体文件路径,例如 "arial.ttf") try: font_path = "arial.ttf" # 替换成你电脑上实际的字体文件路径 font = ImageFont.truetype(font_path, size=36) # 字体大小 36 像素 draw.text((50, 100), "Hello, PIL! (Arial Font)", fill="blue", font=font) except IOError: print("字体文件加载失败,请检查字体文件路径或安装字体") default_font = ImageFont.load_default() # 加载默认字体作为备选 draw.text((50, 100), "Hello, PIL! (Default Font - Fallback)", fill="blue", font=default_font) # 3. 使用默认字体 (另一种方式) default_font = ImageFont.load_default() draw.text((50, 150), "Hello, PIL! (Default Font - Explicit)", fill="green", font=default_font)
注意:
arial.ttf
只是一个示例字体文件名,你需要 根据你的电脑系统和字体安装情况,选择一个实际存在的 TrueType 字体文件路径。 常见的字体文件路径可能在 Windows 的C:\Windows\Fonts
目录下,或者 macOS 的/Library/Fonts
或/System/Library/Fonts
目录下。 你可以根据你的操作系统搜索字体文件,并替换代码中的font_path
。 如果找不到合适的字体文件,可以先尝试使用ImageFont.load_default()
默认字体。
-
代码实战 (动手练习):
我们继续使用 your_image.jpg
图片作为画布,练习绘制各种图形和添加文字。
from PIL import Image, ImageDraw, ImageFont
image_path = "your_image.jpg"
img = Image.open(image_path).convert("RGB") # 确保是 RGB 模式,方便颜色显示
draw = ImageDraw.Draw(img)
# 1. 绘制点
draw.point((50, 50), fill="red")
draw.point([(100, 50), (150, 50), (200, 50)], fill="green")
# 2. 绘制线
draw.line([(50, 100), (200, 100)], fill="blue", width=3)
draw.line([(50, 150), (100, 200), (150, 150), (200, 200)], fill="purple")
# 3. 绘制矩形
draw.rectangle((50, 250, 150, 350), fill="yellow")
draw.rectangle((200, 250, 300, 350), outline="red", width=5)
# 4. 绘制椭圆
draw.ellipse((50, 400, 150, 500), fill="orange")
draw.ellipse((200, 400, 300, 500), outline="green", width=3)
# 5. 绘制多边形
draw.polygon([(50, 550), (100, 650), (150, 550)], fill="blue")
draw.polygon([(200, 550), (250, 570), (280, 630), (220, 650), (170, 600)], outline="red")
# 6. 添加文字 (使用默认字体,你也可以尝试加载 TrueType 字体)
default_font = ImageFont.load_default()
draw.text((50, 700), "Hello, PIL! - Points, Lines, Shapes", fill="black", font=default_font)
draw.text((50, 750), "Drawing is Fun!", fill="purple", font=default_font)
# 保存结果
img.save("drawing_image.jpg")
print("绘图完成,已保存为 drawing_image.jpg")
动手练习:
- 修改代码: 将
image_path = "your_image.jpg"
替换成你图片的实际路径。 尝试修改各种绘图函数的参数,例如坐标、颜色、宽度、字体等,观察绘图效果的变化。 尝试绘制更多不同的图形和文字。 - 运行代码: 保存代码为
.py
文件 (例如draw_shapes_text.py
),然后在终端中运行python draw_shapes_text.py
命令。 - 查看效果: 查看生成的
drawing_image.jpg
文件,观察绘制的各种图形和文字。
案例应用:为图片添加水印,制作带有文字说明的图片
-
为图片添加水印
水印通常用于 保护图片版权,或者 标记图片来源。 水印可以是 文字 或 半透明的图像。 这里我们演示添加 半透明文字水印 的方法。
from PIL import Image, ImageDraw, ImageFont image_path = "your_image.jpg" img = Image.open(image_path).convert("RGBA") # 转换为 RGBA 模式,支持透明度 draw = ImageDraw.Draw(img, "RGBA") # Draw 对象也需要指定 "RGBA" 模式 text = "© My Watermark" # 水印文字 font_size = 48 font = ImageFont.load_default() # 或者加载 TrueType 字体 text_color = (255, 255, 255, 128) # 白色半透明 (RGBA: Red, Green, Blue, Alpha 透明度) Alpha 值 128 表示半透明 # 获取文字的宽度和高度,用于计算文字位置 text_width, text_height = draw.textsize(text, font=font) # 计算水印位置 (例如,右下角,留出一些边距) margin = 10 text_position = (img.width - text_width - margin, img.height - text_height - margin) # 绘制半透明水印文字 draw.text(text_position, text, fill=text_color, font=font) # 保存带水印的图片 img.save("watermarked_image.png") # 保存为 PNG 格式,保留透明度 print("水印添加完成,已保存为 watermarked_image.png")
代码解释:
img = Image.open(image_path).convert("RGBA")
: 将图像转换为 RGBA 模式,RGBA 模式比 RGB 模式多了一个 Alpha 通道,用于表示 透明度。 只有在 RGBA 模式下,才能实现图像的半透明效果。draw = ImageDraw.Draw(img, "RGBA")
: 创建Draw
对象时,也需要指定"RGBA"
模式,确保绘图操作支持透明度。text_color = (255, 255, 255, 128)
: 文字颜色使用 RGBA 值表示, 最后一个值 128 就是 Alpha 透明度值,取值范围 0-255,0 表示完全透明,255 表示完全不透明,128 表示半透明。draw.textsize(text, font=font)
:draw.textsize()
方法可以 获取指定文字在指定字体下的宽度和高度 (像素)。 这可以帮助我们计算文字在图像中的位置,例如居中对齐、右下角对齐等。- 保存为 PNG 格式: 为了 保留透明度效果,水印图片通常需要 保存为 PNG 格式。 JPG 格式不支持透明度。
-
制作带有文字说明的图片
我们可以结合绘图和文字,制作出带有各种文字说明的图片,例如 产品宣传图、海报、信息图 等。 下面是一个简单的例子,在图片下方添加一段文字说明。
from PIL import Image, ImageDraw, ImageFont image_path = "your_image.jpg" img = Image.open(image_path).convert("RGB") # RGB 模式即可 draw = ImageDraw.Draw(img) title_text = "Beautiful Scenery" # 图片标题 description_text = "A breathtaking view of mountains and lake at sunset." # 图片描述 font_title = ImageFont.load_default() # 标题字体 font_description = ImageFont.load_default() # 描述字体 title_color = "black" description_color = "gray" # 1. 绘制标题 (居中显示在图片上方) title_width, title_height = draw.textsize(title_text, font=font_title) title_position = ((img.width - title_width) // 2, 20) # 居中对齐,距离顶部 20 像素 draw.text(title_position, title_text, fill=title_color, font=font_title) # 2. 绘制描述文字 (居中显示在图片下方) description_width, description_height = draw.textsize(description_text, font=font_description) description_position = ((img.width - description_width) // 2, img.height - description_height - 20 - 50) # 居中对齐,距离底部 20 + 50 像素 draw.text(description_position, description_text, fill=description_color, font=font_description) # 3. 可以添加一些简单的装饰线条,例如在标题和图片之间、图片和描述文字之间 line_y_top = title_position[1] + title_height + 10 # 标题下方 10 像素 line_y_bottom = description_position[1] - 10 # 描述文字上方 10 像素 draw.line([(50, line_y_top), (img.width - 50, line_y_top)], fill="lightgray", width=1) # 上方线条 draw.line([(50, line_y_bottom), (img.width - 50, line_y_bottom)], fill="lightgray", width=1) # 下方线条 # 保存带文字说明的图片 img.save("image_with_text_description.jpg") print("带文字说明的图片制作完成,已保存为 image_with_text_description.jpg")
代码解释:
- 文字排版: 通过
draw.textsize()
方法获取文字尺寸,并结合图像尺寸,可以实现文字的 居中对齐、边缘对齐 等排版效果。 可以根据实际需求调整文字位置和间距。 - 装饰线条: 使用
draw.line()
函数可以添加简单的装饰线条,例如分隔线、边框线等,增强图片的视觉效果。
- 文字排版: 通过
费曼回顾 (知识巩固):
请你用自己的话,总结一下今天我们学习的图像绘图和文字添加的知识,包括:
ImageDraw
模块的作用是什么? 如何创建Draw
对象?- 我们学习了哪些基本图形的绘制函数? 它们分别有什么参数?
- 如何使用
draw.text()
函数添加文字?font
参数有什么作用? 如何加载字体文件? - 在水印添加和文字说明图片制作的案例中,我们是如何运用绘图和文字技巧的? RGBA 模式和透明度有什么作用?
draw.textsize()
方法有什么用途?
像给你的朋友讲解一样,用最简单的语言解释这些概念,并结合代码示例和实际操作,帮助他们理解图像绘图和文字的乐趣。
课后思考 (拓展延伸):
- 尝试使用不同的字体文件,以及调整字体大小、颜色,看看文字效果的变化。
- 尝试绘制更复杂的图形,例如曲线、箭头、图标等。 (PIL 库还提供了一些更高级的绘图函数,例如
draw.arc()
,draw.chord()
,draw.pieslice()
等,可以查阅 PIL 官方文档了解更多) - 尝试将绘图和文字技巧与其他图像处理技巧结合起来,例如图像缩放、裁剪、颜色调整等,创造更丰富的图像效果。
- 思考一下,图像绘图和文字添加还可以应用在哪些场景中? 例如,社交媒体图片制作、电子贺卡设计、信息可视化等等。 你有什么有趣的创意想法吗?
恭喜你!完成了 PIL 库的第四篇文章学习! 你已经掌握了图像绘图和文字的 “画笔”,可以开始在图像上自由创作,让你的图像作品充满创意和个性了! 下一篇文章,我们将学习如何给图像添加各种 “滤镜” 和进行图像增强,让你的图像更 “出色”,更有 “味道”! 敬请期待!