Pillow中的文件处理¶
以图像形式打开文件时, Pillow 需要文件名, pathlib.Path
对象,或类似文件的对象。 Pillow 使用文件名或 Path
要打开一个文件,所以在本文的其余部分中,它们都将被视为一个类似文件的对象。
以下都是等效的:
from PIL import Image
import io
import pathlib
with Image.open('test.jpg') as im:
...
with Image.open(pathlib.Path('test.jpg')) as im2:
...
with open('test.jpg', 'rb') as f:
im3 = Image.open(f)
...
with open('test.jpg', 'rb') as f:
im4 = Image.open(io.BytesIO(f.read()))
...
如果将文件名或类似路径的对象传递到 Pillow ,则 Pillow 打开的结果文件对象也可以在 Image.Image.load()
如果关联的图像没有多个帧,则调用方法。
Pillow一般不能关闭和重新打开文件,因此任何访问该文件需要在关闭之前。
图像生命周期¶
Image.open()
文件名和Path
对象作为文件打开。从打开的文件中读取元数据。文件保持打开状态以供进一步使用。Image.Image.load()
当需要图像中的像素数据时,load()
被称为。当前帧被读取到内存中。现在可以独立于基础图像文件使用图像。如果文件名或
Path
对象已传递给Image.open()
,然后文件对象被 Pillow 打开,被认为是 Pillow 专用的。因此,如果图像是单帧图像,则在读取帧后,该文件将在此方法中关闭。如果图像是多帧图像(如多页TIFF和动画GIF),图像文件将保持打开状态,以便Image.Image.seek()
可以加载适当的框架。Image.Image.close()
关闭文件并销毁核心图像对象。这在 Pillow 上下文管理器支持中使用。例如。::with Image.open('test.jpg') as img: ... # image operations here.
单帧图像的生命周期相对简单。文件必须保持打开状态,直到 load()
或 close()
调用函数或退出上下文管理器。
多帧图像更复杂。这个 load()
方法不是终端方法,因此不应关闭基础文件。一般来说,在调用者明确关闭图像之前, Pillow 不知道是否会有其他数据请求。
难题¶
TiffImagePlugin
有一些代码可以将底层文件描述符传递到libtiff中(如果处理的是实际文件)。由于libtiff在内部关闭文件描述符,因此在将其传递到libtiff之前,它是重复的。关闭文件后,需要访问文件的操作将失败:
with open('test.jpg', 'rb') as f: im5 = Image.open(f) im5.load() # FAILS, closed file with Image.open('test.jpg') as im6: pass im6.load() # FAILS, closed file
建议的文件处理¶
Image.Image.load()
应该关闭图像文件,除非有多个帧。Image.Image.seek()
不应关闭图像文件。库的用户应使用上下文管理器或调用
Image.Image.close()
在使用文件名或Path
对象以确保关闭基础文件。