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 ​对象以确保关闭基础文件。


以上内容是否对您有帮助:
在线笔记
App下载
App下载

扫描二维码

下载编程狮App

公众号
微信公众号

编程狮公众号