Python 实现图片压缩并转换为 WebP 格式
6/19/25About 8 min
在现代 Web 开发中,图片优化是提升网站加载速度和用户体验的关键一环。WebP 格式因其出色的压缩效率和良好的图像质量,正逐渐成为主流的图片格式。本文将介绍如何使用 Python 配合 Pillow 库,实现图片的批量压缩、添加水印,并最终转换为 WebP 格式。
核心功能概览
我们将基于一个 Python 脚本 imgtools.py
来展开,该脚本主要包含以下功能:
- 添加文字水印:在图片上叠加自定义的文字水印,支持描边效果以增强可读性。
- 图片格式转换与压缩:将常见的图片格式(如 JPG, PNG, BMP)转换为 WebP 格式,并控制压缩质量。
- 批量处理:支持处理指定目录下的所有符合条件的图片。
关键库:Pillow
Pillow 是 Python Imaging Library (PIL) 的一个友好分支,它为 Python 提供了强大的图像处理能力。在我们的脚本中,Pillow 用于打开、操作和保存图片。
from PIL import Image, ImageDraw, ImageFont
1. 添加文字水印
在分享图片前,添加水印是一种常见的版权保护或品牌宣传手段。add_watermark
函数实现了这一功能。
def add_watermark(
image: Image.Image,
watermark_text: str,
font_path: str,
font_size: int,
font_color: Tuple[int, int, int, int],
stroke_color: Tuple[int, int, int, int],
stroke_width: int = 1,
margin: int = 10
) -> Image.Image:
"""
在图片上添加带描边的文字水印。
Args:
image (Image.Image): Pillow Image 对象 (需要是 RGBA 模式).
watermark_text (str): 水印文字内容.
font_path (str): 字体文件的路径.
font_size (int): 字体大小.
font_color (Tuple[int, int, int, int]): 文字颜色 (R, G, B, Alpha).
stroke_color (Tuple[int, int, int, int]): 文字描边颜色 (R, G, B, Alpha).
stroke_width (int): 描边宽度.
margin (int): 水印距离图片边缘的距离.
Returns:
Image.Image: 添加了水印的 Pillow Image 对象.
"""
# 创建一个与原图大小相同的透明水印层
watermark_layer = Image.new("RGBA", image.size, (0, 0, 0, 0))
draw = ImageDraw.Draw(watermark_layer)
# 加载字体
try:
font = ImageFont.truetype(font_path, font_size)
except IOError:
print(f"警告: 字体 '{font_path}' 未找到, 将使用默认字体。")
font = ImageFont.load_default()
# 计算水印文字的尺寸
bbox = draw.textbbox((0, 0), watermark_text, font=font)
text_width = bbox[2] - bbox[0]
text_height = bbox[3] - bbox[1]
# 计算水印位置 (右下角)
x = image.width - text_width - margin
y = image.height - text_height - margin
# 绘制描边
if stroke_width > 0 and stroke_color:
for i in range(-stroke_width, stroke_width + 1):
for j in range(-stroke_width, stroke_width + 1):
if i != 0 or j != 0: # 避免在中心点重复绘制
draw.text((x + i, y + j), watermark_text, font=font, fill=stroke_color)
# 绘制文字本体
draw.text((x, y), watermark_text, font=font, fill=font_color)
# 将水印层合并到原图上
return Image.alpha_composite(image, watermark_layer)
主要步骤:
- 创建一个与原图等大的透明图层 (
watermark_layer
) 用于绘制水印。 - 加载指定字体和大小。如果字体加载失败,则使用 Pillow 的默认字体。
- 计算水印文本的宽度和高度,以确定其在图片右下角的位置(可根据需求调整位置计算逻辑)。
- 描边效果:通过在文字主体周围的多个偏移位置绘制描边颜色的文本,实现描边效果,增强水印在不同背景下的可见性。
- 绘制文字主体。
- 使用
Image.alpha_composite
将带有透明度的水印层叠加到原始图片上(原图需转换为 "RGBA" 模式)。
2. 处理单张图片:添加水印、转换与保存
process_image_and_save
函数负责处理单张图片,包括打开图片、添加水印、转换为 WebP 格式并保存。
def process_image_and_save(
input_path: str,
output_path: str,
watermark_text: str,
font_path: str,
font_color: Tuple[int, int, int, int],
stroke_color: Tuple[int, int, int, int],
quality: int = 80
):
"""
打开图片、添加水印、转换为WebP格式并保存。
"""
try:
# 打开原图并转换为RGBA模式以支持透明度
with Image.open(input_path).convert("RGBA") as base_image:
width, height = base_image.size
# 动态计算字体大小
font_size = int(min(width, height) * 0.04)
# 添加水印
watermarked_image = add_watermark(
image=base_image,
watermark_text=watermark_text,
font_path=font_path,
font_size=font_size,
font_color=font_color,
stroke_color=stroke_color
)
# 转换回RGB模式以便保存为WebP
final_image = watermarked_image.convert("RGB")
# 保存为WebP
final_image.save(output_path, "webp", quality=quality, method=6)
print(f"处理完成: {os.path.basename(input_path)} -> {os.path.basename(output_path)}")
except Exception as e:
print(f"处理失败: {os.path.basename(input_path)}, 错误: {e}")
核心流程:
- 打开图片:使用
Image.open(input_path)
打开图片,并通过.convert("RGBA")
确保图片是 RGBA 模式,以便正确处理透明度(特别是水印的透明度)。 - 动态字体大小:根据图片尺寸(宽度和高度的较小值)动态计算水印字体大小,使其在不同尺寸的图片上保持相对一致的视觉效果。
- 添加水印:调用前面介绍的
add_watermark
函数。 - 转换回 RGB:WebP 格式虽然支持透明度,但如果最终目的是减小文件大小且不需要透明背景,或者为了更广泛的兼容性,可以转换回 "RGB" 模式。如果需要保留透明度,则应在 RGBA 模式下直接保存。
- 保存为 WebP:使用
final_image.save(output_path, "webp", quality=quality, method=6)
保存。"webp"
: 指定保存格式。quality
: 控制 WebP 的压缩质量,范围 0-100,值越高质量越好但文件越大。脚本中默认为 80。method
: WebP 的编码方法,范围 0-6。值越大,编码速度越慢,但压缩效果可能更好。method=6
是最慢但压缩率最高的选项。
3. 批量处理图片
对于大量图片,手动逐个处理显然不现实。batch_process_images
函数实现了批量处理的逻辑。
def batch_process_images(
input_dir: str,
output_dir: str,
watermark_text: str,
font_path: str,
font_color: Tuple[int, int, int, int],
stroke_color: Tuple[int, int, int, int],
quality: int = 80,
exts: Tuple[str, ...] = ('.jpg', '.jpeg', '.png', '.bmp')
):
"""
批量处理指定目录中的所有图片。
"""
if not os.path.exists(output_dir):
os.makedirs(output_dir)
print(f"创建输出目录: {output_dir}")
for filename in os.listdir(input_dir):
if filename.lower().endswith(exts): # 检查文件扩展名
input_path = os.path.join(input_dir, filename)
name, _ = os.path.splitext(filename)
output_path = os.path.join(output_dir, name + ".webp") # 输出文件名为 .webp
process_image_and_save(
input_path=input_path,
output_path=output_path,
watermark_text=watermark_text,
font_path=font_path,
font_color=font_color,
stroke_color=stroke_color,
quality=quality
)
工作方式:
- 检查输出目录是否存在,如果不存在则创建。
- 遍历输入目录 (
input_dir
) 下的所有文件。 - 通过
filename.lower().endswith(exts)
检查文件是否为指定的图片类型(默认为.jpg
,.jpeg
,.png
,.bmp
)。 - 为每个符合条件的图片构建输入路径和输出路径(输出文件名后缀改为
.webp
)。 - 调用
process_image_and_save
函数处理并保存图片。
4. 如何使用
脚本提供了一个 if __name__ == "__main__":
代码块,方便直接运行和配置参数。
if __name__ == "__main__":
# --- 请在这里配置您的参数 ---
# 1. 目录设置 (建议输入和输出目录不同,以防覆盖原图)
INPUT_DIRECTORY = "/Users/workspace/src/.vuepress/public/test" # 输入图片目录
OUTPUT_DIRECTORY = "/Users/workspace/src/.vuepress/public/test" # 输出目录
# 2. 水印内容
WATERMARK_TEXT = "[email protected]"
# 3. 字体路径 (请根据您的操作系统修改)
# macOS: "/Library/Fonts/Arial.ttf"
# Windows: "C:/Windows/Fonts/arial.ttf"
# Linux: "/usr/share/fonts/truetype/liberation/LiberationSans-Regular.ttf"
FONT_PATH = "/Library/Fonts/Arial Unicode.ttf"
# 4. 颜色配置 (R, G, B, Alpha),Alpha值范围 0-255,0为完全透明,255为不透明
FONT_COLOR = (255, 255, 255, 180) # 白色半透明文字
STROKE_COLOR = (0, 0, 0, 180) # 黑色半透明描边
# 5. WebP 压缩质量 (0-100,推荐 75-85)
WEBP_QUALITY = 80
# --- 配置结束 ---
# 执行批量处理
batch_process_images(
input_dir=INPUT_DIRECTORY,
output_dir=OUTPUT_DIRECTORY,
watermark_text=WATERMARK_TEXT,
font_path=FONT_PATH,
font_color=FONT_COLOR,
stroke_color=STROKE_COLOR,
quality=WEBP_QUALITY
)
配置说明:
INPUT_DIRECTORY
: 存放原始图片的文件夹路径。OUTPUT_DIRECTORY
: 处理后图片保存的文件夹路径。强烈建议设置与输入目录不同的路径,以避免意外覆盖原始图片。WATERMARK_TEXT
: 要添加的水印文字。FONT_PATH
: 水印文字所用字体文件的完整路径。脚本中提供了常见操作系统下的示例路径。FONT_COLOR
: 水印文字颜色,格式为(R, G, B, Alpha)
。Alpha 值控制透明度。STROKE_COLOR
: 水印文字描边颜色,格式同上。WEBP_QUALITY
: WebP 图片的压缩质量。
修改这些参数后,直接运行此 Python 脚本即可开始批量处理图片。
总结
通过 Python 和 Pillow 库,我们可以方便地实现图片的自动化处理流程,包括添加水印、格式转换和压缩。将图片转换为 WebP 格式不仅能有效减小文件体积,还能在保证良好视觉效果的前提下,加快网站加载速度,提升用户体验。这对于拥有大量图片内容的网站来说尤其重要。