Python使用Pillow库修改图片尺寸的基础教程

Miles
Miles
发布时间:2026-11-12 | 4人浏览过
原创

本教程详细讲解如何使用Python的Pillow(PIL)库修改图片尺寸。涵盖Image.resize与Image.thumbnail的核心区别、等比例缩放计算、重采样滤镜选择及常见避坑指南。

在Python中批量处理或调整图片大小时,最稳定、功能最完备的工具是 Pillow(它是 Python Imaging Library 即 PIL 的现代化分支)。修改图片尺寸的核心操作主要依赖两个方法:生成新尺寸副本的 resize(),以及原地生成等比例缩略图的 thumbnail()。本文将从库的安装导入开始,系统讲解这两种方法的使用场景、等比例缩放数学计算、重采样滤镜的选取,以及日常开发中容易忽视的格式与通道避坑点。

Python使用Pillow库修改图片尺寸的基础教程
图1:Pillow 图片尺寸修改全生命周期与关键节点

准备工作:安装与读取图片

Pillow 可以在终端或命令行环境中使用 pip 直接安装:

pip install Pillow

安装完成后,在 Python 代码中通过导入 PIL 命名空间下的 Image 模块进行操作。读取本地图片并获取其元数据信息如下:

from PIL import Image

# 1. 打开指定路径下的图片文件
img = Image.open("photo.jpg")

# 2. 查看基本信息:size 返回 (宽度, 高度) 元组,单位为像素
orig_width, orig_height = img.size
print(f"原始尺寸: 宽 {orig_width}px, 高 {orig_height}px")
print(f"色彩模式: {img.mode}")   # 例如: RGB, RGBA, L 等
print(f"图片格式: {img.format}") # 例如: JPEG, PNG 等

注意,Image.open() 采用懒加载机制,调用该函数时并不会立刻将全部像素数据解压到内存中,只有在进行尺寸修改、滤镜处理或保存时才会真正解码图片。

方法一:使用 resize() 调整为指定尺寸

resize() 是最通用的缩放方法,接收一个包含 (新宽度, 新高度) 的元组作为第一个参数,并返回一个新的 Image 实例。原本的图像对象保持不变。

1. 直接指定固定宽高(强制拉伸)

如果直接传入固定的长宽尺寸,当目标宽高比与原图不一致时,画面会被拉伸或压缩导致失真:

# 强制将图片尺寸修改为 400x300(若原图不是4:3比例,图像会发生形变)
resized_img = img.resize((400, 300))
resized_img.save("output_fixed.jpg")

2. 保持宽高比的手动计算缩放

在日常业务场景中,绝大多数情况下需要保持图片比例。我们可以根据目标宽度(或目标高度)推算对应维度的像素值:

# 设定目标宽度为 600px,高度自动按比例等比缩放
target_width = 600
orig_w, orig_h = img.size

# 计算缩放比例并确定目标高度
scale = target_width / orig_w
target_height = int(orig_h * scale)

# 使用等比尺寸生成新图
proportional_img = img.resize((target_width, target_height))
proportional_img.save("output_proportional.jpg")
print(f"调整后尺寸: {proportional_img.size}")
Python使用Pillow库修改图片尺寸的基础教程
图2:resize 与 thumbnail 对图像宽高比和原图对象的处理区别

方法二:使用 thumbnail() 制作等比例缩略图

如果你只需要将一张高清大图缩小为指定边界内的缩略图,并不希望自行编写数学公式推算长宽,thumbnail() 是更优雅便捷的选择。

thumbnail() 接收一个 (最大宽度, 最大高度) 的元组。它的执行逻辑是:在保证图片宽高比不改变的前提下,将图片等比例缩小至完全容纳在给定的宽高矩形框内。更重要的是,该方法属于原地修改(In-place),直接改变当前对象自身,函数返回值为 None。

# 将图片约束在 800x800 的矩形框内
# 原图若为 1920x1080 (16:9),处理后实际变为 800x450
img.thumbnail((800, 800))

# 注意:切勿写成 img = img.thumbnail(...),否则 img 将变成 None
img.save("output_thumb.jpg")
print(f"缩略图最终尺寸: {img.size}")
thumbnail() 与 resize() 的关键对比:
  • 返回值差异: resize() 返回处理后的新 Image 副本,原图对象保持不变;而 thumbnail() 原地改变原对象,返回值恒为 None。
  • 比例保护机制: resize() 严格按照传入尺寸拉伸;thumbnail() 自动维持原纵横比,绝不变形。
  • 尺寸放大处理: resize() 既可以放大也可以缩小;而 thumbnail() 默认只执行缩小操作,如果传入的尺寸大于原图尺寸,图片尺寸将保持原样不变。

重采样滤波器(Resampling Filter)的原理与选用

无论放大还是缩小图片,其本质都是重新计算像素矩阵中的颜色取值。如果直接丢弃或复制像素,容易造成严重的锯齿或噪点。Pillow 提供了多种重采样滤镜(Resampling Filter),通过 resample 参数进行配置。

在 Pillow 9.0.0 及以上版本中,建议使用现代枚举语法 Image.Resampling.<FILTER>(兼容旧版中形如 Image.LANCZOS 的常量):

# 使用最高品质的 LANCZOS 滤镜进行重采样缩放
high_quality_img = img.resize(
    (target_width, target_height), 
    resample=Image.Resampling.LANCZOS
)
算法常量 运算速度 成像素质 核心原理与典型适用场景
Resampling.NEAREST 极快 低(有锯齿) 最近邻插值,直接复制最近的单个像素。适合像素画(Pixel Art)或需要保留绝对锐利硬边缘的二值化遮罩。
Resampling.BILINEAR 快 中等 双线性插值,基于周围 2×2 像素进行线性加权。适合对处理性能敏感的中等缩放场景。
Resampling.BICUBIC 中等 良好 双三次插值,基于周围 4×4 像素进行三次多项式平滑。常用于照片的平滑放大。
Resampling.LANCZOS 稍慢 极高 基于 Sinc 函数的高阶滤波算法,在保留细微边缘锐利度的同时抑制混叠。常规图片缩小的首选算法。
Python使用Pillow库修改图片尺寸的基础教程
图3:Pillow 四大重采样滤波器的插值原理与综合指标对比

常见问题与避坑指南

1. RGBA 透明通道保存为 JPEG 格式报错

如果原始图片是带有透明通道的 PNG 格式(其 mode 为 "RGBA"),直接缩放后保存为 .jpg 文件会抛出如下经典异常:

OSError: cannot write mode RGBA as JPEG

原因与解决方案: JPEG 格式标准本身不支持 Alpha 透明通道。在保存为 JPEG 之前,必须先将色彩空间转换成 RGB 模式。如果直接调用 convert('RGB'),透明区域可能会默认变成纯黑色。推荐新建白色背景图层进行粘贴合并:

def safe_convert_to_rgb(image):
    if image.mode in ("RGBA", "LA") or (image.mode == "P" and "transparency" in image.info):
        # 创建同等尺寸的纯白色 RGB 背景
        background = Image.new("RGB", image.size, (255, 255, 255))
        # 使用原图的 Alpha 通道作为遮罩粘贴
        background.paste(image, mask=image.split()[3])
        return background
    return image.convert("RGB")

2. 手机拍摄照片缩放后发生“倒立”或“横置”

智能手机在拍照时通常不会真正物理旋转传感器捕获的图像,而是将手机朝向信息记录在图片文件的 EXIF 元数据中。Pillow 打开图片时默认不会自动执行 EXIF 旋转修正。使用 ImageOps.exif_transpose() 可以在缩放前自动恢复正确的视觉方向:

from PIL import ImageOps

# 依据 EXIF 标签自动转正图片,避免修改尺寸后方向错乱
img = ImageOps.exif_transpose(img)

3. thumbnail() 原地修改误赋值为 None

许多初学者习惯了 s = s.strip() 这种函数式赋值风格,误写为 img = img.thumbnail(...)。因为 thumbnail 是原地修改且返回 None,这会导致 img 变成空对象,紧接着执行 img.save() 时触发 AttributeError: 'NoneType' object has no attribute 'save'。

Python使用Pillow库修改图片尺寸的基础教程
图4:Pillow 尺寸修改常见避坑点与防御性代码处理逻辑

实用综合示例:构建通用的图片尺寸调整函数

将上述所有知识点(EXIF 方向校正、等比计算、透明通道保底兼容、高质量 Lanczos 重采样)整合为一个可以直接在实际项目中复用的通用函数:

import os
from PIL import Image, ImageOps

def resize_image_properly(input_path, output_path, max_width=800, quality=85):
    """
    读取图片并将其等比例缩放至不超过 max_width,支持全格式兼容。
    """
    if not os.path.exists(input_path):
        raise FileNotFoundError(f"输入文件未找到: {input_path}")

    # 1. 打开图片并自动校正拍摄朝向
    with Image.open(input_path) as im:
        im = ImageOps.exif_transpose(im)
        orig_w, orig_h = im.size

        # 2. 如果宽度已小于等于限制,无需放大(保留原尺寸)
        if orig_w <= max_width:
            target_w, target_h = orig_w, orig_h
        else:
            target_w = max_width
            target_h = int(orig_h * (max_width / orig_w))

        # 3. 使用 LANCZOS 高质量算法重采样
        resized_im = im.resize((target_w, target_h), resample=Image.Resampling.LANCZOS)

        # 4. 判断目标格式兼容性(若存为 JPEG 则处理 Alpha 通道)
        ext = os.path.splitext(output_path)[1].lower()
        if ext in [".jpg", ".jpeg"]:
            if resized_im.mode in ("RGBA", "LA"):
                bg = Image.new("RGB", resized_im.size, (255, 255, 255))
                bg.paste(resized_im, mask=resized_im.split()[-1])
                resized_im = bg
            elif resized_im.mode != "RGB":
                resized_im = resized_im.convert("RGB")
            
            resized_im.save(output_path, "JPEG", quality=quality, optimize=True)
        else:
            # PNG 或 WebP 等格式可直接保存
            resized_im.save(output_path, optimize=True)

    print(f"处理完成: {output_path} ({target_w}x{target_h})")

# 示例调用
# resize_image_properly("avatar.png", "avatar_small.jpg", max_width=500)
Python使用Pillow库修改图片尺寸的基础教程
图5:Pillow 修改图片尺寸核心方法与选型决策对比表

结语

在 Python 中修改图片尺寸是一项基础而高频的任务。掌握 resize() 的副本生成机制与 thumbnail() 的就地修改逻辑,结合 Resampling.LANCZOS 重采样滤镜,能够确保图片在缩放过程中保持细腻清晰的质感。同时,在生产环境中务必注意通过 exif_transpose() 纠正拍摄姿态,以及妥善处理 RGBA 透明通道与 JPEG 格式之间的转换兼容,写出稳健可靠的图像批处理脚本。

本站声明

本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。

Python 相关产品和应用

全部下载

专题列表