PicScrub logoPicScrub
返回格式列表

TIFF 格式

Tagged Image File Format

文件头结构

TIFF 是图片元数据的老祖宗。你在 JPEG 里看到的 EXIF 数据, 其实就是一段嵌在文件里的 TIFF 结构。搞懂 TIFF, 也就搞懂了大多数图片元数据的运作方式。

这个格式以一个 8 字节的文件头开场,它告诉你两件关键的事: 字节序(Intel 还是 Motorola),以及第一个 IFD 在哪里。 从这里开始,剩下的就全是顺着指针跳来跳去了。

TIFF 文件结构

Header
IFD0
Strip Data
EXIF IFD
GPS IFD
Header
8 字节
字节序 + 魔数 + IFD 偏移量
IFD0
200 字节
主图像目录
Strip Data
长度可变
图像像素数据
EXIF IFD
500 字节
EXIF 子目录
GPS IFD
100 字节
GPS 子目录

TIFF 文件头

字节序(II = 小端序)
魔数(42)
第一个 IFD 的偏移量
OffsetHexASCII
0000
49492A0008000000
II*.....

字节序

49 49(II)

Intel:小端序(低位字节在前)

4D 4D(MM)

Motorola:大端序(高位字节在前)

IFD 结构

IFD 是 Image File Directory 的缩写,你可以把它当成一份目录。 它是一张扁平的标签列表,每个标签指向一块数据。妙的地方在于, IFD 还能指向别的 IFD,从而形成一棵树。

IFD 的布局

2 字节条目数量(标签个数)
12 × N 字节标签条目(每个 12 字节)
4 字节下一个 IFD 的偏移量(没有则为 0)

标签条目的结构(12 字节)

标签 ID类型数量值/偏移量
2 字节2 字节4 字节4 字节

如果数据能塞进 4 字节,就直接存在值字段里;否则值字段存的是指向数据的偏移量。

标签类型

TIFF 是强类型的。每个标签不仅说明自己装着什么,还说明这些字节该怎么解释。 所以要正确解析 TIFF,就必须先搞懂它的类型系统。

ID名称大小说明
1BYTE18 位无符号整数
2ASCII1以空字符结尾的字符串(8 位)
3SHORT216 位无符号整数
4LONG432 位无符号整数
5RATIONAL8两个 LONG:分子/分母
6SBYTE18 位有符号整数
7UNDEFINED1原始字节(二进制数据)
8SSHORT216 位有符号整数
9SLONG432 位有符号整数
10SRATIONAL8两个 SLONG:有符号的分子/分母
11FLOAT4IEEE 32 位浮点数
12DOUBLE8IEEE 64 位双精度浮点数
13IFD4指向嵌套 IFD 的指针

值的存放规则

如果 大小 × 数量 ≤ 4 字节,值就直接存在那 4 字节的值字段里; 否则该字段存的是一个偏移量,指向数据在文件中的实际位置。

IFD 偏移量的计算

解析 TIFF 最难的部分是跟着偏移量一路追下去。所有偏移量都相对于文件开头, 你得来回跳很多次。计算方式是这样的:

// IFD0 的位置
IFD0_offset = bytes[4:8] // 来自 TIFF 文件头
// 下一个 IFD 的位置(例如放缩略图的 IFD1)
next_IFD = IFD0_offset + 2 + (entry_count × 12) + 4
// 子 IFD 的位置(EXIF、GPS)
subIFD_offset = tag_value // 来自指针标签(0x8769、0x8825)

重要的标签

图像数据标签(会保留)

0x0100:ImageWidth
0x0101:ImageLength
0x0102:BitsPerSample
0x0103:Compression
0x0111:StripOffsets
0x0117:StripByteCounts

元数据标签(会清除)

0x010F:Make(相机厂商)
0x0110:Model(相机型号)
0x0132:DateTime
0x013B:Artist
0x8298:Copyright
0x9003:DateTimeOriginal

指针标签(子 IFD)

0x8769:ExifIFDPointer
0x8825:GPSInfoIFDPointer
0xA005:InteroperabilityIFDPointer

子 IFD

主 IFD(IFD0)里常常有一些“指针标签”,指向各个子目录。 EXIF、GPS 和其他元数据就是这样被分成一组组逻辑单元, 同时让主 IFD 保持清爽。

EXIF 子 IFD

存放相机相关的元数据:曝光、光圈、ISO、焦距、闪光灯、白平衡等等。

GPS 子 IFD

存放地理位置数据:纬度、经度、海拔、时间戳、卫星、速度、方向。 隐私上的头号问题。

Maker Notes

相机厂商的私有数据,格式各家不同, 里面可能有序列号、固件版本和自定义设置。

PicScrub 如何处理 TIFF

1

解析文件头

判断字节序(II/MM),并找到第一个 IFD

2

建立标签白名单

找出渲染图像所必需的标签

3

过滤 IFD 条目

删除元数据标签,把子 IFD 的指针清零

4

重写文件

用干净的 IFD 和原样复制的图像数据重新组装 TIFF

偏移量的重新计算

TIFF 文件大量依赖文件内的偏移量。清除元数据之后, PicScrub 必须重新计算所有偏移量,才能保证文件仍然完整可用。