Pillow中的文件处理
2021-07-19 11:17 更新
以图像形式打开文件时,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,则在Image.Image.load()
调用该方法后,Pillow 打开的结果文件对象也可能被 Pillow 关闭 ,前提是关联的图像没有多帧。
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
对象以确保关闭基础文件。
以上内容是否对您有帮助:
更多建议: