Pillow使用了一个插件模型,允许你将自己的解码器添加到库中,而无需对库本身进行任何更改。这样的插件通常有这样的名字 XxxImagePlugin.py
在哪里 Xxx
是唯一的格式名(通常是缩写)。
警告
Pillow >=2.1.0不再自动导入python路径中名称以 ImagePlugin.py
. 您需要手动导入图像插件。
Pillow分两个阶段解码文件:
-
它以加载的顺序循环访问可用的图像插件,并调用插件的
_accept
函数的前16个字节。如果_accept
函数返回true,插件的_open
方法来设置图像元数据和图像分片。这个_open
方法不用于解码实际图像数据。 -
当请求图像数据时,
ImageFile.load
方法,它为每个图块设置一个解码器并将数据提供给它。
插件应包含从图像处理程序派生的格式 PIL.ImageFile.ImageFile
基类。此类应提供 _open
方法,它读取文件头并至少设置 mode
和 size
属性。为了能够加载该文件,该方法还必须创建一个 tile
描述符,其中包含解码器名称、块的范围和任何特定于解码器的数据。必须通过调用 Image
模块。
注解
出于性能原因,重要的是 _open
方法快速拒绝没有适当内容的文件。
例子
下面的插件支持一个简单的格式,它有一个128字节的头,由单词“SPAM”组成,后跟宽度、高度和像素大小(以位为单位)。标题字段用空格隔开。图像数据紧跟在标题之后,可以是二级、灰度级或24位真彩色。
spamimageplugin.py版: :
from PIL import Image, ImageFile
def _accept(prefix):
return prefix[:4] == b"SPAM"
class SpamImageFile(ImageFile.ImageFile):
format = "SPAM"
format_description = "Spam raster image"
def _open(self):
header = self.fp.read(128).split()
# size in pixels (width, height)
self._size = int(header[1]), int(header[2])
# mode setting
bits = int(header[3])
if bits == 1:
self.mode = "1"
elif bits == 8:
self.mode = "L"
elif bits == 24:
self.mode = "RGB"
else:
raise SyntaxError("unknown number of bits")
# data descriptor
self.tile = [("raw", (0, 0) + self.size, 128, (self.mode, 0, 1))]
Image.register_open(SpamImageFile.format, SpamImageFile, _accept)
Image.register_extensions(SpamImageFile.format, [
".spam",
".spa", # DOS version
])
格式处理程序必须始终设置 size
和 mode
属性。如果未设置,则无法打开文件。为了简化插件,调用代码考虑异常,例如 SyntaxError
, KeyError
, IndexError
, EOFError
和 struct.error
无法识别文件。
请注意,必须使用 PIL.Image.register_open()
. 尽管不是必需的,但最好注册此格式使用的任何扩展名。
导入插件后,可以使用它:
from PIL import Image
import SpamImagePlugin
with Image.open("hopper.spam") as im:
pass
这个 tile
属性
为了能够读取该文件以及识别它, tile
还必须设置属性。这个属性包含一个平铺描述符列表,其中每个描述符指定如何将数据加载到图像中的给定区域。在大多数情况下,只使用一个描述符,覆盖整个图像。
tile描述符是一个包含以下内容的4元组:
(decoder, region, offset, parameters)
字段使用如下:
- decoder
-
指定要使用的解码器。这个
raw
这里使用的解码器支持各种像素格式的未压缩数据。有关此解码器的详细信息,请参阅下面的说明。 - region
-
一个4元组,指定在映像中存储数据的位置。
- offset
-
从文件开头到图像数据的字节偏移量。
- parameters
-
解码器的参数。此字段的内容取决于平铺描述符元组中第一个字段指定的解码器。如果解码器不需要任何参数,则使用
None
对于这个领域。
请注意 tile
属性包含一个平铺描述符列表,而不仅仅是一个描述符。
原始解码器
这个 raw
解码器用于从图像文件中读取未压缩的数据。它可以用于大多数未压缩的文件格式,如PPM、BMP、未压缩的TIFF和许多其他格式。将原始解码器与 PIL.Image.frombytes()
函数,请使用以下语法:
image = Image.frombytes(
mode, size, data, "raw",
raw mode, stride, orientation
)
在tile描述符中使用时,参数字段应如下所示:
(raw mode, stride, orientation)
字段使用如下:
- 原始模式
-
文件中使用的像素布局,用于将数据正确转换为PIL的内部布局。有关可用格式的摘要,请参阅下表。
- stride
-
图像中两个连续行之间的距离(字节)。如果为0,则假定图像是压缩的(行与行之间没有填充)。如果忽略,步幅默认为0。
- orientation
-
图像中的第一行是屏幕上的顶行(1),还是底行(-1)。如果忽略,则方向默认为1。
这个 原始模式 字段用于确定如何解包数据以匹配PIL的内部像素布局。PIL支持大量的原始模式;有关完整的列表,请参阅中的表 Unpack.c
模块。下表介绍了一些常用的 原始模式 :
模式 |
描述 |
---|---|
|
1位双层,存储时最左边的像素最多
有效位。0表示黑色,1表示白色。
|
|
1位反转的两级,与最左边的像素一起存储在
最高有效位。0表示白色,1表示黑色。
|
|
1位反转两级,与最左边的像素一起存储在
最低有效位。0表示黑色,1表示白色。
|
|
8位灰度。0表示黑色,255表示白色。 |
|
8位反转灰度。0表示白色,255表示黑色。 |
|
8位调色板映射图像。 |
|
24位真彩色,存储为(红、绿、蓝)。 |
|
24位真彩色,存储为(蓝色、绿色、红色)。 |
|
24位真彩色,存储为(红、绿、蓝、垫)。垫子
像素可能会有所不同。
|
|
24位真彩色,线条交错(首先全部为红色像素,然后
全部为绿色像素,最后为全部蓝色像素)。
|
请注意,对于最常见的情况,原始模式与模式完全相同。
python图像库支持许多其他解码器,包括jpeg、png和packbits。有关详细信息,请参见 decode.c
源文件,以及随库提供的标准插件实现。
解码浮点数据
PIL提供了一些特殊的机制,允许您将各种格式加载到一个模式中。 F
(浮点)图像存储器。
你可以使用 raw
解码器,使用以下原始模式之一读取数据打包为任何标准机器数据类型的图像:
模式 |
描述 |
---|---|
|
32位本机浮点。 |
|
8位无符号整数。 |
|
8位有符号整数。 |
|
16位小尾数无符号整数。 |
|
16位小端有符号整数。 |
|
16位大尾数无符号整数。 |
|
16位大尾数带符号整数。 |
|
16位本机无符号整数。 |
|
16位本机有符号整数。 |
|
32位小尾数无符号整数。 |
|
32位小端有符号整数。 |
|
32位大尾数无符号整数。 |
|
32位大尾数带符号整数。 |
|
32位本机无符号整数。 |
|
32位本机有符号整数。 |
|
32位小尾数浮点数。 |
|
32位大端浮点。 |
|
32位本机浮点。 |
|
64位小尾数浮点数。 |
|
64位大端浮点。 |
|
64位本机浮点。 |
位译码器
如果原始解码器无法处理您的格式,PIL还提供了一个特殊的“位”解码器,可用于将各种打包格式读取到浮点图像内存中。
将位解码器与 PIL.Image.frombytes()
函数,请使用以下语法:
image = Image.frombytes(
mode, size, data, "bit",
bits, pad, fill, sign, orientation
)
在tile描述符中使用时,参数字段应如下所示:
(bits, pad, fill, sign, orientation)
字段使用如下:
- bits
-
每像素位数(2-32)。没有默认值。
- pad
-
行间填充,以位为单位。如果没有填充,则为0;如果行被填充为完整字节,则为8。如果忽略,填充值默认为8。
- fill
-
控制如何将数据添加到解码器位缓冲区并从中存储数据。
- **填充=0 **
-
向解码器缓冲区的LSB端添加字节;从MSB端存储像素。
- **填充=1 **
-
将字节添加到解码器缓冲区的MSB端;从MSB端存储像素。
- **填充=2 **
-
向解码器缓冲区的LSB端添加字节;从LSB端存储像素。
- **填充=3 **
-
向解码器缓冲区的msb端添加字节;从lsb端存储像素。
如果忽略,则填充顺序默认为0。
- sign
-
如果非零,位字段将被符号扩展。如果为零或忽略,则位字段无符号。
- orientation
-
图像中的第一行是屏幕上的顶行(1),还是底行(-1)。如果忽略,则方向默认为1。
文件解码器的生命周期有三个阶段:
-
设置: Pillow 在解码器注册表中查找函数,返回到名为的函数
[decodername]_decoder
在内部核心图像对象上。该函数是用args
元组从tile
设置在_open
方法。 -
解码:解码器的解码功能通过图像数据块重复调用。
-
清除:如果解码器注册了清除函数,则在解码过程结束时将调用该函数,即使出现异常。
安装程序
当前的惯例是解码器设置函数的名称 PyImaging_[Decodername]DecoderNew
定义在 decode.c
. 它的python绑定名为 [decodername]_decoder
从内部设置 _imaging.c
函数数组的codecs部分中的文件。
设置函数需要调用 PyImaging_DecoderNew
至少,设置 decode
函数指针。此对象中感兴趣的字段是:
- decode
-
指向解码函数的函数指针,该函数可以访问
im
,state
以及要添加到图像中的数据缓冲区。 - cleanup
-
指向清除函数的函数指针,可以访问
state
. - im
-
目标图像将由Pillow设置。
- state
-
ImagingCodeStateInstance将由枕头设置。这个
context
成员是一个不透明结构,解码器可以使用它来存储任何特定于格式的状态或选项。 - pulls_fd
-
EXPERIMENTAL —— WARNING, 接口可能会改变。如果设置为1,
state->fd
将是指向类似于python文件的对象的指针。解码器可以使用codec_fd.c
直接从类似对象的文件中读取,而不是将数据推送到缓冲区中。请注意,在删除此警告之前,可以重构此实现。3.3.0 新版功能.
译码
使用目标(核心)图像、解码器状态结构和要解码的数据缓冲区调用解码函数。
Experimental ——如果 pulls_fd
设置,然后使用空缓冲区调用一次decode函数。译码器的责任是在那个调用中解码整个图块。本节其余部分仅适用于以下情况: pulls_fd
未设置。
解码器负责从缓冲区中提取尽可能多的数据,并返回所消耗的字节数。对解码器的下一个调用将包括以前未使用的尾部。当从类似文件的对象中读取数据时,解码器函数将被多次调用。
如果发生错误,设置 state->errcode
然后返回- 1。
成功时返回-1,不设置错误代码。
清理
如果解码器返回负值或文件中存在读取错误,则调用cleanup函数。这个函数应该释放所有分配的内存,并从外部库释放任何资源。
python文件解码器应派生自 PIL.ImageFile.PyDecoder
至少应该重写解码方法。文件解码器应使用 PIL.Image.register_decoder()
. 与文件解码器的C实现一样,基于Python的文件解码器的生命周期中有三个阶段:
-
设置:Pillow在注册表中查找解码器,然后实例化类。
-
解码:解码器实例的
decode
方法通过要解释的数据缓冲区重复调用。 -
清理:解码器实例的
cleanup
方法被调用。
讨论区