这里记录一下我在研究tiff标签图像文件格式(Tag Image File Format,TIFF)时的一些知识点,为后续自己实现tiff文件解析器做准备。
tiff是什么
tiff是一种基于标签的、用于存储图像数据的文件格式。tiff的应用非常广泛。这里的tiff指的是文件格式,而不是文件扩展名,基于tiff标准的文件的扩展名通常为.tiff或者.tif
注:一些基于tiff文件格式规范的文件会使用其他扩展名,比如.svs文件,它是基于tiff规范,只不过在tiff规范规定的标准之外定义了自己的新标签。
特点
- TIFF可以描述多种类型的图像、支持多种色彩系统;
- 他支持多种图像压缩方案
- 和操作系统无关
- 易于扩展:基于标签的格式使其易于扩展存储的信息
格式复杂
TIFF文件的复杂性给它的应用带来了一些问题。一方面,要写一种能够识别所有不同标记的软件非常困难。另一方面,一个TIFF文件可以包含多个图像,每个图像都有自己的IFD和一系列标记,并且采用了多种压缩算法。这样也增加了程序设计的复杂度。
灵活/可扩展
TIFF 是一个灵活适应性强的文件格式,通过在文件头中包含“标签”它能够在一个文件中处理多幅图像和数据。标签能够标明图像的如图像大小这样的基本几何尺寸或者定义图像数据是如何排列的并且是否使用了各种各样的图像压缩选项。以至于它能够满足各种需求,从而被应用到很多领域,比如基于TIFF规范的数字切片格式定义等。
程序员可以随意基于TIFF标准来定义新的标签和选项,但是并不是所有的实现程序都能支持这些创造出来的标签。因此,解析tiff文件变得很复杂,谁也不知道你的图像数据是什么,有多少张。
TIFF结构简单了解
以下内容以TIFF version 6 版本为准
TIFF文件以.tif为扩展名。其数据格式是一种3级体系结构,它内部结构可以分成三个部分,分别是:文件头信息区、图像文件目录和图像数据区。其中所有的标签都是以升序排列
,这些标签信息是用来处理文件中的图像信息的。(注意,除了头文件信息区,另外两个的顺序不固定的)
文件头(IFH)
在每一个TIFF文件中第一个数据结构称为图像文件头或IFH,它是图像文件体系结构的最高层。这个结构在一个TIFF文件中是惟一的,有固定的位置。它位于文件的开始部分,包含了正确解释TIFF文件的其他部分所需的必要信息。
每个TIFF文件都是从指示字节顺序的两个字节开始的。“II”表示小字节在先、“MM”表示大字节在先字节顺序。
在tiff6.0的规范中,其3-4个字节标识版本号,其值总是为42。
再后面的4个字节就是第一个 IFD 的偏移量,注意,IFD可能有多个。
- TIFF 文件中所使用的偏移量,都是相对于文件头位置的偏移量;
- 偏移量必须以
Word
边界开始,也就是说,所有偏移量必须为偶数。
文件目录(IFD)
IFD是TIFF文件中第2个数据结构,它是一个名为标记(tag)的用于区分一个或多个可变长度数据块的表,标记中包含了有关于图像的所有信息。IFD提供了一系列的指针(索引),这些指针告诉我们各种有关的数据字段在文件中的开始位置,并给出每个字段的数据类型及长度
。这种方法允许数据字段定位在文件的任何地方,且可以是任意长度,因此文件格式十分灵活。
图像文件目录(Image File Directory)是 TIFF 图中非常重要的数据结构,一个 TIFF 文件可以包含多个 IFD,这时表示此文件包含多个图像,一个 IFD 标识一个图像的属性。
TIFF文件中必须至少有1个IFD,并且每个IFD必须至少有一个条目(Directory Entry,简称DE,下文介绍)。
IFD结构
一个IFD包括:
- 2个字节:表示该IFD中DE数量(Directory Entry Count)
- 第一个DE数据(每个DE固定12字节)
- 第二个DE数据。。。以此类推
- 第count个DE数据
- 4个字节:下一个IFD数据结构的起始偏移量的位置,如果没有下一个,则需要补填上4个字节的0
Directory Entry(DE)
表示图像的某一个属性,共有 Directory Entry Count 个。一个 DE 记录一个图像的属性,例如图像的 长、宽、分辨率等。
- 最开始前两个字节是表示:Tag(知道为什么叫标签图像文件格式了吧),数据类型是word
- 第3、4个字节表示:Type,数据类型是word
- 再后面的4个字节,表示Length,数据类型是: Unsigned Long
- 最后4个字节表示:value Offset 数据类型是:Unsigned Long
每个DE共占据12个字节。但是一个图像的属性说不定不够12个字节记录的,那怎么办呢?看下文的valueOffset
定义。
tag
2 字节,该属性的标签编号,在 IFD 中,多个 DE 的 Tag 值是升序排列的
,此编号可以在 TIFF 的规范中找到。(用户也可以定义自己的私有标签,并赋予它含义,这样可以极大扩展TIFF格式的灵活性,但是因为是非标准这也意味着对于TIFF解析器来说,他可以忽略这个标签)
比如:TagName为ImageWidth的这个tag,其tag值用256表示,其Type(看下文)是SHORT or LONG
Type
2 字节,该属性的数据的数据类型,该值可以在 TIFF 规范中找到。比如Type是3就表示是SHORT,表示16位 unsigned integer.
Length
4 字节,数据的数量,注意,此处为数据的数量而不是数据的字节数。也就是说,如果该值为1,则表明Type类型的数据有1个。如果为100,则表明Type类型的数据有100个,更详细的了解结合valueOffset。
valueOffset
标准TIFF规范中,其字段为 4 字节,如果数据的数量乘以数据类型的字节长度(即实际数据的字节数)小于等于 4,则此处存储数据,否则,此处存储数据位置的偏移量(相对于文件头的偏移量)
也就是说如果说这个DE的数据大小超过了4字节,则这里存的是该数据存储的偏移量,说是小于4字节,则这里直接存该数据了。真灵活,数据可以乱存。而且由于Length的存在,其实这个DE真实的数据大小可以不固定。他是由Length * 数据类型的字节长度得来的。
图像数据
根据IFD所指向的地址,存储相关的数据信息。这里面的数据,需要搭配IFD中的信息来进行解释。
bigtiff
标准tiff使用 32 位偏移量(指IFD -> DE -> valueOffset),因此它的数据的限制为 4 GB(因为超过4GB,那么其在IFD中描述的偏移量就超过了32位了)所以,就推出了bigtiff,它使用 64 位偏移量以突破标准tiff的4GB大小的限制。
具体标准tiff和bigtiff的差异,请参考:https://www.awaresystems.be/imaging/tiff/bigtiff.html
总结
通过本篇文章,我们了解了什么是tiff文件格式,以及大致理清了整个文件结构中包含哪些内容,然而想要能够真正对其进行解析,我们还需要了解TIFF标注所定义的tag(IFD -> DE -> tag)的含义是什么,这样,才能解析出tiff中所存储的数据。关于这一部分,主要参考TIFF 6.0规范的pdf文档,我整理了规范中比较常用的一些tag,参考:TIFF6文档参考。