手机拍摄的照片包含GPS信息,群晖的Moments可以根据拍摄图片的位置信息对照片进行分类。
那么,GPS 信息是如何储存的呢?该如何读取相关信息?
Exif是什么
Exif文件格式与JPEG文件格式基本相同,是专门为数码相机的照片设定的,可以记录数码照片的属性信息和拍摄数据。最初由日本电子工业发展协会在1996年制定,版本为1.0。1998年,升级到2.1,增加了对音频文件的支持。2002年3月,发表了2.2版。
JPEG格式和标记
每个JPEG文件均以0xFFD8开头,以0xFFD9结尾。 基本格式如下:
Exif文件标识为0xFFE1
0xFFE1+数据大小(2个字节)+数据(n个字节)
数据大小(2字节)是“ Motorola”字节对齐,从较大的数字开始。请注意,如果有这样的标记,则“数据”包含数据大小描述符;
FF C1 00 0C
此Marker(0xFFC1)有0x000C(等于12个)字节的数据,也就是说在0x000C之后有10个字节的数据。
TIFF头的结构
TIFF格式的前8个字节是TIFF头。前2个字节定义TIFF数据的字节对齐。如果它是0x4949 (Ascii为“ I I”),则表示“ Intel”类型的字节对齐。如果它是0x4d4d (Ascii值为“ MM”),则表示“ Motorola”类型的字节对齐。例如,第十六个系统将值“ 305,419,896”标记为0x12345678。在Motrola对齐方式下,它存储为0x12,0x34,0x56,0x78。如果是Intel align,则将其存储为0x78,0x56,0x34,0x12。
接下来的2个字节始终是2个字节的长度值0x002A。如果数据使用Intel align,则接下来的2个字节为“ 0x2a00”。如果使用摩托罗拉,则为“ 0x002a”。
TIFF头的最后4个字节是第一个IFD的偏移量。包括此偏移量本身,TIFF格式中使用的所有偏移量值都是从TIFF头的第一个字节开始计算。通常,第一个IFD紧跟TIFF头,因此此偏移量的值为0x00000008。
IFD:Image File Directory
IFD包含图片信息,前2个字节表示此IFD中包含的Directory Entry数。 然后是Directory Entry(每组数据12字节)。 在最后一个entry之后,有4个字节的数据,用来表示到下一个IFD的偏移量。 如果其值为“ 0x00000000”,则为最后一个IFD。
Entry结构
Bytes 0-1 Tag
Bytes 2-3 Type
Bytes 4-7 Count
Bytes 8-11 Value Offset
Tag
每个entry前2个字节都是tag。 Exif 0th IFD和1st IFD中的tag号与TIFFtag号相同。
Type
1 = BYTE 8-bit unsigned int
2 = ASCII 8-bit byte(包含一个7-bit ASCII码, 最后一个byte为字符串终止符NULL)
3 = SHORT 16-bit (2-byte) unsigned int
4 = LONG A 32-bit (4-byte) unsigned int
5 = RATIONAL 两个LONG, 第一个LONG 是分子,第二个LONG是分母
7 = UNDEFINED 8-bit byte 可以取任何值,具体取决于字段定义
9 = SLONG A 32-bit (4-byte) signed in
10 = SRATIONAL两个SLONG, 第一个SLONG 是分子,第二个SLONG是分母
Count
value的数量。 注意: Count不是byte的总和。 一个SHORT(16位)的是2个字节,计数也为“ 1”。byte数=Count*Value类型字节数
Value Offset
该Tag记录从TIFF头的开头到记录值本身的位置的偏移量。 在如果值等于4个字节,则会记录值本身。 如果该值小于4个字节,则值为从左开始,即从字节偏移区域的后面开始,存储在4字节区域中。 例如,大字节序格式,如果类型为SHORT并且值为1,则记录为00010000.H。
例如:
1000
0E01020020000000CE000000
0F01020020000000EE000000
......
000072010000258804000100
0000D002
GPS信息的Tag值为0x8825
Tag: 0x8825
Type: 4
Count: 1
Value Offset: 720
按照Tag的偏移量找到GPS IFD
GPSIFD有很多entry,我需要的只是里面的经纬度
GPS LatitudeRef
Tag = 1 (1.H)
Type = ASCII
Count = 2
Default = none
'N' = 北纬
'S' = 南纬
Other = reserved
GPS Latitude
Tag = 2 (2.H)
Type = RATIONAL
Count = 3
Default = none
GPS LongitudeRef
Tag = 3 (3.H)
Type = ASCII
Count = 2
Default = none
'E' = East longitude
'W' = West longitude
Other = reserved
GPS Longitude
Tag = 4 (4.H)
Type = RATIONAL
Count = 3
Default = none
例:
LatitudeRef
tag: 1
type: 2
count: 2
value offset: 78
Latitude
tag: 2
type: 5
count: 3
value offset: 846
LongitudeRef
tag: 3
type: 2
count: 2
value offset: 69
Longitude
tag: 4
type: 5
count: 3
value offset: 870
解析结果:
LatitudeRef: 北
Latitude: 39.000000 38.000000 12.214900
LongitudeRef: 东
Longitude: 115.000000 34.000000 25.567000
参考资料:
https://www.media.mit.edu/pia/Research/deepview/exif.html
http://www.exif.org/Exif2-2.PDF