假设你有一项无聊的工作,要调整数千张图片的大小,并在每张图片的角上增
加一个小徽标水印。使用基本的图形程序,如Paintbrush 或Paint,完成这项工作需要很长时间。像 Photoshop
这样神奇的应用程序可以批量处理,但这个软件要花几百美元。让我们写一个脚本来完成工作。
假定图 17-11 是要添加到每个图像右下角的标识:带有白色边框的黑猫图标,图像的其余部分是透明的。
总的来说,程序应该完成下面的事:
• 载入徽标图像。
• 循环遍历工作目标中的所有.png 和.jpg 文件。
• 检查图片是否宽于或高于 300 像素。
• 如果是,将宽度或高度中较大的一个减小为 300 像素,并按比例缩小的另一维度。
• 在角上粘贴徽标图像。
• 将改变的图像存入另一个文件夹。
这意味着代码需要做到以下几点:
• 打开catlogo.png 文件作为 Image 对象。
• 循环遍历 os.listdir('.')返回的字符串。
• 通过 size 属性取得图像的宽度和高度。
• 计算调整后图像的新高度和宽度。
• 调用 resize()方法来调整图像大小。
• 调用 paste()方法来粘贴徽标。
• 调用 save()方法保存更改,使用原来的文件名。
第 1 步:打开徽标图像
针对这个项目,打开一个新的文件编辑器窗口,输入以下代码,并保存为
resizeAndAddLogo.py:
#! python3
# resizeAndAddLogo.py - Resizes all images in current working directory to fit # in a
300x300 square, and adds catlogo.png to the lower-right corner.
import os
from PIL import Image
➊ SQUARE_FIT_SIZE = 300
➋ LOGO_FILENAME = 'catlogo.png'
➌ logoIm = Image.open(LOGO_FILENAME)
➍ logoWidth, logoHeight = logoIm.size
# TODO: Loop over all files in the working directory. # TODO: Check if image needs
to be resized.
# TODO: Calculate the new width and height to resize to. # TODO: Resize the image.
# TODO: Add the logo. # TODO: Save changes.
在程序开始时设置 SQUARE_FIT_SIZE➊和 LOGO_FILENAME➋常量,这让程
序以后更容易修改。假定你要添加的徽标不是猫图标,或者假定将输出图像的最大大小要减少的值不是 300
像素。有了程序开始时定义的这些常量,你可以打开代码,修改一下这些值,就大功告成了(或者你可以让这些常量的值从命令行参数获得)。没有这些常数,就要在代码中寻找所有的 300
和'catlogo.png',将它们替换新项目的值。总之,使用常量使程序更加通用。
徽标 Image 对象从 Image.open()返回➌。为了增强可读性,logoWidth 和logoHeight
被赋予 logoIm.size 中的值➍。
该程序的其余部分目前是 TODO 注释,说明了程序的骨架。
第 2 步:遍历所有文件并打开图像
现在,需要找到当前工作目录中的每个 PNG 文件和.jpg 文件。请注意,你不希望将徽标图像添加到徽标图像本身,所以程序应该跳过所有像
LOGO_FILENAME这样的图像文件名。在程序中添加以下代码:
#! python3
# resizeAndAddLogo.py - Resizes all images in current working directory to fit # in a
300x300 square, and adds catlogo.png to the lower-right corner.
import os
from PIL import Image
--snip--
os.makedirs('withLogo', exist_ok=True)
# Loop over all files in the working directory.
➊ for filename in os.listdir('.'):
➋ if not (filename.endswith('.png') or filename.endswith('.jpg')) \ or
filename == LOGO_FILENAME:
➌ continue # skip non-image files and the logo file
itself
➍ im = Image.open(filename) width, height = im.size
--snip--
首先,os.makedirs()调用创建了一个文件夹 withLogo,用于保存完成的、带有徽标的图像,而不是覆盖原始图像文件。关键字参数 exist_ok=True 将防止
os.makedirs()在 withLogo 已存在时抛出异常。在用 os.listdir('.')遍历工作目录中的所有文件时➊,较长的 if
语句➋检查每个 filename 是否以.png 或.jpg 结束。如果不是,或者该文件是徽标图像本身,循环就跳过它,使用
continue➌去处理下一个文件。如果 filename确实以'.png'或'.jpg'结束(而且不是徽标文件),可以将它打开为一个 Image
对象➍,并设置 width 和 height。
第 3 步:调整图像的大小
只在有宽或高超过 SQUARE_FIT_SIZE 时(在这个例子中,是 300 像素),该程序才应该调整图像的大小,所以将所有大小调整的代码放在一个检查 width 和 height 变量的 if
语句内。在程序中添加以下代码:
#! python3
# resizeAndAddLogo.py - Resizes all images in current working directory to fit # in a
300x300 square, and adds catlogo.png to the lower-right corner.
import os
from PIL import Image
--snip--
# Check if image needs to be resized.
if width > SQUARE_FIT_SIZE and height > SQUARE_FIT_SIZE: # Calculate the new width and
height to resize to. if width > height:
➊ height = int((SQUARE_FIT_SIZE / width) * height)
width = SQUARE_FIT_SIZE
else:
➋ width = int((SQUARE_FIT_SIZE / height) * width)
height = SQUARE_FIT_SIZE
# Resize the image.
print('Resizing %s...' % (filename))
➌ im = im.resize((width, height))
--snip--
如果图像确实需要调整大小,就需要弄清楚它是太宽还是太高。如果 width 大于 height,则高度应该根据宽度同比例减小➊。这个比例是当前宽度除以 SQUARE_
FIT_SIZE 的值。新的高度值是这个比例乘以当前高度值。由于除法运算符返回一个浮点值,而 resize()要求的尺寸是整数,所以要记得将结果用 int()函数转换成整数。最后,新的 width
值就设置为 SQUARE_FIT_SIZE。
如果 height 大于或等于 width(这两种情况都在 else 子句中处理),那么进行同样的计算,只是交换 height 和 width 变量的位置➋。
在width 和 height 包含新图像尺寸后,将它们传入 resize()方法,并返回的 Image
对象保存在 im 中➌。
图 17-12 在右下角放置徽标的左坐标和顶坐标,应该是图像的宽度/高度减去徽标宽度/高度
代码将徽标粘贴到图像中后,应保存修改后的Image 对象。将以下代码添加到程序中:
#! python3
# resizeAndAddLogo.py - Resizes all images in current working directory to fit
# in a 300x300 square, and adds catlogo.png to the lower-right corner.
import os
from PIL import Image
--snip--
# Check if image needs to be resized.
--snip--
# Add the logo.
➊ print('Adding logo to %s...' % (filename))
➋ im.paste(logoIm, (width - logoWidth, height - logoHeight), logoIm)
# Save changes.
➌ im.save(os.path.join('withLogo', filename))
新的代码输出一条消息,告诉用户徽标已被加入➊,将 logoIm 粘贴到 im 中计算的坐标处➋,并将变更保存到 withLogo 目录的
filename 中➌。如果运行这个程序, zophie.png 文件是工作目录中唯一的图像,输出会是这样:
Resizing zophie.png... Adding logo to zophie.png...
图像 zophie.png 将变成 225×300 像素的图像,如图 17-13 所示。请记住,如果没有传入 logoIm
作为第三个参数,paste()方法不会粘贴透明的像素。这个程序可以在短短几分钟内自动调整几百幅图像,并“加上徽标”。
第 4 步:添加徽标,并保存更改
不论图像是否调整大小,徽标仍应粘贴到右下角。徽标粘贴的确切位置取决于图像的大小和徽标的大小。图 17-12
展示了如何计算粘贴的位置。粘贴徽标的左坐标将是图像宽度减去徽标宽度,顶坐标将是图像高度减去徽标高度。
第 5 步:类似程序的想法
能够批量合成图像或修改图像大小,在许多应用中都有用。可以编写类似的程序,完成以下任务:
• 为图像添加文字或网站 URL。
• 为图像添加时间戳。
• 根据图像的大小,将图像复制或移动到不同的文件夹中。
• 为图像添加一个几乎透明的水印,防止他人复制。