作者:中科大鹏
1 前言
因为最近有个项目开发,需要通过读取JPEG图片文件的GPS位置信息,显示到相应的地图界面中。这两天,查询了相关资料,发现这方面科普性的文章挺多,但适合项目应用开发的示例代码有限。为此,自己查阅资料,梳理了解析GPS信息的相关过程,编写了部分代码,在此分享给大家。不足之处望多多包涵。
文章只列举了很少部分的JPEG格式说明,关于JPEG文件格式详细介绍,可以参阅相关文献(文末会分享查阅的接口标准和参考文献),另外,本文只针对需要的GPS信息进行了解析,其余的很多信息直接略过,大家可以参看接口标准说明文件。
2 JPEG图像数据的基本结构
2.1原始图像数据的基本结构
图像数据采用的存储格式,取决于需要的图像数据类型:
-
- 未压缩RGB数据: 采用TIFF Rev. 6.0标准修订版的RGB全彩图像类型格式
- 未压缩YCbCr数据: TIFF 6.0 修订版的扩展YCbCr 图像类型数据格式
- JPEG压缩数据: JPEG标准的ADCT。
就压缩数据而言,DSC应用程序所需要的属性信息记录在文件APP1信息中,写入APP1中的数据需要与TIFF兼容。图像文件使用了一种存储压缩和未压缩数据属性信息的通用方法,这样可以得到更简单的格式;同时又利用标记的可扩展性机制,实现了为附加信息添加私有标记的可能。
2.2未压缩RGB数据的基本结构
未压缩RGB数据的按照TIFF Rev. 6.0 RGB 标准的全色彩图像要求进行记录。
文件的通用属性信息记录在TIFF Rev. 6.0指定的Tag标签中。Exif特定的属性信息使用该标准为TIFF保留的私有Tag标签来记录。私有Tag标签指向该属性的信息集合(Exif IFD)。同样,JPEG文件的GPS信息也属于扩展属性信息,记录在TIFF Rev. 6.0中规定的标记中。
需要注意的是,在TIFF标准中,并未规定每个IFD(Image File Directory)值的记录位置。
JPEG文件结构主要包括:
-
- File Header, 文件头
- 0th IFD, 第0个IFD
- 0th IFD Value, 第0个IFD的值
- 1st IFD, 第1个IFD
- 1st IFD Value, 第一个IFD的值
- 1st (Thumbnail) Image Data, 缩略图
- 0th (Primary) Image Data. 图片数据
基本文件结构如图所示:
图 1 未压缩数据文件的基本结构
TIFF标准中定义的文件头占8字节,其中,到IFD的偏移量字段表示从TIFF头开始至第0个IFD的起始地址的偏移位置。
同样,第0个IFD存储的IFD偏移量,表示第1个IFD(缩略图)的存储地址。当没有记录缩略图,即没有第1个IFD时,第0个IFD存储的偏移量以00000000.H结束。
TIFF头部结构如表所示:
表 1 TIFF头部结构
名称 |
长度(字节) |
描述 |
Byte Order |
2 |
“II”(4949.H)或 “MM”(4D4D.H) • II 表示数字存储遵循 intel 的字节序,即小端存储 • MM 表示数据存储遵循 Motorola 的字节序,即大端存储 不同的存储字节序的选择主要是因为不同厂商的不同的数码产品的差异引起。大部分的数码相机使用 Intel 的字节序,也有些奇葩的产品的,比如Sony 的大部分产品都是使用Intel字节序的。 重要:Byte Order直接影响到数据内容,所以在解析Exiff数据前必须检查文件的Byte align |
固定值 |
2 |
固定为002A.H |
到IFD的偏移量 |
4 |
第0个 IFD偏移量。如果TIFF头后面紧跟着第0个IFD,则它被写为00000008.H。(从Byte Order起算。后续的数据偏移量也从Byte Order起算) |
2.3 JPEG压缩数据的基本结构
压缩数据文件按照ISO/IEC 10918-1中规定的JPEG DCT格式进行记录,并插入应用片段(APP1)。APP1紧随着ISO标记而记录,ISO标记指示了文件的开头(见图)。同样,可以根据需要记录多个APP2,并且可以紧随APP1之后。Exif不使用APP1和APP2之外的APPn或COM段。因此,Exif读取程序设计需要跳过未知的APPn和COM数据段。
图 2 压缩数据文件的基本结构
互操作性:APP1由APP1标记、Exif标识符代码和属性信息本身组成。APP1的大小包含所有这些元素,其长度不得超过JPEG标准规定的64KB。
属性信息存储于TIFF结构中,包括1个文件头,最多2个IFD(0th IFD和1th IFD)。0th IFD记录与压缩图像(主图像)有关的属性信息。1th IFD可用于记录缩略图等。
APP2由APP2标记、FPXR标识符代码和扩展记录或流数据的内容列表组成。多个APP2标记段的字符串可用于记录超过64KB的数据。
2.4 缩略图数据的基本结构
缩略图数据使用两种现有的图像格式记录在第一个IFD中,与主图像类似。
缩略图的大小没有限制,也不是强制性的。
缩略图不用采用与主图像相同的数据结构。然而,当主图像记录为未被压缩的RGB数据或未压缩的YCbCr数据时,缩略图不能记录为JPEG压缩数据(见表)。
表 2 主图像和压缩图像适应性
以压缩格式记录缩略图时,按照标准TIFF Rev. 6.0 RGB Full Color Images 或者TIFF Rev. 6.0 Extensions YCbCr Images要求将其记录在第一个IFD中。
Exif特定的记录格式用于压缩的缩略图。此时,压缩标签值被设置为“6”,第一个IFD的标签用于指定位置和大小。图像在指定位置存储为符合JPGE标准DCT格式的数据流(从SOI到EOI)。JPEG数据流中不记录APPn标记、COM标记或重置标记,见图。为了避免重复定义,第一个IFD不用于记录指示TIFF图像的标记或记录在别处作为JPEG标记段的信息。
图 3 具有压缩缩略图的Exif文件结构
3 Tag标签
3.1 属性信息的特征
RGB数据符合标准Rev. 6.0 RGB Full Color Images, YCbCr符合TIFF Rev. 6.0 扩展YCbCr Images标准。因此,TIFF后面紧跟的数据库应按照TIFF标准记录信息。除了TIFF标准中规定的强制性属性外,Exif标准还添加了用于DSC或其他系统的TIFF可选标签,包括用于记录DSC特定属性信息的Exif特定标签,以及用于记录位置信息的GPS标签。同样,还有一些原始规格用于记录Exif压缩缩略图的信息并不包括在标准中。
文件记录的压缩数据与非压缩数据的区别在于:
- 以压缩数据记录主图像时,没有指定主图像或其地址指针的Tag标签。
- 缩略图数据以压缩形式记录时,使用Exif特定的Tag标签指定其地址和大小。
- 无论主图像还是缩略图,与JPEG标准定义的Tag标签信息不会重复记录。
- 与压缩相关的信息能够用Tag标签记录。
3.2 IFD结构
Exif标准中使用的IFD共计12字节,结构如下:
字节0-1: 标签Tag字段
字节2-3: 类型Type字段
字节4-7: 数量Count字段
字节8-11: 下一个IFD偏移字段。
(1)Tag标签
每个Tag标签分配唯一2字节数字来标识该字段,Exif 0th IFD和1st IFD的标签号都与TIFF标签号相同。
(2)类型Type
Exif使用了以下类型:
表 3 IFD数据类型
类型编码 |
大小(字节) |
描述 |
|
1 |
1 |
BYTE |
8bit unsigned integer |
2 |
1*n |
ASCII |
ASCII信息码。最后一个字节必须以空字符结尾。 |
3 |
2 |
SHORT |
(2-byte) unsigned integer |
4 |
4 |
LONG |
(4-byte) unsigned long |
5 |
8 |
LONG * 2 |
第一个数字是分子,第二个数字是分母 |
7 |
n |
UNDEFINED |
可以包含任意数值 |
9 |
4 |
SLONG |
32-bit (4-byte) signed integer |
10 |
8 |
SLONG * 2 |
第一个数字是分子,第二个数字是分母 |
(3)数量Count字段
数值的数量。需要注意的是,数量不是字节的总和,而是根据类型Type值确定的个数。比如,在类型Type=03的情况下,Count=1,此时数据是2个字节。
(4)偏移量
这个字段记录从TIFF标头开始到记录值本身位置的偏移量。如果数值是4字节,则记录的是数值本身;如果数值长度小于4字节,则该值存储在从左侧开始的4字节中,即偏移区域的低位开始。例如,在大端存储big endian(TIFF Headers Byte Order为 4D4D.H)时,如果short类型值为1,则存储为00010000.H。
注意:Interoperability字段的Tag标签应按从最小号开始按顺序记录。标签值(value)记录的顺序和位置没有规定。
3.3 Exif特定的IFD
表 4 Exif特定的IFD
IFD |
Tag标签 |
Type |
Count |
Default |
Exif IFD |
34665 (8769.H) |
LONG |
1 |
-- |
GPS IFD |
34853 (8825.H) |
LONG |
1 |
-- |
Interoperability IFD |
40965 (A005.H) |
LONG |
1 |
-- |
… |
… |
… |
… |
… |
3.4 GPS信息
表 5 GPS信息
IFD |
Tag标签 |
Type |
Count |
默认值及含义 |
|
GPSVersionID |
0 (0.H) |
BYTE |
4 |
2.2.0.0 |
2.2.0.0 = Version 2.2 Other = reserved |
GPSLatitudeRef |
1 (1.H) |
ASCII |
2 |
-- |
'N' = North latitude 'S' = South latitude |
GPSLatitude |
2 (2.H) |
RATIONAL |
3 |
--- |
|
GPSLongitudeRef |
3 (3.H) |
ASCII |
2 |
-- |
'E' = East longitude 'W' = West longitude |
GPSLongitude |
4(4.H) |
RATIONAL |
3 |
--- |
|
GPSAltitudeRef |
5 (5.H) |
BYTE |
1 |
0 |
0 = Sea level 1 = (negative value) |
GPSAltitude |
6 (6.H) |
RATIONAL |
1 |
--- |
|
GPSTimeStamp |
7 (7.H) |
RATIONAL |
3 |
--- |
|
GPSSatellites |
8 (8.H) |
ASCII |
可变 |
--- |
|
GPSStatus |
9 (9.H) |
ASCII |
2 |
--- |
'A' = in progress 'V' = Interoperability |
GPSMeasureMode |
10 (A.H) |
ASCII |
2 |
--- |
'2' = 2-D '3' = 3-D |
GPSDOP |
11 (B.H) |
RATIONAL |
1 |
--- |
|
GPSSpeedRef |
12 (C.H) |
ASCII |
2 |
'K' |
'K' = Kilometers per hour 'M' = Miles per hour 'N' = Knots |
GPSSpeed |
13 (D.H) |
RATIONAL |
1 |
--- |
|
…… |
…… |
…… |
…… |
…… |
4 数据解析示例
4.1 示例JPEG文件头部信息数据
00000000h: FF D8 FF E0 00 10 4A 46 49 46 00 01 01 01 00 78 ; ??.JFIF.....x
00000010h: 00 78 00 00 FF E1 00 C4 45 78 69 66 00 00 49 49 ; .x..?腅xif..II
00000020h: 2A 00 08 00 00 00 02 00 31 01 02 00 10 00 00 00 ; *.......1.......
00000030h: 26 00 00 00 25 88 04 00 01 00 00 00 36 00 00 00 ; &...%?.....6...
00000040h: 00 00 00 00 4C 6F 63 61 53 70 61 63 65 56 69 65 ; ....LocaSpaceVie
00000050h: 77 65 72 00 06 00 01 00 02 00 02 00 00 00 4E 00 ; wer...........N.
00000060h: 00 00 02 00 05 00 03 00 00 00 84 00 00 00 03 00 ; ..........?....
00000070h: 02 00 02 00 00 00 45 00 00 00 04 00 05 00 03 00 ; ......E.........
00000080h: 00 00 9C 00 00 00 05 00 01 00 01 00 00 00 00 00 ; ..?............
00000090h: 00 00 06 00 05 00 01 00 00 00 B4 00 00 00 00 00 ; ..........?....
000000a0h: 00 00 1E 00 00 00 01 00 00 00 37 00 00 00 01 00 ; ..........7.....
000000b0h: 00 00 87 0F 68 0F 80 96 98 00 67 00 00 00 01 00 ; ..?h.€枠.g.....
000000c0h: 00 00 1D 00 00 00 01 00 00 00 10 A1 D8 0C 80 96 ; ...........∝.€?
000000d0h: 98 00 20 4E 00 00 10 27 00 00 ; ? N...'..
4.2 JPEG数据层级解析
首先把原始数据按照几个大块进行分割。
APP数据都是按照标志(2字节)、长度(4字节)、数据正文(长度根据数据定)的结构。如表所示。
表 6 JPEG数据层级解析
信息 类型 |
存储 位置 |
Hex |
描述 |
文件 标志 |
00.H. |
FF D8 |
Start Of Image (SOI),JPEG文件开始标识符 |
APP0 |
02.H |
FF E0 |
Application-sepcific 0 (APP0)标志 注:FF En, n是从0~F的数字,如FF E0,表示APPn标志 |
04.H |
00 10 |
APP0数据帧长度,不包括标识符FF E0, 包括长度符 00 10自身 |
|
06.H |
4A 46 49 46 00 01 01 01 00 78 00 78 00 00 |
APP0数据帧信息内容 |
|
APP1 |
14.H |
FF E1 |