以图像形式打开文件时,枕头需要文件名, pathlib.Path
对象,或类似文件的对象。枕头使用文件名或 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()
,然后文件对象被枕头打开,被认为是枕头专用的。因此,如果图像是单帧图像,则在读取帧后,该文件将在此方法中关闭。如果图像是多帧图像(如多页TIFF和动画GIF),图像文件将保持打开状态,以便Image.Image.seek()
可以加载适当的框架。 -
Image.Image.close()
关闭文件并销毁核心图像对象。这在枕头上下文管理器支持中使用。例如。::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
对象以确保关闭基础文件。
讨论区