当前,几乎新型的数码相机都使用Exif文件格式来存储图像. 它的规格是由JEIDA 来制定的, 但是在互联网上还没有开放的文档可供浏览. 因此我根据从互联网上所能得到一些开放资料做成了这份Exif格式的描述文档.
注: 现在我们能得到官方的文档 Exif2.1 ,它来自 PIMA 的web站点.
ISO 正致力于建立 DCF (Design rule for Camera File system/相机文件系统设计规则) 规格. 所有的数码相机的制造商正准备遵循这份规则并且已经在他们的最新的数字相机上使用了. DCF规格为数字相机定义了完整的文件系统; 如,目录结构, 文件命名方法, 字符集和文件格式等等. 这里的文件格式就是基于 Exif2.1 规格制定的.
rev. 1.3 Sep.09,2000
rev. 1.0 May.28,1999

参考材料

Exif文件格式 itojun著 (日文版文档)
Exif文件格式 Mamoru Ohno著 (日文版文档)
TIFF6.0 规格说明
TIFF/EP 规格说明
exifdump 程序由 Thierry Boush完成制作
DCF 规格说明

什么是 Exif?

基本上, Exif文件格式与JPEG 文件格式相同. Exif按照JPEG的规格在JPEG中插入一些 图像/数字相机 的信息数据以及缩略图像. 于是你能通过与JPEG兼容的互联网浏览器/图片浏览器/图像处理等一些软件 来查看Exif格式的图像文件. 就跟浏览通常的JPEG图像文件一样.

JPEG格式和标记

每一个JPEG文件的内容都开始于一个二进制的值 '0xFFD8', 并结束与二进制值'0xFFD9'. 在JPEG的数据 中有好几种类似于二进制 0xFFXX 的数据, 它们都统称作"标记", 并且它们代表了一段JPEG的 信息数据. 0xFFD8 的意思是SOI图像起始(Start of image), 0xFFD9 则表示EOI图像结束 (End of image). 这两个特殊的标记的后面都不跟随数据, 而其他的标记在后面则会附带数据. 标记的基本 格式如下.
0xFF+标记号(1个字节)+数据大小描述符(2个字节)+数据内容(n个字节)
数据大小描述符(2个字节) 是"Motorola" 的字节顺序, 数据的低位被存放在高地址,也就是 BigEndian. 请注意上面中的 "数据内容" 中包含他前面的数据大小描述符, 如果下面的是一个标记的话;
FF C1 00 0C
它就表示这个标记(0xFFC1) 的数据占 0x000C(等于12)个字节. 但是这个数据大小'12' 包含了 "数据大小" 描述符, 也就是在0x000C后面它只允许带有10 个字节大小的数据.
在JPEG 格式中, 最开始先是用一些标记来描述数据, 然后是放置SOS数据流的起始(Start of stream) 标记. 在SOS标记的后面才是, 存放JPEG图像的数据流并终结于EOI标记.

SOI 标记标记 XX 的大小=SSSS标记 YY 的大小=TTTTSOS 标记 的大小=UUUU图像数据流EOI 标记
FFD8FFXXSSSSDDDD......FFYYTTTTDDDD......FFDAUUUUDDDD....I I I I....FFD9

Exif使用的标记

0xFFE0~0xFFEF之间的标记被叫做"应用标记", 它们在JPEG图像解码中不是必须存在的. 它们被使用于用户的应用程序之中. 例如, 老款的olympus/canon/casio/agfa 数字相机使用 JFIF(JPEG文件交换格式/JPEG File Interchange Format)来存储图像. JFIF 使用 APP0(0xFFE0) 标记来插入数字相机的配置信息数据和缩略图.
Exif也使用应用标记来插入数据, 但是Exif 使用APP1(0xFFE1)标记来避免与JFIF格式的 冲突. 且每一个 Exif 文件格式都开始于它, 如;

SOI 标记APP1 标记APP1 数据Other 标记
FFD8FFE1SSSS 457869660000 TTTT......FFXX SSSS DDDD......

该图像文件从SOI(0xFFD8) 标记开始, 因此它是一个 JPEG 文件. 后面马上跟着 APP1 标记. 而它的所有 Exif数据都被存储在 APP1 数据域中. 上面的 "SSSS" 这部分表示 APP1 数据域 (Exif data area)的大小. 请注意这里的大小 "SSSS" 包含描述符本身的大小.
在"SSSS"后面, 是APP1 的数据. 其中第一个部分是一个特殊的数据,它用来标识是否是 Exif, 其值是ASCII 字符 "Exif" 和 两个0x00字节 的组合字符串.
在APP1 标记域的后面是, 跟随着其他的 JPEG 标记.

Exif数据结构

Exif的数据结构 (APP1)大致如下面那样. 这是"Intel"字节序的情况, 并且它包含了JPEG 格式的 缩略图. 就像上面描述的那样, Exif 数据开始于ASCII字符 "Exif" 和2个字节的0x00, 后面才是 Exif的数据. Exif 使用 TIFF 格式来存储数据. 想获取TIFF的更多的细节的话, 请参考"TIFF6.0规格说明(TIFF6.0 specification)".

FFE1APP1 标记
SSSSAPP1 数据APP1 数据大小
45786966 0000Exif 头
49492A00 08000000TIFF 头
XXXX. . . .IFD0 (主图像)目录
LLLLLLLL连接到 IFD1
XXXX. . . .IFD0的数据域
XXXX. . . .Exif 子IFD目录
00000000连接结束
XXXX. . . .Exif 子IFD的数据域
XXXX. . . .Interoperability IFDDirectory
00000000连接结束
XXXX. . . .Interoperability IFD的数据域
XXXX. . . .Makernote IFDDirectory
00000000连接结束
XXXX. . . .Makernote IFD的数据域
XXXX. . . .IFD1(缩略图像)目录
00000000连接结束
XXXX. . . .IFD1的数据域
FFD8XXXX. . . XXXXFFD9缩略图像

TIFF 头的结构

TIFF格式中前8个字节是 TIFF 头. 其中最开始的前2个字节定义了 TIFF 数据的字节序. 如果这个值是 0x4949="I I"的话, 就表示按照 "Intel" 的字节序(Little Endian) 来排列数据. 如果是 0x4d4d="MM", 则说明按照 "Motorola" 的字节序(Big Endian)来排列数据. 例如, 这个值是'305,419,896' (注意:16进制值为0x12345678). 在Motorola 的 字节序中, 数据存储时的排列顺序为 0x12,0x34,0x56,0x78. 而用 Intel 的字节序的话, 它就是按照 0x78,0x56,0x34,0x12 来排序数据. 几乎所有的数字相机都是使用 Intel 的字节序. 不过 Ricoh 使用的是 Motorola 的. Sony 使用的是 Intel 字节序(除了 D700). Kodak 的DC200/210/240 使用的是 Motorola 字节序, 但是 DC220/260 使用的是 Intel的, 尽管它们都是使用在 PowerPC的平台上! 因此当我们需要使用 Exif 数据的值的时候, 我们必须每次都要检查它的字节序. 尽管 JPEG 数据仅仅是使用 Motorola 字节序, 但Exif 却是允许这两种字节序存在的. 我不明白 Exif 为什么不把字节序修订成 Motorola的.
随后的两个字节是一个2字节长度的固定值 0x002A. 如果数据使用 Intel 字节序, 则这两个 字节的数据排列为 "0x2a,0x00". 如果是 Motorola 的, 则是 "0x00,0x2a". TIFF头的最后的 4个字节是到第一个 IFD(图像文件目录/Image File Directory, 将在下一节中描述)的偏移量. 这个偏移量是指从TIFF头("II" 或者 "MM")开始, 包含自己偏移量值的本身, 到下一个IFD为止的 长度的字节数. 通常地第一个 IFD 是紧挨着 TIFF 头出现的, 因此这个偏移量的值是 '0x00000008'.

字节序标签标注到第一个IFD的偏移量
"I I" or "MM"0x002a0x00000008

IFD : 图像文件目录

紧挨着 TIFF 头, 就是第一个 IFD:图像文件目录(Image File Directory). 它包含了图像 信息的数据. 在下面的表格中, 前两个字节('EEEE') 表示在IFD中有多少个目录项(directory entry) . 它后面存放就是目录项(每个项目大小为12字节) . 在最后一个目录项之后, 有 一个4个字节大小的数据(表格中'LLLLLLLL' ), 它意味着到下一个IFD的偏移量. 如果这个 值是'0x00000000', 则表示它是最后一个IFD 并且不在跟任何的 IFD 相连接.

EEEE目录项的号码
TTTTffffNNNNNNNNDDDDDDDD项目 0
TTTTffffNNNNNNNNDDDDDDDD项目 1
. . . . . . . . .. . . . . .
TTTTffffNNNNNNNNDDDDDDDD项目 EEEE-1
LLLLLLLL到下一个IFD的偏移量

上表中的'TTTT'(2个字节) 是一个标签的号码, 代表数据的种类. 'ffff'(2个字节)表示 数据的格式, 'NNNNNNNN'(4个字节)表示组件的数目. 'DDDDDDDD'(4个字节) 则是数据的 值或者到数据值的偏移量.

数据格式

数据格式 (上面表格中的'ffff') 的定义如下表示. "rational" 的意思是说明数据的 内容是一个分数, 它含有2个有符号/无符号的长整形(signed/unsigned long integer)值, 并且第一个值表示的是分子, 第二个值则是, 分母.

数据的值123456
格式unsigned byteascii stringsunsigned shortunsigned longunsigned rationalsigned byte
组件的大小(字节数)112481
数据的值789101112
格式undefinedsigned shortsigned longsigned rationalsingle floatdouble float
组件的大小(字节数)124848

通过多个存储在'NNNNNNNN'数据区的'组件的大小(字节数)'你能得到所有数据的字节长度. 如果数据的长度小于4个字节, 则'DDDDDDDD' 就表示的是标签的值. 如果长度超过4字节, 则'DDDDDDDD' 里存放的就是所要存储数据的偏移量地址.

IFD数据结构

在Exif格式中, 第一个IFD 是IFD0(主图像IFD), 然后它连接到IFD1(缩略图IFD) 并且IFD 连接在此结束. 但是 IFD0/IFD1 不包含任何的数字相机的信息例如快门速度, 焦距等. IFD0 总是包含一个特殊的标签Exif偏移量(0x8769), 它表示到Exif子IFD的偏移量. Exif子IFD 也是一个IFD 格式化的数据, 它包含了数字相机的信息.