Python怎么用Pillow读取图片文件
详细讲解在Python中使用Pillow库读取图片文件的方法与操作步骤,涵盖Image.open基础用法、图像属性获取、惰性加载机制、内存流读取及常见异常排查。
一、环境准备与模块导入
在编写代码前,需要确保当前 Python 环境已安装 Pillow。Pillow 是早已停止维护的经典 Python Imaging Library(PIL)的现代活跃分支,兼容常见的 JPEG、PNG、WebP、BMP、TIFF 等主流图片格式。
1. 安装 Pillow
打开终端或命令行,执行如下 pip 安装指令:
pip install Pillow
这里的包名是 Pillow。安装过程会自动包含对应操作系统平台的预编译 C 扩展与图像解码动态库。
2. 导入核心类 Image
编写 Python 脚本时,必须注意:导入的命名空间为 PIL(大写),而不是小写的 pillow。Pillow 保持了与早期 PIL 相同的顶层包名设计。
# 正确导入方式
from PIL import Image
# 常见错误:请勿写成 import pillow 或 import Image
二、核心方法:使用 Image.open() 打开图片
读取图片文件的核心函数是 Image.open()。该函数接收一个文件路径字符串(或 pathlib.Path 对象、亦或二进制文件对象),返回一个 PIL.Image.Image 实例。
1. 标准推荐写法:使用 with 语句
因为读取图片涉及底层操作系统文件句柄,强烈建议配合 with 语句使用上下文管理:
from PIL import Image
with Image.open("example.jpg") as img:
# 打印图像基本属性
print("图片格式 (format):", img.format)
print("图片尺寸 (size):", img.size)
print("色彩模式 (mode):", img.mode)
# 弹出系统默认看图工具预览
img.show()
图片格式 (format): JPEG
图片尺寸 (size): (1920, 1080)
色彩模式 (mode): RGB
2. 核心属性说明
img.format:图像编码格式,例如'JPEG'、'PNG'、'GIF'。若图片由内存生成而非从文件打开,该属性值可能为None。img.size:包含两个整数的二元元组(width, height),单位为像素。注意宽度在前,高度在后。img.mode:图像的色彩通道模式,常见有'RGB'(24位真彩色)、'RGBA'(带透明度)、'L'(8位灰度图)等。img.show():主要用于开发调试。该方法会将图片写入系统临时文件,并调用系统内置图片查看器快速弹出窗口展示。
三、深度解析:惰性加载(Lazy Loading)与生命周期
理解 Pillow 的读取机制,关键在于认识到 Image.open() 是一种惰性加载(Lazy Operation)。
当执行 img = Image.open("huge_photo.jpg") 时,Pillow 实际上并没有把整张图片的所有像素数据解压到内存中,而仅仅是读取了文件开头的几十或上百个字节(Header)。通过解析文件头,Pillow 就能获知图像格式、宽高及色彩模式。因此,无论图片体积是几百 KB 还是几十 MB,open() 都能在毫秒级内完成。
为什么必须注意文件句柄与 img.load()?
正因为像素数据没有立刻载入,图像对象在底层仍然持续持有对磁盘文件的引用句柄。只有当后续调用如 img.show()、img.crop()、img.save(),或者主动调用 img.load() 时,Pillow 才会真正启动解码器,解压整张图片的像素矩阵。
with Image.open(...) as img:,在跳出 with 代码块的瞬间,文件句柄就会被强制关闭。如果在退出 with 之后再去访问像素,可能会抛出 ValueError: seek of closed file。解决办法:如果需要在退出上下文后继续操作图像,请在退出前执行
img.load(),强制将像素完全载入内存:
from PIL import Image
with Image.open("example.png") as file_img:
file_img.load() # 强制解码全部像素至内存
img = file_img.copy()
# 离开 with 块后,文件句柄已释放,但 img 依然可以在内存中自由处理
print(img.size)
四、进阶场景:内存流读取与多帧动图处理
实际项目中,除了读取本地磁盘路径外,经常遇到从网络 API 获取图片数据,或者读取 GIF 动图等场景。
1. 从内存二进制流(BytesIO)中读取
当使用 requests 或 urllib 从网络下载图片后,不需要先存为本地临时文件,可以直接使用 Python 标准库的 io.BytesIO 包装字节流后交给 Pillow:
import io
import urllib.request
from PIL import Image
url = "https://example.com/sample.jpg"
with urllib.request.urlopen(url) as response:
image_bytes = response.read()
# 使用 io.BytesIO 将 bytes 转化为内存文件对象
with Image.open(io.BytesIO(image_bytes)) as img:
print("从网络流读取成功:", img.size, img.format)
2. 读取多帧图像(GIF / TIFF)
对于包含多帧画面的动图或多页文档,Pillow 提供了 n_frames 属性和 seek() 方法实现逐帧遍历:
from PIL import Image
with Image.open("animation.gif") as img:
total_frames = getattr(img, "n_frames", 1)
print(f"动图总帧数: {total_frames}")
for frame_idx in range(total_frames):
img.seek(frame_idx) # 定位到对应帧
print(f"当前帧: {img.tell()}, 尺寸: {img.size}")
3. 色彩模式转换注意点
如果读取的是带 Alpha 透明通道的 PNG 图片(模式为 RGBA),当需要将其另存为 JPEG 格式时,必须先进行模式转换。因为 JPEG 格式不支持透明通道,直接保存会抛出 OSError: cannot write mode RGBA as JPEG:
with Image.open("transparent_logo.png") as img:
if img.mode in ("RGBA", "P"):
# 转换为 RGB 格式,去除透明通道
rgb_img = img.convert("RGB")
rgb_img.save("logo.jpg", "JPEG")
五、常见报错与排查诊断
在使用 Image.open() 读取图片过程中,最常遇到的三类异常及排查方法如下:
| 异常类型 | 常见诱发原因 | 推荐应对方案 |
|---|---|---|
FileNotFoundError |
相对路径与当前终端工作目录不一致;Windows 系统下反斜杠转义混淆。 | 使用 pathlib.Path(__file__).parent 构建基准绝对路径;路径字符串前加 r""。 |
UnidentifiedImageError |
文件虽有 .jpg 后缀但实际为损坏文件、HTML 错误页或空文件。 |
使用 try...except UnidentifiedImageError 捕获;校验文件前几个字节(Magic Number)。 |
DecompressionBombError |
图片像素过大(默认超过约 8947 万像素),触发防解压炸弹保护。 | 确认图片可信后,设置 Image.MAX_IMAGE_PIXELS = None 允许读取特大图像。 |
路径排查实操建议
避免硬编码相对路径 "pic.jpg"。推荐统一使用现代标准的 pathlib 库定位脚本同级目录下的资源文件:
from pathlib import Path
from PIL import Image
# 获取当前脚本所在目录
base_dir = Path(__file__).resolve().parent
image_path = base_dir / "assets" / "demo.jpg"
if image_path.exists():
with Image.open(image_path) as img:
print("成功加载:", img.size)
else:
print("文件未找到:", image_path)
六、总结速查表
掌握 Pillow 读取图片文件,核心要点可归结为以下清单:
- 安装与导入:安装执行
pip install Pillow,代码导入写from PIL import Image。 - 基础调用:优先使用
with Image.open(path) as img:上下文管理器,自动管理底层文件生命周期。 - 属性获取:通过
img.size获取二元宽高元组,img.format获取文件格式,img.mode获取色彩通道。 - 性能特性:
open()采用惰性加载,仅解析文件头;脱离上下文前若需继续处理像素,需先执行img.load()。 - 格式兼容:PNG 转存 JPEG 需先调用
img.convert('RGB'),内存数据流可通过io.BytesIO无缝加载。
本站声明
本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。













