10

问候,

我将使用 android 从一些图像中获取 exif 信息。我知道有一些标准的 java lib 可以与设备一起使用。我相信我最终会使用一个。

但与此同时,有人可以向我解释这些信息是如何在 JPG 中编码的吗?您通常在哪里/如何从文档中获取信息。当我打开他用文本编辑器记录它的所有二进制文件时。

好奇它是如何工作的,以及我如何可能读取有问题的数据。

4

5 回答 5

17

我参加聚会有点晚了,但是我写了一个用于处理 Exif(以及其他类型的元数据)的 Java 库,我想我会插话的。

Exif

Exif 建立在TIFF(标记图像文件格式)之上。所以我们首先要检查 TIFF:

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

将结构想象成一棵在叶子上具有原始值的树。TIFF 是关于其结构的自我描述,但它并没有说明叶子上的值的实际含义

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

TIFF 文件有一个通用标题:

  • 2 个字节用于字节排序,要么是 ASCII,MM要么II是 ASCII。这告诉您以什么顺序考虑所有未来的字节——首先是 LSB 或 MSB。
  • 2 字节TIFF 标记,对于 Exif,这是0x002A
  • 指向第一个 IFD 的4 字节指针

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 数据开始的MMor 。II

举个例子

这是我图书馆的一个示例图像的二进制转储:

为了:

JPEG 开始

  • FF D8是 JPEG 的“幻数”。
  • FF标记 JPEG 段的开始。
  • E1表示 JPEG 段类型(这是APP1Exif 所在的位置)。
  • 18 B3(十进制的 6,323)给出了段的长度(包括大小字节),所以我们知道这个 JPG 文件的所有 Exif 数据都将位于接下来的 6,321 字节内。请注意,在 JPG 中,多字节值使用 Motorolla 排序进行编码,尽管嵌套的 Exif 数据可能使用 Intel 排序。
  • 45 78 69 66 00 00或者在 ASCIIExif\0\0中是 Exif 序言。APP1不是专门为 Exif 保留的,所以这是有区别的。

TIFF/Exif 开始

  • 4D 4DMM表示我们在此 Exif 块中有 Motorolla 字节顺序
  • 00 2A是我们的标准 TIFF 标记,如上所述
  • 00 00 00 08是第一个 IFD 的偏移量(8 字节),相对于 TIFF 标头(MM在这种情况下)。在这种情况下,它直接指向序列中的下一个字节,尽管它不是必须的。

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哪个是EASTMAN KODAK COMPANYASCII

生的

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

于 2013-01-02T01:03:21.583 回答
8

如果您搜索字符串“Exif”,您会发现 Exif 数据的开头——它非常复杂,我建议使用库——(例如,如果您使用的是 .NET,则使用我公司的DotImage)。

不过,这是一个高级别的描述:

Exif 本身位于 AppMarker 内部——之前的三个字节将是 E1(AppMarker 1)和文件字节序中标记数据的大小。在 Exif 之后的两个字节,您将看到字节序标记(例如,这49 49意味着II英特尔、小端 - 这意味着 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 和类型以了解它们的含义以及它们的表示方式。

于 2009-11-30T18:48:45.177 回答
3

Wikipedia提供了一些关于 EXIF 数据在文件中的确切存储方式和位置的指示。当然,总是有标准本身需要阅读。

于 2009-11-30T18:35:05.927 回答
1

解析 EXIF 数据非常繁琐,但您可以找到许多库来解析它。我最喜欢的 Java 是,

http://www.java2s.com/Open-Source/Java-Document/Web-Server/Jigsaw/org/w3c/tools/jpeg/Exif.java.htm

http://jigsaw.w3.org/

于 2009-11-30T19:03:57.803 回答
1

这是 Java 和 EXIF 的优秀库之一:http ://www.drewnoakes.com/code/exif/

于 2009-11-30T19:07:40.223 回答