EXIF信息是如何编码的?

11

问候,

我想使用Android获取一些图像的Exif信息。我知道有一些标准的Java库可以在设备上使用,我肯定最终会使用其中一个。

但同时,有人能解释一下这些信息是如何编码在JPG文件内部的吗?通常从文档中哪里/如何获取此信息?当我用文本编辑器打开文档时,它全部都是二进制的。

想了解它的工作原理以及如何读取相关数据。


1
这是我之前写的一篇文章:http://www.codeproject.com/KB/graphics/ExifLibrary.aspx - Ozgur Ozcitak
5个回答

19
我有些晚了,但是作为一名Java库的作者,用于处理Exif(以及其他类型的元数据),我想发表一下看法。

Exif

Exif建立在TIFF(标记图像文件格式)之上。因此,我们首先必须检查TIFF:

  • 一个TIFF文档包含多个称为IFD(图像文件目录)的目录
  • 每个IFD包含零个或多个标签
  • IFD可以链接到零个或多个其他IFD
  • 每个标签都有一个数字ID,并且包含指定数据类型的零个或多个值

将结构视为树状结构,叶子节点包含原始值。TIFF对其结构进行了自我描述,但它并没有规定叶子节点实际上代表什么意义

事实上,您可以在TIFF中存储任何类型的数据,它不与图像耦合。

TIFF文件具有通用标头:

  • 2个字节用于指定字节顺序,可以是ASCII编码下的MMII。这告诉你如何考虑未来的所有字节--是LSB(最低有效位)还是MSB(最高有效位)优先。
  • 2个字节TIFF标记,对于Exif,这是0x002A
  • 4个字节指向第一个IFD的指针

IFD具有同样简单的结构:

  • 2个字节表示接下来要跟随的标签数
  • N个字节用于标签本身(其中N = 12 * tagCount)
  • 4个字节可选指向下一个IFD的指针(如果没有链接到IFD,则使用零值)

标签在12个字节中有简单的表示:

  • 标签ID需要2个字节
  • 数据类型需要2个字节(int8u,int16s,float等)
  • 指定类型的数据值数量需要4个字节
  • 如果适合,值本身需要4个字节,否则需要指向可能找到数据的另一个位置的指针--这可以是指向另一个IFD开头的指针

数据类型是预定义的。例如:1表示8位无符号整数,12表示64位浮点数。

因此,您可以继续跟随数据文件。一些观察结果:

  • 您无法按顺序读取数据,因为它可以自由链接到各个位置。您必须具有随机访问或通过缓冲合成它。
  • 在此时,您所知道的仅是具有ID 0x1234 的标记具有4个整数:{1,2,3,4}

要将TIFF解码为Exif,您需要应用定义每个IFD表示的字典以及这些IFD中每个标记ID表示的内容。

JPEG

大多数使用我的库的用户正在处理JPEG文件。JPEG具有完全不同的结构,由一系列段组成。每个段都有一个标识符和一块字节。Exif在JPEG文件的 APP1 (数字值 0xe1 )段中找到。一旦您拥有它,您必须跳过一些前导字节( Exif \ 0 \ 0 ),然后才能看到表示TIFF格式的Exif数据开始的 MM 或 II 。

通过示例将所有内容整合在一起

这是我的库的样本图像之一的二进制转储:

按顺序:

JPEG起始

  • FF D8 是JPEG的“魔数”。
  • FF 标记了JPEG段的开始。
  • E1 表示JPEG段类型(这是APP1,Exif存储在其中)。
  • 18 B3(6,323十进制)给出了段的长度(包括大小字节),因此我们知道该JPG文件的所有Exif数据将位于接下来的6,321个字节内。请注意,在JPG中,多字节值使用Motorolla排序进行编码,尽管嵌套的Exif数据可能使用Intel排序。
  • 45 78 69 66 00 00 或以ASCII形式表示为Exif\0\0是Exif前导。 APP1不仅专门用于Exif,因此可以区分它们。

TIFF / Exif起始

  • 4D 4DMM表示这个Exif块采用Motorolla字节顺序
  • 00 2A是我们的标准TIFF标记,如上所述
  • 00 00 00 08是相对于TIFF头部(MM在本例中)的第一个IFD的偏移量(8个字节)。这直接指向该序列中的下一个字节,尽管不一定需要。

IFD开始

  • 00 08打开我们的第一个IFD,并告诉我们将有8个标签出现

标签开始

  • 01 0F 是第一个IFD中第一个标签的ID,这里是相机制造商
  • 00 02 是值的类型(2表示ASCII字符串)
  • 00 00 00 16 是组件数,意味着我们将有一个22字节的字符串
  • 00 00 01 B2(434十进制)是指向该字符串位置的指针,相对于TIFF头(MM)。在此截图中看不到它,但它指向的是45 41 53 54 4D 41 4E 20 4B 4F 44 41 4B 20 43 4F 4D 50 41 4E 59 00,即ASCII中的EASTMAN KODAK COMPANY

RAW

相机的原始文件(CR2/NEF/ORW等)通常使用TIFF格式,但是它们使用与Exif不同的标签。这些文件中的第二对字节也将与00 2A不同,表示应该应用的TIFF字典类型。

8
如果您搜索字符串“Exif”,您将找到Exif数据的开始--这非常复杂,我建议使用库--(例如,如果您正在使用.NET,则可以使用我们公司的DotImage)。
以下是高级描述:
Exif本身位于AppMarker内--在此之前的三个字节将是E1(AppMarker 1),标记数据的大小以文件的字节序结尾。在Exif之后的两个字节中,您将看到字节序标记(例如49 49表示II,表示Intel,小端序--这意味着2字节数字在文件中具有低字节优先)。
其余数据广泛使用偏移量,偏移量是从第一个字节序字节(上述情况下的49)的位置开始计算的。
从该偏移量开始的8个字节是一个2字节数字,它是exif标记的数量。如果您处于II字节顺序中,请反转字节以读取长度。
然后将有这个数量的12字节记录。每个记录都是:
2 bytes: Tag ID
2 bytes: Tag Type
4 bytes: Length
4 bytes: data if the data is 4 bytes or less, or an offset to the data

在N个12字节记录之后,您将拥有以上N个记录中使用的每个偏移量指向的数据。 您需要查找ID和类型以了解它们的含义及其表示方式。


3
“Data if the data is 4 bytes or less, or an offset to the data”非常重要,因为大多数网站建议它只是一个偏移量。 - yosh

3

维基百科提供了一些有关EXIF数据存储在文件中的具体位置和方式的指针。当然,你也可以阅读标准文档来了解相关信息。


1

1

谢谢提供链接。我已经找到了一些库,对它们的工作方式很好奇 :-) - Steve

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接