Exif 格式

JPEG 文件格式的基本结构如图 1 所示,由各个段组成。其中的 DQT、DHT、SOF、SOS 段已经在文章 写一个简易的 JPEG 解码器 中介绍过了。还未介绍的 APP 段是用来存储各种应用数据的,本篇文章介绍其中的一种应用数据 —— Exif,它存储在 APP1 段。

Exif 是 Exchangeable image file format 的缩写,即“可交换图像文件格式”。它是专门为数码相机照片设定的文件格式,可以记录照片的各种元数据。Exif 的大致结构如图 1 的右边所示,后续会详细介绍。

图1 JPEG 压缩数据的基本结构 1

Exif 格式基于 TIFF 格式(Tagged Image File Format,标签图像文件格式)。以下是 Exif 和 TIFF 的标准文档:

1. Exif standard version 2.3

2. TIFF Revision 6.0

本篇文章虽然只基于 Exif 格式铺开,但是从标准文档中也可以看出,JPEG、Exif、TIFF 已经是“互存”的关系了,每篇文档里都会对彼此花上不少篇幅的介绍。

APP1

APP1 标记段的结构如图 2 所示,首先是 2 字节的标记符——0xFF 0xE1,代表是 APP1 段。接着是 2 字节的长度域,表示该段的总长度(包括此域自身,不包括标记符)。这些是 JPEG 标准文档中规定的内容。

再往后是 ascii 码—— Exif\0\0,称作 Exif 标识码,作用是为了防止与其他的应用冲突,起到标识的作用。

再往后就是 Exif 的真正内容了,因为其基于 TIFF 格式,所以下一节开始介绍 TIFF 格式。

图2 APP1 标记段的基本结构 2

TIFF

在说明 TIFF 结构 3 之前,先说明一下相关的术语:一条记录(或一个参数)记录在一个 Entry 里面。多个 Entry 组成一组,称为 Image File Directory (IFD)

TIFF 的总体结构如图 3 所示,头部结构中指示第一个 IFD,IFD 中存储了各个 Entry。IFD 的尾部指示下一个 IFD,以类似链表的方式连接在一起。单个 Entry 的结构在图 3 的右侧,后续会详细说明各个字段。

图3 TIFF 结构

头部

TIFF 的头部由 8 个字节组成,依次如下:

Bytes 0-1 : 指明 TIFF 数据的字节端序。"II" 表示小端序;"MM" 表示大端序。

Bytes 2-3 : 值为 42。指示是一个 TIFF 文件。有点类似魔数的概念。注意字节端序从现在已经“生效”了。

Bytes 4-7 : 第一个 IFD 的偏移,单位为字节。偏移是以 TIFF 文件为参照的,文件第一个字节(即这边介绍的头部)的偏移是 0。

TIFF 中的偏移基于 TIFF 头部,并未基于之前所说的 APP1 段。

IFD

IFD 由 3 部分组成:首先是 2 字节指明 Entry 的数量;接着是指定数量的 Entry,每个 Entry 占 12 字节;最后是 4 字节,指示下一个 IFD 的偏移,如果没有下一个 IFD 则为 0。

如果没有下一个 IFD,最后 4 字节为 0x00000000。

Entry

一个 IFD Entry 占 12 字节,布局如下:

Bytes 0-1 : Tag 值,指明值的含义。

Bytes 2-3 : Type 值,指明值的类型。

Bytes 4-7 : Count 值,指明值的个数。注意这边的单位是“个”,实际存储的大小依据值的类型。比如值为一个 16bit 的字(SHORT),则 Count 值为 1,不是 2。

Bytes 8-11 : 值的偏移或者值本身(Value/Offset)。如果值占的总字节数不大于 4,则值直接放在此字段。否则此字段存放的是值所在的偏移。

Tags

Entry 中的 Tag 字段指明值的含义,具体什么值对应什么含义,这在标准文档中都有定义。因为目前自己只对 Exif 信息和缩略图感兴趣,所以后续我们重点关注一下和它们相关的 Tag。

Exif IFD

Exif IFD 存储了一组 Tag,它记录了 Exif 特有的属性信息。Exif IFD 是由一个 Exif 私有 Tag (34665)指定的,其 Value/Offset 字段指定了其从 TIFF 头部开始的偏移地址。Entry 定义如下:

  • Tag     = 34665(8769.H)
  • Type    = LONG
  • Count   = 1
  • Default = None

简单的说,这个 Tag 信息就是指示 Exif IFD 的“指针”。IFD 结构与上文介绍的一致。

缩略图

缩略图可以支持 RGB、YUV 和 JPEG 格式。由于手头的相机图片缩略图都是以 JPEG 存储的,所以这边只说明 JPEG 缩略图的存储方式。其结构如图 4 所示,可以看到 JPEG 缩略图就是以标准的 JPEG 格式进行存储的。由此也可以发现一些好处,像一些宽高、采样率的信息就不必存储在额外的 Tag 中了(自包含在 JPEG 格式中),只需告诉我们缩略图存储的地方和大小就可以。

图4 附带压缩缩略图的 Exif 结构 4

我们使用 Compression 来区分缩略图是否使用 JPEG 压缩。如果缩略图使用 JPEG 压缩,这个 Tag 值是 6:

  • Tag     = 259(103.H)
  • Type    = SHORT
  • Count   = 1
  • Default = None
  • 6     = JPEG compression(thumbnails only)
  • Other = reserved

JPEG 缩略图存储的地方使用 JPEGInterchangeFormat 记录:

  • Tag     = 513(201.H)
  • Type    = LONG
  • Default = None

JPEG 缩略图的长度使用 JPEGInterchangeFormatLength 记录:

  • Tag     = 514(202.H)
  • Type    = LONG
  • Default = None

提取出来的 JPEG 缩略图数据,直接重命名为 .jpg 后缀就可以查看。


1 《Exif standard version 2.3》 : 4.5.4 Basic Structure of JPEG Compressed Data

2 《Exif standard version 2.3》 : 4.7.2 B APP1 Interoperability structure

3 《TIFF Revision 6.0》 : Section 2 TIFF Structure

4 《Exif standard version 2.3》 : 4.5.8 Basic Structure of Thumbnail Data