JPEG/Exif/TIFF格式解读(3):TIFF与JPEG里面EXIF信息存储原理解读
Author:zhoulujun Date:
TIFF - Tag Image File Format文件格式最早是为了存储扫描仪图像而设计的。它的最大的特点就是与计算机的结构、操作系统以及图形硬件系统无关。它可处理黑白、灰度、彩色图像。在存储真彩色图像时和BMP格式一样,直接存储RGB三原色的浓度值而不使用彩色映射(调色板)。对于介质之间的交换,TIF称得上是位图格式的最佳选择之一。由于其简单灵活,所以使用很广。
TIFF的全面性也产生了不少问题,它的包罗万象造成结构较为复杂,变体很多,兼容性较差,它需要大量的编程工作来全面译码。例如,TIF图像数据可以用几种不同的方法压缩,用一个程序来读出所有的TIF几乎是不可能的。
TIFF图像文件格式
TIFF文件由三部分构成:
文件头(TIFF Header),简称IFH
文件目录IFD(Image File Directory),简称IFD
目录项(Directory Entry),包含图像数据
TIF图像文件的一般组织形式是:IFH——图像数据——IFD。IFD数据结构并不一定紧跟在IFH后面,相反,它常常位于图像数据的后面。
其结构如下图所示
文件头的格式与长度是固定的,主要是指出第一个文件目录(IFD0)的位置。文件目录IFD则指出该图像有多少个目录项(Directory Entry),和下一个IFD的位置。
每个目录项有12字节,如上图中IFD0有8个目录项。一般一个IFD表示一个图像,如果TIFF文件中有多个图像,则有多个IFD(IFD0, IFD1,…)。各个IFD由指针连接。
大多数的目录项是存放图像的元数据,目录项中的标签编码(Tag)代表元数据的名称,另外还有类型及数据等如上图所示。
TIFF图像文件头IFH的结构
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" | 0x002a | 0x00000008 |
IFH数据结构包含3个成员共计8个字节:
名称 | 字节数 | 数据类型 | 说明 |
Byte order | 2 | Integer | TIF标记,其值为“MM”(0x4d4d)或“II”(0x4949) 0x4d4d表示该TIFF图是Motoral整数格式,即BigEndian; 0x4949表示该图是Intel整数格式,即LittleEndian。 |
Version | 2 | Integer | 版本号,其值恒为0x2A 00 |
Offset to first IFD | 4 | Long | 第一个IFD相对文件开始处的偏移量(可能会有多个顺序排列的IFD) |
TIFF与元数据
TIFF只定义了图像的基本元数据,对于某些图像中的特有元数据(如照片中的光圈快门等)可以用Private IFD自行定义其专门的元数据。也就是Private IFD可以看成是IFD的扩充,用IFD0中某一标签(Tag)作为指针,指向另一个子IFD,然后在子IFD中定义自己的元数据。
Exif就是由IFD0中Tag=0x8769 的目录项(称为exifIFD)指向一个Exif subIFD,在该子IFD中就是与照片有关的各种元数据,如光圈,快门等。因此Exif使用的是TIFF格式,而Exif本身则是TIFF IFD0的一个子集。
与Exif类似的还有GPS数据(具有GPS功能相机记录的拍摄位置),是由IFD0中Tag=0x8825的目录项指向GPS subIFD。
此外Exif还包含缩略图标,所以还有第二个IFD(IFD1)用于表示缩略图。
Exif总的结构如下图所示:
需要指出的是Exif的IFD0中没有图像数据。Exif中的Makernote是制造商自己设置的数据,没有统一格式,很多也是不公开的,所以Makernote 也是作为Exif的一个子IFD,由制造商自己定义。
IFD : 图像文件目录
IFD是TIFF图像文件中重要的数据结构,它包含了三个成员:DE count、DE、next IFD offset。
由于一个TIFF文件中可以有多个图像,而一个IFD只标识一个图像的所有属性(或称之为“标签”),所以,一个TIFF文件中有几个图像,就会有几个IFD。
IFD的结构:
名称 | 字节数 | 数据类型 | 说明 |
---|---|---|---|
Directory Entry Count | 2 | Integer | 该IFD中DE的数量 |
Directory Entry(1) | 12 | Integer | DE,“目录项” |
Directory Entry(2) | 12 | Integer | DE的个数是不定的,因为每个DE只标识了图像的一个属性,那么这幅图像有N个属性就会有N个DE; |
…… | 用户甚至可添加自定义的标记属性,这就是为什么称TIF格式文件为“可扩充标记的文件”的原因。 | ||
Directory Entry(N) | 12 | Integer | |
Offset to next IFD | 4 | Long | 如果该数字为0,表示已经是最后一个IFD。 如果该TIF文件只包含了一幅图像,那么就只有一个IFD,这个偏移量也会等于0。 |
DE目录入口(Directory Entry)
一个DE就是一幅图像的某一个属性。例如图像的大小、分辨率、是否压缩、像素的行列数、颜色深度(单色、16色、256色、真彩色)等等。
DE结构:
名称 | 字节数 | 数据类型 | 说明 |
tag | 2 | Integer | 本属性的标签编号。在图像文件目录中,它是按照升序排列的(但不一定是连续的) |
type | 2 | Integer | 本属性值的数据类型 |
length | 4 | Long | 该类型数据的个数 |
valueOffset | 4 | Long | tagID代表的变量值相对文件开始处的偏移量,但如果变量值占用的空间不多于4个字节(例如只有1个Integer类型的值),那么该值就直接存放在valueOffset中,没必要再另外指向一个地方了。 |
DE中标签编号的含义
TagID | 属性名称 | type | 说明 |
---|---|---|---|
0100 | 图像宽 | Integer | |
0101 | 图像高 | Integer | |
0102 | 颜色深度 | Integer | 1为单色,4为16色,8为256色。 如果该类型数据个数>2个,说明是真彩图像 |
0103 | 图像数据是否压缩 | Integer | 压缩方式(1/2/5/6/32773),1为不压缩,其他表示压缩 |
0106 | 图像是否采用反色显示 | Integer | 01表示反色,否则表示不反色 对于RGB图,该值是2 |
0111 | 图像扫描线偏移量 | Long | 图像数据起始字节相对于文件开始处的位置 |
0116 | 图像扫描线的数量 | Long | 表示图像有几行扫描线,实际上等于图像高度 |
0117 | 图像数据字节总数 | Integer | 一般是个偶数。如果是奇数,那么实际存放时会在后面补一个0,但这个0不会计算在字节总数之内。 |
011A | 水平分辩率偏移量 | RATIONAL | 单位:像素/英寸 分数型的属性,其值要占用8个字节,所以在valueOffset中存放的肯定是它的具体数值的偏移量,而不是数值本身。下同。 |
011B | 垂直分辩率偏移量 | RATIONAL | 单位:像素/英寸 |
011C | 像素存储顺序 | Integer | 每个像素的(R,G,B)是如何存储的。1表示按照RGBRGB的顺序来存储 |
0128 | X/Y分辨率单位 | Integer | X/Y轴分辨率的单位 |
0131 | 生成该图像的软件名 | ASCII | 字符型属性。值所占用的空间也会大于4字节,所以在valueOffset中存放的也是它们的值的偏移量,而不是值本身。下同。 |
0132 | 生成该图像的时间 | ASCII | |
0140 | 调色板偏移量 | Integer | 256色和16色图像才有此属性,而且有连续2个调色板,但属性的length值只表示出1个调色板 |
TIFF中的图像数据
图像数据。这些数据可能是压缩的,也可能是未压缩的。如果经过压缩,那么压缩算法又有许多种,所以,图像数据是TIF文件中最为复杂的部分,暂还没有哪个软件能译出所有的压缩算法。
TIFF实例
用画图程序新建一个17*15的白色图像,另存为TIF文件:
0000-0007:49 49 2A 00 4E 00 00 00
文件头,0x49 49表示该图是Intel整数格式;0x2A 00表示TIFF版本号;0x4E表示第一个IFD的偏移量为4E。
004E-0107:第一个IFD。
Directory Entry Count的值0x0F为15,表示这个IFD中有15个DE。
每个DE占用12字节,15个DE共占用180字节,加上Directory Entry Count占用的2字节,再加上Offset to next IFD占用的4字节,这个IFD共占用186字节,换算为16进制就是BA,所以,它的数据结束于0x4E + 0xBA = 0107。
Offset to next IFD的值(最后4个字节)均为0,表示整幅图像文件只有这一个IFD。
其中15个DE的描述:
序号 | 偏移量 | TagID | Type | length | Value/Offset | 说明 |
1 | 0050 | 00FE | Long | 1 | 00 | 未知属性值=0 |
2 | 005C | 0100 | Integer | 1 | 11 | 图像宽为17像素(10进制) |
3 | 0068 | 0101 | Integer | 1 | 0F | 图像高为15像素(10进制) |
4 | 0074 | 0102 | Integer | 3 | 48 | 3个Integer类型的值,共计6字节 所以Value/Offset中存放的是其值的偏移量。 其值存放在48-4D |
5 | 0080 | 0103 | Integer | 1 | 05 | 图像是压缩数据,压缩类型为5 |
6 | 008C | 0106 | Integer | 1 | 02 | 图像不反色显示 |
7 | 0098 | 0111 | Long | 1 | 08 | 图像数据起始字节为8 |
8 | 00A4 | 0115 | Integer | 1 | 03 | 未知属性值=3 |
9 | 00B0 | 0116 | Long | 1 | 0F | 图像扫描线有15行 |
10 | 00BC | 0117 | Long | 1 | 2F | 图像共有47个字节的压缩数据 |
11 | 00C8 | 011A | RATIONAL | 1 | 38 | 水平分辩率存放在38-3F |
12 | 00D4 | 011B | RATIONAL | 1 | 40 | 垂直分辩率存放在40-47 |
13 | 00E0 | 011C | Integer | 1 | 01 | 像素存储顺序, 1为RGB |
14 | 00EC | 0128 | Integer | 1 | 02 | Xresolution和Yresolution的单位,值为2 |
15 | 00F8 | 013D | Integer | 1 | 01 | 未知属性值=1 |
0008-0037:图像数据。
注意最后那个0是补加的,它没有统计在“图像数据字节总数”属性值中。
0038-003F:60 00 00 00 01 00 00 00
水平分辩率值,8个字节。
由于它是分数类型,前4个字节是分子,其值为0x60 00 00 00,转换为10进制就是96,后4个字节是分母,其值是0x01 00 00 00,转换为10进制就是1。所以,分数值是96/1,它表示每英寸96像素
0040-0047:60 00 00 00 01 00 00 00
垂直分辩率值。同样为96像素。
0048-004D:08 00 08 00 08 00
颜色深度值。3个整型数据值都为8,表示这是一幅24位图像。
JPEG图片的EXIF数据
EXIF JPEG文件将EXIF信息存储在JFIF的APP1标记中。
EXIF主要保存拍摄照片时的相机参数、图像缩略图、GPS信息等。
EXIF在JPEG图片中的存储位置
EXIF 存储在JPEG图片的 APP1标记中,符合JFIF标准。APP1标记的格式包含三部分:标记 (0xFFE1)、数据长度、数据内容。
存储了EXIF的APP1标记通常包含:标记 (0xFFE1)、数据长度、EXIF标示符、EXIF数据。
也就是说,EXIF APP1 在数据内容起始(即紧跟数据长度之后),设置Exif标示符 (“Exif\0\0”),标示该APP1 中的数据是EXIF数据。
EXIF标示符是为了与其它也使用 APP1标记的数据(如XMP)区分。
JPEG图片中存储的EXIF如图:
就像上面描述的那样, Exif 数据开始于ASCII字符 "Exif" 和2个字节的0x00, 后面才是 Exif的数据.
缩略图数据存储在IFD1的数据域.
FFE1 | APP1 标记 | ||||
SSSS | APP1 数据 | APP1 数据大小 | |||
45786966 0000 | Exif 头 | ||||
49492A00 08000000 | TIFF 头 | ||||
XXXX. . . . | IFD0 (主图像) | 目录 | |||
LLLLLLLL | 连接到 IFD1 | ||||
XXXX. . . . | IFD0的数据域 | ||||
XXXX. . . . | Exif 子IFD | 目录 | |||
00000000 | 连接结束 | ||||
XXXX. . . . | Exif 子IFD的数据域 | ||||
XXXX. . . . | Interoperability IFD | Directory | |||
00000000 | 连接结束 | ||||
XXXX. . . . | Interoperability IFD的数据域 | ||||
XXXX. . . . | Makernote IFD | Directory | |||
00000000 | 连接结束 | ||||
XXXX. . . . | Makernote IFD的数据域 | ||||
XXXX. . . . | IFD1(缩略图像) | 目录 | |||
00000000 | 连接结束 | ||||
XXXX. . . . | IFD1的数据域 | ||||
FFD8XXXX. . . XXXXFFD9 | 缩略图像 |
需要说明的是,尽管 JPEG 数据仅仅是使用 Motorola 字节序, 但 Exif 却是允许Intel字节序 和 Motorola 字节序这两种字节序存在的。
EXIF遵循TIFF文件格式,并对TIFF格式做了一些扩展。
EXIF中的IFD结构
因此EXIF也是一种非常灵活的格式,具有非常好的可扩充性,要想较好地处理其中的相关数据也是比较麻烦的。
标准的TIFF格式在 上篇中讲到。简单回顾一下TIFF格式中的IFD。
IFD是一个链表结构,如图所示。在每个IFD的末尾包含一个指向下一个IFD的偏移量(同样是从TIFF Header算起),如果这个偏移量为0,则表示已经到了链表的末尾。
在Exif格式中,只有两个标准IFD。第一个IFD 是IFD0(主图像IFD), 然后它连接到IFD1(缩略图IFD) ,并且IFD 连接在此结束。IFD0/IFD1 不包含任何的数字相机的信息,例如快门速度, 焦距等.
在IFD0中除了自己的DE外,还包括了EXIF自定义的EXIF Sub IFD、GPS IFD,而EXIF sub IFD中又进一步包括了Interoperability IFD(简称IOP)和MakerNote IFD。
EXIF自定义IFD的结构与标准TIFF IFD相同,但不是记录于TIFF的IFD链表中,而是 作为TIFF IFD的子链表形式存在(因为扩展IFD里定义了不同于TIFF标准的Tag,这样为了与标准的TIFF格式区分),使得原来的TIFF IFD链表结构变成了树形结构 。
EXIF自定义IFD在IFD0中以DE Tag的方式出现,都是LONG类型,它记录了相应扩展IFD的起始位置(从TIFF Header开始的偏移)。
EXIF自定义标签编号的含义
TagID | 属性名称 | type | 说明 |
8769 | EXIF IFD | LONG | 数字相机的信息 |
8825 | GPS IFD | LONG | 地理位置信息 |
A005 | Interoperability IFD | LONG | 互操作扩展信息 |
927C | MakerNote IFD | LONG | 厂商自己独有的注释信息 |
扩展IFD中用到的Tag全部是EXIF重新定义的。 Tag的种类和数量非常之大,在EXIF规范里定义了各个Tag的支持级别,光是JPEG格式下必须支持的Tag就有十几个,再加上可选支持的Tag,有几十上百个,并且还存在未来继续扩充的可能。
其它头描述,《JPEG/Exif/TIFF格式解读(5):exif marker Tag ID》
EEEE | 目录项的号码 | |||
TTTT | ffff | NNNNNNNN | DDDDDDDD | 项目 0 |
TTTT | ffff | NNNNNNNN | DDDDDDDD | 项目 1 |
. . . . . . . . . | . . . . . . | |||
TTTT | ffff | NNNNNNNN | DDDDDDDD | 项目 EEEE-1 |
LLLLLLLL | 到下一个IFD的偏移量 |
上表中的'TTTT'(2个字节) 是一个标签的号码, 代表数据的种类. 'ffff'(2个字节)表示 数据的格式, 'NNNNNNNN'(4个字节)表示组件的数目. 'DDDDDDDD'(4个字节) 则是数据的 值或者到数据值的偏移量.
数据格式
数据格式 (上面表格中的'ffff') 的定义如下表示. "rational" 的意思是说明数据的 内容是一个分数, 它含有2个有符号/无符号的长整形(signed/unsigned long integer)值, 并且第一个值表示的是分子, 第二个值则是, 分母.
数据的值 | 1 | 2 | 3 | 4 | 5 | 6 |
格式 | unsigned byte | ascii strings | unsigned short | unsigned long | unsigned rational | signed byte |
组件的大小(字节数) | 1 | 1 | 2 | 4 | 8 | 1 |
数据的值 | 7 | 8 | 9 | 10 | 11 | 12 |
格式 | undefined | signed short | signed long | signed rational | single float | double float |
组件的大小(字节数) | 1 | 2 | 4 | 8 | 4 | 8 |
通过多个存储在'NNNNNNNN'数据区的'组件的大小(字节数)'你能得到所有数据的字节长度. 如果数据的长度小于4个字节, 则'DDDDDDDD' 就表示的是标签的值. 如果长度超过4字节, 则'DDDDDDDD' 里存放的就是所要存储数据的偏移量地址.
IFD数据结构
在Exif格式中, 第一个IFD 是IFD0(主图像IFD), 然后它连接到IFD1(缩略图IFD) 并且IFD 连接在此结束. 但是 IFD0/IFD1 不包含任何的数字相机的信息例如快门速度, 焦距等. IFD0 总是包含一个特殊的标签 Exif偏移量(0x8769), 它表示到 Exif子IFD 的偏移量. Exif子IFD 也是一个IFD 格式化的数据, 它包含了数字相机的信息.
在扩展Exif格式(Exif2.1/DCF)中, Exif子IFD还包含了特殊的标签 Exif Interoperability Offset (0xa005). 这个偏移量也指向Interoperability IFD. 根据 DCF 规格, 这个标签是必须的并且子IFD (主图像 IFD) 和 IFD1 (缩略图 IFD) 中可能也会包含Interoperability IFD. 通常, 仅仅主图像仅仅有这个标签.
另外一些数字相机也为Makernote(制造商注释)使用 IFD 数据格式; 这是生产商特定的 魔数(magic number)区域. 判断makernote 是否是IFD 格式是非常困难的, 必须仔细的 编程. 关于Makernote的信息请参考附录.
0000: 49 49 2A 00 08 00 00 00-02 00 1A 01 05 00 01 00 0010: 00 00 26 00 00 00 69 87-04 00 01 00 00 00 11 02 0020: 00 00 40 00 00 00 48 00-00 00 01 00 00 00
上面的是TIFF数据的开头部分, 对它的解读如下;
前两个字节是 "I I", 所以字节序是 'Intel'.
在地址0x0004~0x0007处存放的值是 0x08000000, 因此IFD0 从地址 '0x0008'开始
在地址0x0008~0x0009处存放的值是 0x0200, 则表示IFD0有 '2' 个目录项.
在地址0x000a~0x000b处存放的值是 0x1A01, 它意味着这是一个 XResolution(0x011A) 标签, 表示这是图像的水平分辨率.
地址0x000c~0x000d处存放的值为 0x0500, 说明数据的格式是一个 unsigned rational(0x0005).
地址0x000e~0x0011处存放的值是 0x01000000, 说明组件的数据只有 '1'个. Unsigned rational的数据大小是8字节(组件的大小), 因此数据的总长度是 1x8=8字节.
总数居长度比4字节大了, 因此它后面的4个字节里面存放的是一个指向实际数据的偏移量地址.
地址0x0012~0x0015处存放的是 0x26000000, 表示XResolution(水平分辨率) 数据的存储地址是0x0026
地址0x0026~0x0029处存放的数据是 0x48000000, 说明分子的值为 72, 而地址0x002a~0x002d 处存放的是0x0100000000, 说明分母为 '1'. 因此XResoultion 的值是 72/1.
地址0x0016~0x0017处存放的数据为0x6987, 表示下一个标签是 ExifOffset(0x8769). 这就是 指向 Exif子IFD的偏移量
而它的数据格式是 0x0004, 即是一个无符号的长整形(unsigned long integer).
这个标签只有一个组件. 无符号长整形的数据大小是4字节, 因此总数据长度为4字节.
总数据长度是 4字节, 则说明下一个4字节的数据中存放的是Exif子IFD的偏移量.
地址0x001e~0x0021处存放的是 0x11020000, 则说明Exif子IFD的开始地址是 '0x0211'.
这是最后一个目录项, 接下来的4个字节存放的是下一个IFD的偏移地址.
地址0x0022~0x0025处存放的是 0x40000000, 就可以知道下一个IFD的开始地址为 '0x0040'
缩略图
Exif格式中包含缩略图像(除了Ricoh RDC-300Z). 通常它被放到IFD1的后面. 缩略图有 3 种格式; JPEG 格式(JPEG 使用YCbCr), RGB TIFF 格式, YCbCr TIFF 格式. 在Exif2.1之后推荐使用JPEG 格式和160x120像素的尺寸. 根据 DCF 规格, 缩略图像必须 使用JPEG 格式以及图像的尺寸 固定为160x120 像素.
JPEG格式的缩略图
IFD1中的标签Compression(0x0103)如果是 '6', 则缩略图就是JPEG格式. 几乎所有的 Exif图像中缩略图都使用JPEG 格式. 在这种情况下, 你能从IFD1的JpegIFOffset(0x0201) 标签中得到缩略图的偏移量, 从标签JpegIFByteCount(0x0202)中得到缩略图的大小. 数据格式则是普通的 JPEG 格式, 也就是从0xFFD8处开始在0xFFD9处结束.
TIFF格式的缩略图
IFD1的标签Compression(0x0103)如果是 '1', 则缩略图的格式就没有经过压缩的 (就是TIFF 图像). 缩略图数据的开始点是标签 StripOffset(0x0111) , 缩略图的尺寸 就是标签 StripByteCounts(0x0117) 之和.
如果缩略图使用非压缩格式并且IFD1中的标签 PhotometricInterpretation(0x0106) 是 '2', 则缩略图使用了 RGB 格式. 在这种情况下, 你只要简单的把数据拷贝到计算机的RGB格式 中就能看到缩略图了(如 BMP 格式, 或者拷贝到 VRAM 目录下). Kodak DC-210/220/260 就使用 这个格式. 注意TIFF中存储的像素数据是'RGB' 顺序的, 而 BMP 里的存储顺序则是 'BGR' .
如果这个标签的值是 '6', 缩略图使用 YCbCr 格式. 如果你想要看到缩略图的话, 你必须把它 转换成 RGB 格式的. Ricoh RDC4200/4300, Fuji DS-7/300 和 DX-5/7/9 使用的是这种格式 (较新的 RDC5000/MX-X00 系列使用的是 JPEG). 在下一节中主要描述的就是Fuji DS相机的缩略图 的图像转换. 想要了解更多的信息, 请参考 TIFF6.0 规格说明.
在DX-5/7/9的场合, YCbCrSubsampling(0x0212) 的值是 '2,1', PlanarConfiguration(0x011c) 的 值是 '1'. 因此这种图像的数据排列是下面的那样.
Y(0,0),Y(1,0),Cb(0,0),Cr(0,0), Y(2,0),Y(3,0),Cb(2,0),Cr(3.0), Y(4,0),Y(5,0),Cb(4,0),Cr(4,0). . . .
括号中的数字代表的是像素坐标. DX 系列中000YCbCrCoefficients(0x0211) 的值是 '0.299/0.587/0.114', ReferenceBlackWhite(0x0214) 的值是 '0,255,128,255,128,255'. 于是把 Y/Cb/Cr 转换成 RGB 就是;
(0,0)=(Cb-128)*(2-0.114*2)+Y(0,0)
R(0,0)=(Cr-128)*(2-0.299*2)+Y(0,0)
G(0,0)=(Y(0,0)-0.114*B(0,0)-0.299*R(0,0))/0.587
水 平 subsampling 的值是 '2', 因此你能使用 Y(1,0)和 Cr(0,0)/Cb(0,0)计算出B(1,0)/R(1,0)/G(1,0). 根据ImageWidth(0x0100) 和 ImageLength(0x0101)的值可以重复这些转换.
参考资料:
JPEG系列二 JPEG文件中的EXIF(上) https://blog.csdn.net/shelldon/article/details/54234426
JPEG系列二 JPEG文件中的EXIF(下) https://blog.csdn.net/shelldon/article/details/54407534
图片文件Exif信息详细说明 blog.sina.com.cn/s/blog_651251e60102uz3d.html#AboutExif
图像Exif信息 元数据(Metadata) https://www.jianshu.com/p/a6d67df60e7e
关于图片文件旋转JPEG与EXIF信息 https://blog.csdn.net/yulimin/article/details/102827865
https://www.media.mit.edu/pia/Research/deepview/exif.html
https://baike.baidu.com/item/Exif/422825?fr=aladdin
读取JPG图片的Exif属性(一) - Exif信息简介 https://blog.csdn.net/fioletfly/article/details/53605959
读取JPG图片的Exif属性(二) - C代码实现 https://blog.csdn.net/fioletfly/article/details/54094940
读取JPG图片的Exif属性(三) - Exif属性读取GPS信息代码(C/C++实现)https://blog.csdn.net/fioletfly/article/details/54133422
在jpg图片添加Exif信息的C程序实现 https://blog.csdn.net/psy6653/article/details/79658144
JPEG添加EXIF https://blog.csdn.net/weixin_43549602/article/details/84654965
jpeg图片格式详解 https://blog.csdn.net/yun_hen/article/details/78135122
压缩算法——JPEG2000 编解码原理 https://blog.csdn.net/ytang_/article/details/76571635
PNG、JPEG、BMP等几种图片格式详解 https://www.jianshu.com/p/f5557c0e689e
使用HTTP2和渐进式JPEG图片更快的加载图像 http
转载本站文章《JPEG/Exif/TIFF格式解读(3):TIFF与JPEG里面EXIF信息存储原理解读》,
请注明出处:https://www.zhoulujun.cn/html/theory/multimedia/CG-CV-IP/8398.html